§2 landed — Qualifier vocabulary categorization

Record for the qualifier-vocabulary-categorization plan §2 (all sub-sections). The Grammar composer's qualifier picker is now categorized at the ISN root, not worked around in the SPA.

Outcomes

ItemResultArtifact
§2a — de-pollute the qualifier role ✓ keep-flag The 136 cross-listed tokens (bolometer, gradient, …) were found NOT to be in qualifiers.yml — they enter Vocabularies.qualifiers only because the parser unions unary-prefix operators + locus/object tokens for stripping. Fix: the emitter publishes qualifiers.yml (genuine set), not the union. Parser acceptance untouched → zero round-trip risk.
§2b — categorize genuine qualifiers ✓ 12 categories imas_standard_names/grammar/vocabularies/qualifier_categories.yml — all 161 tokens mapped (transport·source·geometry·region·state·energy·diagnostic·polarization·temporal·normalized·species·engineering). Parser populates IR Qualifier.category via load_qualifier_categories().
§2c — emit categories ✓ 159 emitted dataset.py::_build_grammar_vocab: GRAMMAR_VOCAB.qualifiers = genuine set minus subjects, each {token, category}.
§2d — site picker ✓ grouped by category site/src/views/Grammar.jsx: generic qualifier picker sub-groups by emitted category; subtraction workaround removed; subjects no longer mixed in.

Verification

What's next

Optional refinement (queued as a followup on the parent plan): a domain-expert pass over the family-based 12-category bucketing (e.g. ferritic material vs source; normalized currently under state→normalized), and a deeper audit of whether any genuinely mis-filed locus/operator tokens should be removed from the parser's qualifier acceptance union (vs. merely excluded from the published role).