A template entry may now narrow its pattern and carry a note. TemplateEntry gains requires (per segment kind, the tokens a name must carry), excludes (segment kinds a name must not fill) and note (one sentence). The accessor exposes the note on AppliedTemplate.note; the consumer renders it after the entry's documentation opening.

requires is satisfied when the name carries at least one of the listed tokens for that segment kind. The population, aggregation and state segments are closed single-token segments, so the intersection test reduces to membership; stated as an intersection it also holds for a segment that admits several tokens. excludes is satisfied when the name fills none of the listed segment kinds. The name's tokens per segment kind come from the parse: the accessor groups them once in _ir_segment_tokens, and _ir_tokens is now that grouping's union rather than a second walk of the IR.

Precedence rule. Selection runs the subset test, then the conditions, then precedence: among matching entries that share a base and the same required segment kinds, a conditioned entry supersedes its unconditioned siblings — the conditioned entry is selected and the unconditioned sibling is dropped for that name. A conditioned entry and an unconditioned sibling therefore never both render for one name, so a note placed on the conditioned entry reaches only the names it admits. An entry with no conditions selects exactly as before, and entries that share a base but differ in their required segment kinds (the several temperature openings) are not siblings and all still apply. Reversing the rule — the unconditioned sibling wins when both match — makes test_conditioned_entry_supersedes_its_unconditioned_sibling fail.

The note rides the template, not the applied name: it is emitted on every name that selects the entry and on no other. Because a name that selects two openings of the same base (a species and an aggregation opening) may carry a note from each, a note is written on the single entry whose pattern it separates, so it still renders once per name.

Every shipped template selects as before. The shipped templates.yml carries no condition and no note, so the new branch is a no-op. test_every_existing_template_selects_as_before asserts all shipped entries are unconditioned and, for the names the existing convention tests render, that the selected (base, segments) tuples equal an independent reimplementation of the plain subset test.

Follow-on folded in: _entry_definitions in vocab_loaders.py no longer opens and parses its YAML itself; it reads through _load_yaml like the other loaders.

Measure. tests/grammar/test_template_conditions.py (new) exercises a required token, an excluded kind, a note on a selecting and a non-selecting name, a name selecting two openings, the loader refusals for an unknown required token and an unknown excluded kind, the precedence rule, and the shipped-registry no-op. Gate: PYTHONPATH=$PWD uv run --no-sync pytest -p no:cacheprovider tests/grammar -q ran 1212 passed, 32 skipped (EXIT=0) at head versus 1204 passed, 32 skipped (EXIT=0) at base — eight added tests, zero added failures, judged by delta.

Negative control, declared as dropping the condition filter from _select_templates and holding everything else fixed. With that filter removed, tests/grammar/test_template_conditions.py ran 3 failed, 5 passed (EXIT=1), failing the required-token test, the excluded-kind test and the precedence test — all passing at head. Two additional mutations were run and are recorded in the run directory: drop note=entry.note from the applied template (3 failed, EXIT=1, including both note tests), and reverse the precedence rule (1 failed, EXIT=1, the precedence test). Log: negative-control.log in the run directory.

No figure accompanies this fragment: the change is a selection rule and a field, and the tests above carry it. The figure directory given to this node is left empty.