§3 landed — grammar residuals + decomposition re-parse triage ✓ landed 2026-07-18
Evergreen: canonical-qualifier-order §3.
Closes the last three §3 followups (f-cqo-normdir-shadow, f-cqo-003,
f-cqo-004) and delivers the decomposition re-parse triage script + dry-run manifest
that the docs-campaign plan gated on §3 being final
(model-selection-and-global-refine · f-decomp-reparse-triage).
1 — normalized-direction shadow removed (ISN d150b6c)
components.yml and coordinate_axes.yml registered
normalized_parallel and normalized_perpendicular as projection tokens.
Longest-match then shadowed the operator reading:
normalized_parallel_momentum_flux fused to a
projection=normalized_parallel instead of the GyroBohm-normalization
operator applied to the parallel momentum flux — silently changing the meaning of
every GyroBohm-normalized projected quantity. The unit-suspicion validator carried a
stop-gap component-prefix exemption to paper over it, but the ambiguity itself was live.
Resolution (physics-grounded, deterministic). parallel and
perpendicular are field-relative directions (along / across B)
with no distinct normalized-direction variant — so a leading normalized on them can
only ever be the operator. Both tokens are removed from components.yml and
coordinate_axes.yml; the genuine normalized coordinate-frame directions
(normalized_radial→ρ, normalized_vertical, normalized_toroidal→φ,
normalized_poloidal→θ) are retained. The stop-gap exemption is deleted — the operator
is now exempted through the existing dimensionless-operator path, which also restores correct
unit-suspicion for the genuine normalized_radial-class components (a ρ-component
magnetic field still carries Tesla).
| Name | Before (shadowed) | After |
|---|---|---|
normalized_parallel_momentum_flux |
projection=normalized_parallel |
operator normalized + projection=parallel |
normalized_radial_magnetic_field |
projection=normalized_radial |
projection=normalized_radial (unchanged — genuine) |
The 4 affected GyroBohm names re-parse to the canonical
<direction>_normalized_<base> form (component leads the normalization
qualifier, per the royal-adjective-order decision) and are surfaced as migration backlog, not
papered over. ISN suite 1822 passed (the single failing
test_find_git_root_raises_when_no_repo is a pre-existing environmental tmp-path
flake, orthogonal to grammar); codegen in sync.
2 — vocabulary-disjointness guard at its intentional floor (f-cqo-003)
tests/grammar/test_vocab_uniqueness.py asserts the segment-role vocabularies are
pairwise disjoint outside a small, documented allowlist, and is green. The ratchet the followup
tracked is complete: qualifiers ∩ {operators, physical_bases, generic_physical_bases,
subjects(particle/state), processes, locus_registry} are all now empty
(the mis-filed tokens were pulled to their true segments across the §2 dupe removal and the
rc55–rc59 curation). The remaining allowlist entries are genuinely intentional dual-roles
(components ∩ coordinate_axes; channels ∩ physical_bases for energy/momentum;
zones ∩ regions/locus; generic_bases ⊂ bases; the three fusion-reactant
qualifiers ∩ subjects pairs; qualifiers ∩ physics_domains for
equilibrium/mhd/nbi) — not mis-files. The guard actively blocks re-introduction.
3 — §3 per-token curation complete (f-cqo-004)
The deep per-token review landed incrementally across the §3 slices, each recorded in the vocab file it touched and in its followup outcome:
- base-bound / compound bases — the token-by-token verdict (atomic base vs
qualifier vs coordinate-carrier) and the compound-vs-qualifier rule are recorded in
physical_bases.yml(the wetted/surface/cross-sectional area family, spectral, the channels-dual energy/momentum design). - scoping vs kind-forming qualifiers —
scoping_qualifiers.ymlcarries the phrase-scoping binding class (implicit/explicit/effective/incident/…), grounded in English royal adjective order (Forsyth; Scontras et al. 2017). - regime qualifiers vs
due_to_processes — the process vocabulary was curated (97→89) andqualifiers ∩ processesis now empty. - components vs operators — the normalized-direction shadow above was the last open grammar residual of this class.
With the normalized-direction ambiguity resolved, §3's curation is complete: no un-adjudicated cross-segment mis-file remains (the guard proves it), and the remaining dual-roles are documented design, not debt.
4 — the decomposition audit was obsolete under controlled bases — retired (imas-codex 5a08c744)
The physical/geometric base slot is a controlled vocabulary: the parser
rejects an unregistered base token (flibbertigibbet_field →
UnknownBaseTokenError), so a composer cannot hide structure in an open
physical_base — the failure mode the audit was built to catch. The audit read a
name's surface base phrase (model.physical_base, e.g.
reference_magnetic_field, absorbed_power,
nuclear_heating_power) and compared it against the registered base-token
set — but the actual base token (ir.base.token: magnetic_field,
power, heating_power) is always registered. The
surface phrase legitimately carries glued kind-forming qualifiers (royal-order:
ion_atomic_mass, wave_electric_field). So there is no genuine
"absorbed token" this audit could ever detect on a name that parses; names that don't parse are
caught by the grammar gate.
| Apparent "rename" class | Reality |
|---|---|
absorbed_power, wave_electric_field, alfven_frequency (262) |
kind-forming qualifier glued to a registered base — correct per royal-order |
ratio_of_A_to_B (~20) |
binary-operator names; physical_base is one nested argument, not a flat base |
upper_bound_charge_number (~8) |
zone token upper matched inside the upper_bound qualifier — substring artifact |
lower_bound_energy, critical_momentum (~10) |
energy/momentum is the registered base head, not an absorption |
Retired. decomposition_audit_check, the
find_absorbed_closed_tokens primitive, and their tests are removed; the reviewer
prompt's hand-scan-and-dock bullet is replaced with "the base registry is grammar-enforced; emit
a vocab_gap when no registered base fits." All stored findings were drained
graph-wide (2252 accepted-name findings via the interim tool, then the remaining 1641 across all
stages — 0 remain). No name was renamed; none needed it. The base grammar itself
is now the guarantee. The interim sn decomp-triage tool was deleted (single-shot).
The original dry-run manifest is retained as a historical artifact:
decomp-triage-dry-run.json
(its "rename" bucket is now understood as false positives).