§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).

NameBefore (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:

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)

Correction (2026-07-18): an initial re-parse triage bucketed the 2252 decomposition_audit findings as drain 1809 / suppress 173 / rename 270 and shipped a sn decomp-triage tool + dry-run manifest. The lead's controlled-base point then revealed the deeper truth: every one of those findings — including the "270 rename queue" — was a historic false positive. The audit was retired, not refined.

The physical/geometric base slot is a controlled vocabulary: the parser rejects an unregistered base token (flibbertigibbet_fieldUnknownBaseTokenError), 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" classReality
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).