Nine ADRs (0254, 0256-0263) were merged into main and left stamped Proposed. Two carried an explicit ratify-on-merge predicate their own merge had already discharged, and ADR-0256 governs deduction_serving_enabled, which was ratified True on 2026-07-24 and is serving live traffic. So the governance record asserted "not yet decided" about a decision already in force. That is the asymmetry the assessment arc (#113) found one file over in workbench/api.py: the honest path degrades, the stale record lies. An unwritten ADR is a visible gap; a Proposed one that is actually in force is a false statement. Each stamp records the ACTUAL ratifying act -- "Accepted, ratified by Joshua Shay via <merge> (<sha>, <date>)" -- derived from the commit that added the file and verified an ancestor of main, not assumed. Merge authority is Shay's alone (AGENTS.md: no merge automation), so the merge IS the ratifying act. No ADR content changed. No flag changed. ADR-0262's stamp says so explicitly: accepting it does NOT enable curriculum_serving_enabled, which stays False pending ratified volume -- eleven bands re-measured today, still 24x-73x short. tests/test_adr_status_governance.py pins two independent invariants in the smoke (pre-push) suite: 1. A default-ON flag is not governed by a Proposed ADR. The flag -> ADR mapping is DERIVED by walking core/config.py for `<name>: bool = True` and reading ADR refs from the preceding comment block -- not a hand-written table, which would be the same second-copy-of-a-closed-set defect ADR-0256's arc fixed. 2. A ratify-on-merge predicate cannot coexist with Proposed. Self-discharging: the file being on main IS the merge having happened. Plus a vacuity guard, because a derivation that parses zero flags would make every other assertion pass on an empty set. Registered two orphans found in passing: test_adr_index.py (5) and test_ratification_ceremony.py (14) landed in #113 in NO curated suite, so 19 tests -- including the one mechanism that can move curriculum volume -- ran only under `full`, which gates nothing. Fifth instance of this shape. Deliberately NOT fixed, recorded in the research doc: the 312-file corpus has 27 unparseable status lines and draft/ratified/active variants. A closed-vocab assertion would fail on ~35 pre-existing files and get muted, and a muted gate reads as coverage. [Verification]: smoke 555 passed in 137.73s (236 baseline + 314 + 5, +1.2s); governance pin 314 passed in 1.18s standalone and MUTATION-CHECKED -- reverting ADR-0256 to Proposed fails both invariants independently (2 failed/312 passed); orphans 19 passed; ruff clean. Canonical Python 3.12.13, uv sync --locked.
126 lines
6.1 KiB
Markdown
126 lines
6.1 KiB
Markdown
# ADR Status Governance — Nine Stamps and an Enforcement Pin
|
||
|
||
**Date:** 2026-07-25 · Follow-on to the assessment-verification arc (PR #113).
|
||
Evidence + mechanism only. No flag was touched; no ADR's *content* was changed.
|
||
|
||
## 1. What was wrong
|
||
|
||
Nine ADRs were merged into `main` and left stamped `Proposed`:
|
||
|
||
| ADR | ratifying merge | why the stamp was contradictory |
|
||
|---|---|---|
|
||
| 0254 | PR #103 → `da3447e9` (2026-07-23) | its own status line said *"ratify on PR #103 merge"* |
|
||
| 0256 | `1a6ccaf9` (2026-07-23) | its own status line said *"ratify-on-merge"*, **and** it governs `deduction_serving_enabled`, ratified `True` on 2026-07-24 |
|
||
| 0257 | PR #107 → `9405cf19` | Band v2-EN, live in the serving cascade |
|
||
| 0258 | PR #108 → `dd2245a7` | Band v3-MEM, live |
|
||
| 0259 | PR #109 → `5224b5e0` | Band v4-CM, live |
|
||
| 0260 | PR #111 → `2a82c8a3` | Band v5-VP, live |
|
||
| 0261 | `a8488e9c` | Band v6-EX, live |
|
||
| 0262 | `0ae54ebb` | curriculum-grounded serving (flag still OFF — see §3) |
|
||
| 0263 | `0ae54ebb` | ratified-ledger bridge, consumed by three capabilities |
|
||
|
||
Every merge above was verified an ancestor of `main` before stamping
|
||
(`git merge-base --is-ancestor`), and each ADR's ratifying merge was derived
|
||
from the commit that *added* the file, not assumed.
|
||
|
||
ADR-0256 is the sharp case. It governs a flag that was ratified ON and serving
|
||
live traffic, so the governance record asserted "this decision is not yet made"
|
||
about a decision already in force. That is the same asymmetry the arc that just
|
||
closed found in `workbench/api.py`: **the honest path degrades, the stale
|
||
record lies.** An unregistered grounding label reported
|
||
`epistemic_state_needed`; a hand-copied whitelist reported `none`. Here, an
|
||
unwritten ADR would have been a visible gap; a `Proposed` one that is actually
|
||
in force is a false statement.
|
||
|
||
## 2. What the stamps say
|
||
|
||
Status lines now record the *actual* ratifying act rather than inventing a
|
||
ceremony: `Accepted — ratified by Joshua Shay via <the merge> (<sha>, <date>)`.
|
||
Merge authority in this repo is Shay's alone (`AGENTS.md`: no merge automation;
|
||
green PRs sit until explicit authorization), so the merge **is** the ratifying
|
||
act and naming it is traceable rather than decorative.
|
||
|
||
## 3. Accepting an ADR is not flipping its flag
|
||
|
||
ADR-0262's stamp says so explicitly. `curriculum_serving_enabled` stays
|
||
`False`; its blocker is ratified curriculum volume (§5.1), and eleven live
|
||
bands remain 24×–73× short of the entailed-bucket floor — re-measured
|
||
2026-07-25 against the live loader, unchanged from the Tier-S S6 figures
|
||
(physics `causal` 7, `modal` 9, `systems_software` `sequence` 3,
|
||
`mathematics_logic` `modal` 4). An accepted ADR records a decision about
|
||
*mechanism*; a flipped flag records a decision about *earned evidence*. Two
|
||
different rulings, and this document conflates neither.
|
||
|
||
## 4. The pin
|
||
|
||
`tests/test_adr_status_governance.py`, registered in the `smoke` suite (the
|
||
pre-push gate). Two independent invariants, both mutation-checked — reverting
|
||
ADR-0256 to `Proposed` fails each one separately:
|
||
|
||
1. **A default-ON flag is not governed by a `Proposed` ADR.** The
|
||
flag → ADR mapping is **derived** by walking `core/config.py` for
|
||
`<name>: bool = True` and reading the ADR references out of the preceding
|
||
comment block. Deliberately not a hand-written table: a second copy of a
|
||
closed set that falls behind the original in silence is the exact defect
|
||
ADR-0256's arc fixed one file over.
|
||
2. **A `ratify-on-merge` predicate cannot coexist with `Proposed`.** Self
|
||
discharging and needs no bookkeeping: the file being present on `main` *is*
|
||
the merge having happened, so the two states are contradictory by
|
||
construction.
|
||
|
||
Plus `test_config_flag_parse_is_not_vacuous`, because a derivation that silently
|
||
parses zero flags would make every other assertion pass on an empty set —
|
||
silence reading as success.
|
||
|
||
Measured: **314 passed in 1.18s** standalone; 2 failed / 312 passed under
|
||
mutation.
|
||
|
||
Current binding scope is exactly one flag/ADR pair
|
||
(`deduction_serving_enabled` → 0256), because only one of the 32 runtime bool
|
||
flags is both default-True and ADR-citing. Narrow today by construction, and it
|
||
widens automatically the moment another earned path is ratified ON — which is
|
||
the point.
|
||
|
||
## 5. Two orphaned test files, registered in passing
|
||
|
||
`tests/test_adr_index.py` (5 tests) and `tests/test_ratification_ceremony.py`
|
||
(14) landed in PR #113 in **no** curated suite. `full` is the directory
|
||
`tests/`, so they ran there and nowhere that gates. Nineteen tests outside every
|
||
gate — including the ceremony, the one mechanism that can move the
|
||
curriculum-volume constraint, and an index test whose whole purpose is catching
|
||
staleness.
|
||
|
||
That is the **fifth** instance of this shape: a stale suite tuple (S5), a stale
|
||
lane roster (#113), a masked lane pin (S2), an unregistered grounding label
|
||
(#113), and now unregistered test files. Registered `test_adr_index.py` into
|
||
`smoke` alongside the new pin, and `test_ratification_ceremony.py` into
|
||
`teaching` beside `test_proposal_queue.py`.
|
||
|
||
## 6. Deliberately NOT fixed — recorded so it is not re-found
|
||
|
||
The ADR corpus is 312 files and its status vocabulary has real drift:
|
||
|
||
| status token | files |
|
||
|---|---:|
|
||
| `accepted` | 201 |
|
||
| `proposed` | 67 |
|
||
| *(status line unparseable)* | **27** |
|
||
| `draft` | 4 |
|
||
| `ratified` | 3 |
|
||
| `accepted.` / `active` / `phase` | 2 each |
|
||
| `implemented` / `empirical` / `superseded` | 1 each |
|
||
|
||
A closed-vocabulary assertion over all 312 would fail on ~35 pre-existing files
|
||
and get muted or `xfail`ed, which is worse than no check — a muted gate reads as
|
||
coverage. So the pin's scope is exactly the ADRs whose status is load-bearing
|
||
*now*, and it fails loudly on any of *those* it cannot parse rather than
|
||
skipping it.
|
||
|
||
**The open item:** normalize the 27 unparseable status lines and collapse
|
||
`ratified`/`draft`/`active`/`implemented` into the intended lifecycle, then
|
||
widen the pin to a closed vocabulary. Sizeable, mechanical, and a good
|
||
delegation candidate — it is a docs sweep with a test as its acceptance
|
||
criterion, not a design question.
|
||
|
||
Relates to [[project-generalization-arc]], `docs/adr/INDEX-by-domain.md`,
|
||
`docs/handoff/BRIEF-CLOSE-assessment-verification-2026-07-25.md`.
|