A derived field can silently leave the tag group it names
- Dominant language
- Python
- Stars
- 21
- Forks
- 2
- Avg merge
- 6h 33m
- Merged PRs (30d)
- 91
Description
Found adopting `derive` in the anthology. Not a bug in 0.13 — a guard that isn't there yet, and the hazard is silent.
## The shape
A scheme constrains a subset of its tags and then derives a field naming which one it is:
```toml
[luria.schemes.SOTA.fields.primary_topic]
derive = "{tags[0]}"
[luria.schemes.SOTA.tag_groups.primary_topic]
require = "exactly-one"
tags = ["training-optimization", "attention-techniques", ...]
```
`exactly-one` guarantees that exactly one tag comes from that list. It says nothing about **where in the list it sits**. So `{tags[0]}` rests on a convention — the primary tag is written first — that nothing checks.
Write the tags in the other order and `primary_topic` derives to a secondary tag. Nothing fails: the group is still satisfied (there is still exactly one primary tag), the derivation still renders, and the field is now quietly wrong. Everything downstream inherits it — a chain's `invariant`, a facet, a report column — and the failure looks like a data problem in whatever consumed it.
Measured on the anthology: `tags[0]` is the primary topic in all 188 practices and all 218 notes, so the convention holds today. That is what makes it worth a guard rather than a workaround — it will hold right up until someone appends a tag to the top of a list.
## What would fix it
A check that a derived value lands in the tag group of the same name, when one exists:
```
luria: SOTA-085: `primary_topic` derives `flash-attention`, which is not in
the `primary_topic` group (the group's tag must come first in `tags:`)
```
It fits the bar in CLAUDE.md — the violation is always wrong and mechanically fixable (reorder the two tags), so it can be a lint finding rather than a report.
Two design questions I don't have a view on:
1. **What ties the field to the group?** Matching names is the obvious rule and is what the anthology's config already looks like, but it is implicit. An explicit `in_group = "primary_topic"` on the field says it instead of inferring it, at the cost of a line.
2. **Is the check about groups at all?** The general version is that a derived field can declare a vocabulary, the way an ordinary field does, and be checked against it. A tag group is not a vocabulary today (`tag_groups` constrain a subset of values, per the comment in `config.py`), so this may be the smaller and more honest fix even though the wider one is tempting.
Filed rather than worked around: the anthology declares the derivation now, with a comment naming the convention and pointing here.
Contributor guide
Research direction
Start with config.py's tag_groups handling and the linting bar described in CLAUDE.md. Trace how derive fields are validated, then resolve whether same-name group matching or an explicit declaration is the intended link. Done means an out-of-group derived value produces a lint finding with the relevant scheme, field, derived value, and group, while valid ordering remains accepted.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100