Contracts

gate-extension.md

Contract: Gate Extension, Sanctions, and Floor Transfer

Binding contract for FR-001 / FR-005 / FR-006 / FR-007 / FR-012 and NFR-004/005/007 (IC-01, IC-05, IC-06).

E1 — Close the holes BEFORE migrating (FR-001, IC-01)

Two holes exist today; migrating into them would trade visible semi-compliance for invisible non-enforcement.

HoleRequirement
One site passes a handle from a canonicalizer the fold set does not recognise — neither routed nor allow-listed, passing by omissioneither route the site or teach the gate that canonicalizer; the choice MUST be recorded, not implicit
The fold-prescription gate's three allow/flag sets bless only the blind primitive, so a directory obtained from the seam is in neither the sanctioned nor the flagged setwiden the sets to know the tier-1 seam idiom, so migrated sites are affirmatively sanctioned

Loosening guard: widening a blessing set is a relaxation unless paired with a bite test proving the gate still flags a bad read in a migrated module (NFR-005, SC-004).

E2 — Censused callees (FR-012)

gate covers (resolve_feature_dir_for_mission), and the primary primitive, which inherits the guarantee transferred from the retired use-count floors (E5).

primary primitive on the grounds that its fail-loud surface is zero and it was already censused on the anchoring axis. That held while the floors survived. Once the operator prescribed delegate-then-remove and FR-007 retired the floors, exclusion would leave the primitive policed by nothing — so it is censused here, with its end-state sanctions (resolver-internal + the four named foundation sites of FR-005). The ~34 in-flight sites are expected red between the gate landing and the migration completing; that red is the mission's acceptance signal (US8 / FR-023), not a defect.

primitive, on which axis, with its sized residual (FR-016/FR-017).

  • The censused-callee set grows 2 → 4: the kind-blind, topology-routed resolver that no
  • Superseded framing (recorded so it is not re-derived): an earlier draft excluded the
  • The ledger's Known-gap section still records which gate covers each non-censused
  • Alias resolution MUST hold: an aliased import cannot defeat the census.

E3 — Sanctions: asserted, never silently skipped

RequirementDetail
Per-file rationaleeach sanctioned module carries a written reason
Per-primitive non-vacuitythe meta-test MUST prove a sanctioned module carries a real finding for the newly censused primitive, not merely for a previously censused one — otherwise the new primitive's sanctions are vacuously "proved"
Blanket-excluded seam internalssites under the pinned scan-scope prefix cannot be brought into scope (the prefix set is frozen and guarded); accountability is a per-file rationale entry plus the per-primitive assertion above
Foundation sites (FR-005)the four sites beneath the seam are recorded by name with their recursion rationale and remain unrouted (NFR-009)

E4 — Allow-list

routed or removed is deleted.

  • Entries are per-site content descriptors; no path-scoped blankets (C-003).
  • Shrink-only, with a staleness twin-guard that reds until an entry whose site was
  • For preserved sites, the existing production comment is the rationale of record.

E5 — Floor retirement / transfer (FR-007, NFR-007, IC-06)

The two use-count floors count uses of the blind primitive. After Step 2 their subject population is only resolver-internal and named-sanctioned sites, where a raw handle is correct by contract — so the floors would guard nothing and instead oblige the primitive to keep being used, inverting their purpose.

RequirementDetail
Preferred end stateretire both floors and transfer the guarantee to the bypass census (E2/E3)
Mechanical fallbackre-pin to the honest post-migration numbers, respecting the existing margin rule
Either wayrecord the before/after integers and the reason ("a routing shrink"), per the floors' own doctrine — never relax silently
Two-file editthe floor values are asserted as bare literals in a second module too; both MUST move together
Companion bookkeepingthe blessed-name allow-list in the trio gate shrinks (its own failure text prescribes this — a tightening); the pin-existence test paired with the retired residual pin is retired with it (FR-014)

E6 — Acceptance

CheckHow verified
Biteplanted direct call reds; planted aliased call reds; prose mention stays green
No green-by-omissionplanted bad read in a migrated module still flagged
Per-primitive non-vacuityassertion parameterised by primitive; passes for the new one on its own merits
Allow-list integritystale entry reds; no path blanket present
Ledger parsedmutation per primitive reds (see ledger-grammar.md G3)
Floorseither absent with the guarantee transferred, or re-pinned with before/after recorded; no test obliges the primitive to remain in use
Foundation sitesrecorded by name, still unrouted, no resolution cycle
Verification scopeonly the named gates run locally (C-008); the exhaustive sweep is CI's

ledger-grammar.md

Contract: Ledger Grammar and Per-Site Index

Binding contract for FR-008 / FR-009 (IC-02). This is a hard prerequisite (C-009): no classification row for a newly censused primitive may be written until these hold.

Why this is a prerequisite, not a finishing touch

The originally-prescribed "per-primitive sub-tables" shape was executed against the real parser. Result: only the first table under a parsed heading is read; the second primitive's rows vanish; and the reconciliation test stays green. That is a silently vacuous gate — the exact failure a previous landing pass had to repair on this same gate. Adding rows first would bake it in.

G1 — Parse constraints (normative)

RuleFailure it prevents
Exactly one table under each machine-parsed headingsecond table silently dropped
Parsed headings kept verbatim (located by exact full-line match)section not found → parses empty
Verdict / rel_path / qualname remain at their current leading column positionspositional readers silently skip or mis-read rows
A primitive discriminator is appended as a trailing columna leading/middle insertion breaks the positional contract; appending fails loudly if mis-specified
No duplicate key within a counts tableduplicate keys overwrite silently, last-wins
Non-numeric cells in count columns are an error, not a skipsilent row skipping

G2 — Index grammar (per-site addressing)

The stay-lenient index is keyed per site, not per function. It MUST be able to address several censused sites inside one qualname — a known case carries four (one existing primitive plus three of the newly censused one).

composite) so each site is distinct.

otherwise it reds by construction.

  • The key gains a discriminator (trailing primitive + site token, or an equivalent
  • The uniqueness assertion MUST be updated in the same change as the key shape;
  • Acceptance fixture: the known four-site qualname.

G3 — New gate assertions (this is what makes the grammar enforceable)

1. Row-count reconciliation — parsed row count equals the summed per-primitive census. A dropped table or shifted column makes this red rather than parse-empty. 2. Per-primitive mutation — mutating a row belonging to each primitive independently MUST red the gate. A single-primitive mutation test would pass while the second primitive is unenforced. 3. Counts scoping — reconciliation covers the live residual / lenient totals, which are the figures the gate parses. The historical pre-migration totals are preserved and labelled as an audit record, never rewritten to satisfy a check.

G4 — Acceptance

CheckHow verified
G1 holdsthe reconciliation and mutation tests above, plus a review of the section shapes
G2 holdsthe four-site qualname is representable and the uniqueness assertion passes
Mutation reds per primitivescratch-copy mutation per primitive, each expected red
Historical totals intactthe pre-migration figures still present and labelled
Ordering respectedno new classification row exists in any commit before the commit that lands G1–G3

placement-layering.md

Contract: Placement Layering (what the architecture page must state)

Binding contract for FR-018 / FR-020 (IC-09). The page is docs/architecture/artifact-placement-seam.md. This contract fixes what must be true of the page, not its prose.

C1 — Required content

The page MUST contain, each as a named section:

1. What "routing" means here — the placement sense: mapping an artifact kind plus the mission's topology to a TopologySurface. It MUST point at the glossary's Routing disambiguation for the other senses rather than restating them. 2. The layer table — one row per layer (L0 entry, L1 partition classification, L2a declared decision, L2b affirmative decision, L3 discovery/assembly, L4 translation), each naming its owning module and what it is aware of. See data-model.md §1. 3. Both composition roots — the read root and the write root, shown as separate roots reached through one seam object (INV-4). 4. The compliance taxonomy — compliant tier-1 / delegating-but-lenient / semi-compliant / non-compliant, with the shape of each (data-model.md §1). 5. Honest bounds — the surface members with no production producer, and the frozenset still carrying a retired word as residual rename debt (INV-5). Named, not laundered. 6. Citations — ADR 2026-06-24-1 (kind-and-topology-aware placement) and ADR 2026-07-23-1 (TopologySurface vocabulary + the forbidden-conditioning rule) as the governing decisions.

C2 — Required accuracy (the load-bearing corrections)

is materialization-blind so that it can disagree with an already-resolved stamp; that divergence is what allows the existing surface-cannot-hold guard to fire. Describing "one decision module" is a defect.

already-discovered location and refuses when absent. Assembly belongs to L3. Getting this wrong teaches readers to strangle through L4 and re-add discovery at the call site — the misappropriation the page exists to prevent.

reading, and so a future rename shows up as a broken citation rather than silent rot.

  • The L2 split is deliberate and MUST be shown as two functions. The declared decision
  • Translation MUST NOT be described as assembling a path. It selects an
  • Every code-shape claim MUST carry a module:symbol citation so drift is detectable by

C3 — Prohibitions

forbidden-conditioning rule, alias retirement) — link to them. The page is explanatory.

PRIMARY partition, COORD partition).

  • MUST NOT restate normative rules the ADRs own (the placement invariant, the
  • MUST NOT introduce a synonym for a concept the glossary already names (TopologySurface,
  • MUST NOT be named *-routing.md — the word is already overloaded across ≥10 senses.

C4 — The competing authority MUST be narrowed in the same slice

docs/architecture/branch-target-routing.md currently asserts per-artifact-kind placement rules (the new page's core claim) under a branch-sense title, in vocabulary the glossary retires, with no read path. In the same slice it MUST be reduced to the branch sense and link to the new page for placement. Leaving both is the two-authority failure this mission exists to end.

C5 — Acceptance

CheckHow verified
Sections C1.1–C1.6 presentdocs test asserting the named sections and the citations
Layer table matches the codereviewer reads each row's cited module:symbol
No prohibited synonym; terminology guard greenterminology + glossary-canonical-terms gates
Registered and discoverabledocs/architecture/index.md entry; both gated registries regenerated; links resolve; check_docs_freshness --ci zero errors
Competing page narrowedthe old page no longer asserts kind-level placement rules, no longer uses the retired alias, and links out (SC-017)
Comprehensiona reader who has not followed the programme can state the three questions in User Story 7's Independent Test