core/docs/handoff/ADR-0167-FOLLOWUPS.md
Shay ecc0072ea1
chore: remove stub injector + superseded docs (cleanup-as-you-find) (#373)
Three concrete cleanup items from the day's work, per the
cleanup-as-you-find memory principle.

## 1. Remove inject_rate_with_currency stub

PR #369 (A2 rate_with_currency) shipped a function that always returns
() with an extensive docstring documenting the Rate-not-in-SentenceChoice
schema gap. The function is dead at runtime — `_INJECTORS.get(category)`
returning None has the same downstream behavior as the function
returning (). The 16 tests pinned the empty-tuple return; the case-0050
hazard pin is duplicated in test_recognizer_skip_wrong_zero.py and
test_brief_11b_step2_lexicon.py.

The schema gap is now properly documented in ADR-0170 (PR #372). A
dispatch-table comment at the removal site retains the at-code pointer
to that ADR for anyone wiring a new injector.

Removed:
- `inject_rate_with_currency` function in generate/recognizer_anchor_inject.py
- Its `_INJECTORS` dispatch table entry
- Its `__all__` export
- tests/test_injector_rate_with_currency.py (371 lines, 16 tests)

## 2. Remove docs/handoff/GPT55-MOBILE-DISPATCH.md

Single-session travel-time scaffolding. The 5 tasks it named are
complete or superseded by ADR-0170's findings. Pure historical artifact.

## 3. Remove docs/handoff/WAVE-NEXT-INJECTORS.md

Superseded by docs/handoff/WAVE-NEXT-REVISED.md, which captures
everything load-bearing from the original brief in its A1–A4 findings
table. The "kept for history" justification didn't survive scrutiny:
the document was misframed (over-promised lift; misframed schema work
as injector work). Lessons captured in REVISED + ADR-0170.

Updated cross-references:
- WAVE-NEXT-REVISED.md: removed the "supersedes ... kept for history"
  pointer; tightened cross-reference list
- ADR-0167-FOLLOWUPS.md §7: rewrote pointer to name ADR-0170 + REVISED
  as the live plan rather than "the original is retained"

## Test plan

- 219 tests passed across G.2/G.4/G.5/S1/Brief 11/B1/B11A/wiring/partition/DCS-D.2
- evals/gsm8k_math/train_sample/v1/report.json untouched (regen
  surfaces a separate stale-baseline test issue — out of cleanup scope)
- No runtime behavior change

## Net impact

- 5 files removed (~1200 lines)
- 1 file modified for explanatory comment (~30 lines)
- 2 doc files updated to remove dangling cross-references
- 0 behavioral change
2026-05-27 11:08:14 -07:00

271 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ADR-0167 — Follow-ups Queue
**Date opened:** 2026-05-27 (end of Wave 3)
**Parent:** [ADR-0167](../decisions/ADR-0167-audit-as-teaching-evidence.md)
**Companion:** [SESSION-2026-05-27](../decisions/SESSION-2026-05-27-adr-0167-parallel-dispatch.md)
The LexicalClaim slice landed clean (W1-A → W2-A/B/C/D → W3-A merged
2026-05-27). This file captures the named follow-ups that surfaced
during the wave and were deliberately deferred so the slice could
converge. The next operator picking up ADR-0167 work should walk this
queue top-down and decide which item the project's current capability
gate actually needs.
Each item: scope, why deferred, where the breadcrumbs live, and the
acceptance criterion that would close it.
---
## 1. Frame-opener sub-types (FrameClaim / CompositionClaim / ReferenceClaim / SlotClaim)
**Scope.** Four additional ratification handlers, one per remaining
sub-type in `SUB_TYPE_FOR_OPERATOR`:
| Sub-type | Maps from | Ratification primitive |
|---|---|---|
| `FrameClaim` | `pre_frame_filler_sentence`, `multi_subject_sentence` | Verb-category reclassification |
| `CompositionClaim` | `multi_quantity_composition`, `quantity_extraction` | Frame-split rule |
| `ReferenceClaim` | `pronoun_resolution` | Anaphora-resolution entry |
| `SlotClaim` | `question_frame_slot`, `unit_binding`, `question_target_slot`, `descriptive_frame_question` | Slot-completion table entry |
**Why deferred.** ADR-0167 §"Proposed sub-type set" explicitly chose
LexicalClaim-first because it is the lowest-risk surface (drain_token
additions cannot create wrong admissions without also passing graph
completeness). The other four touch frame-opener decisions, anaphora,
or slot bindings — each is a new admission path multiplying the
`wrong=0` surface area, and each needs its own scoping ADR with the
six open questions from ADR-0167 §"Open questions" answered for that
sub-type's mechanics.
**Where breadcrumbs live.**
- `teaching/math_evidence.py::SUB_TYPE_FOR_OPERATOR` — already maps
the operator labels; no schema change needed
- `teaching/math_lexical_ratification.py` — the template for what a
sub-type handler looks like (preconditions, receipt, idempotency,
hazard pins)
- `tests/test_math_lexical_ratification.py::test_rejects_non_lexical_sub_type`
— pins that non-lexical claims currently raise `WrongClaimSubType`;
each new handler retires its corresponding rejection
**Acceptance.** Each new sub-type ships as an ADR (likely ADR-0168,
ADR-0169, ...) followed by a wave of PRs analogous to ADR-0167's W2-D.
Each handler must:
- declare its own `SAFE_CATEGORIES` allowlist analogous to W2-D's
`{"drain_token"}`
- preserve the case 0050 hazard pin
- carry the same idempotency / evidence-tampering / unknown-category
guards W2-D established
- pass an e2e ratification → row-movement test analogous to
`test_lexical_ratification_advances_unknown_word_row`
**Priority hint.** FrameClaim is the highest-leverage next sub-type
(9 cases in the current taxonomy under `pre_frame_filler_sentence`),
but also the riskiest — frame-opener miscategorisation is exactly the
case 0050 hazard. CompositionClaim (8+11 cases) is the next-highest
count, also high-risk. ReferenceClaim (3 cases) and SlotClaim (smaller
buckets) are lower-leverage but structurally simpler.
---
## 2. Partition test architectural fix
**Status.** Closed by `fix/adr-0167-partition-test-invariant`.
The original `git status --porcelain` runtime assertion was retired.
Partition invariants are now expressed behaviorally through:
- serialization discrimination (`domain` omitted for cognition,
explicit for math)
- deterministic canonical-byte divergence between cognition and math
candidates
- existing cognition regression suites already exercised in CI
This removes the structurally brittle requirement that every future
ADR-0167 PR edit a filename allowlist merely to add a new evidence test.
The partition guarantee now lives at the protocol surface instead of
repository working-tree state.
---
## 3. Pre-existing main test failures (unrelated to ADR-0167)
**Status update.** The two failures originally flagged during W3-A were
later traced to a real wrong=0 hazard and fixed in #359 rather than
being treated as unrelated noise.
The relevant fix path:
- recognized-but-uninjectable statements now refuse instead of silently
admitting partial graphs
- audit taxonomy updated accordingly
- regression coverage added for recognizer skip-only fallback behavior
Retain this section as historical context only; do not reopen unless a
fresh regression appears.
---
## 4. Workbench v1 — math candidate rendering
**Scope.** Make the read-only operator UI (ADR-0160/0162) render
`MathReaderRefusalEvidence` candidates alongside cognition
`DiscoveryCandidate` records.
**Why deferred.** ADR-0167 §"Open questions Q4" explicitly out-of-scope.
The LexicalClaim slice ships the ratification handler but no UI to
trigger ratification through — today, an operator would call
`apply_lexical_claim()` from a Python REPL.
**Where breadcrumbs live.**
- ADR-0160 (Core Workbench v1)
- ADR-0162 (Workbench Design System)
- W-029 (proposal queue) — closest existing surface
- W-031 (replay theater) — replay primitive that math evidence
records inherit through ADR-0057
**Acceptance.** A workbench panel that lists pending
`MathReaderRefusalEvidence` candidates with sub-type, claim signature,
recognized terms, refusal context, and a ratify-action that calls
`apply_lexical_claim()` (or its sub-type-specific successor) with an
operator-supplied reviewer tag and category.
---
## 5. Cross-domain partition risks (from Gemini's W2-C audit)
Two specific code paths Gemini flagged in
`docs/handoff/ADR-0167-W2C-cross-domain-audit.md` as needing partition
discrimination:
### 5a. Contemplation pack indexing
**Scope.** `teaching/contemplation.py::contemplate()` uses hardcoded
cognition pack and corpus indexes (`_pack_index` and `_corpus_index`).
Future math-domain candidates would silently get cognition-domain
lookups.
**Acceptance.** Pack and corpus indexes parameterised by
`candidate.domain` — cognition candidates look up cognition packs,
math candidates look up math packs (currently `en_core_math_v1`).
Tests must exercise both paths.
### 5b. Replay gate default
**Scope.** `teaching/proposals.py` defaults its replay gate to
cognition's. Proposing math/admissibility candidates requires passing
`run_admissibility_replay_gate` explicitly to prevent false rejections.
**Acceptance.** Either the replay gate is selected by
`proposal.domain`, or the cognition default is made explicit and math
proposals are required to declare their gate. Decision goes in
ADR-0168 (or wherever the first non-lexical sub-type ADR lands —
that handler will be the first real exerciser of the proposals path
for math).
---
## 6. HolonomyAlignmentCase — structural-vs-blend convergence isolation
**Scope.** Determine whether the existing
`tests/test_alignment_graph.py::test_holonomy_alignment_case_positive_closer_than_negative`
proves *structurally-derived* cross-language convergence or only proves
*endpoint similarity under the mount-time blend*.
**Why deferred.** The proof obligation is executed today — the test
asserts that an aligned Logos clause produces nearer holonomies across
English/Hebrew/Greek than a misaligned negative triple. That clears the
schema's nominal claim. But the test does not distinguish two possible
explanations for the convergence:
1. **Structural.** The Hebrew tri-consonantal root rotors and Greek
case-last orientation rotations produce versors that genuinely
land in the same regions of the manifold because the morphology
operators encode equivalent semantic structure.
2. **Blend-induced.** `_apply_mounted_primary_domain_resonance`
(`language_packs/compiler.py:558`) nudges Hebrew/Greek versors
toward an English prototype at 40% blend, and the test passes
because both packs have been pulled close to the English anchor
regardless of structural derivation.
If (2) is doing the work, the three-language architecture is a *claim*
that English-anchored geometric averaging produces the right endpoints,
not a *proof* that the depth packs are structurally independent
operators converging coherently with the articulation surface.
**Where breadcrumbs live.**
- `language_packs/compiler.py::_apply_mounted_primary_domain_resonance`
— the architectural-invariant comment names this gap explicitly and
references this section
- `tests/test_alignment_graph.py:73` — the existing positive-closer-
than-negative assertion
- `language_packs/schema.py::HolonomyAlignmentCase` — the schema type
whose nominal contract is "proves structural divergence with
coherent convergence"
**Acceptance.** One of:
- **(a) Ablation test.** A test that runs the holonomy proof with
`_apply_mounted_primary_domain_resonance` disabled (or with the
blend factor set to 0.0) and asserts that the positive-closer-than-
negative relation still holds. This would prove (1) and retire the
concern.
- **(b) Reframe the claim.** If the ablation fails, document
explicitly that cross-language convergence depends on the
mount-time blend, and update `HolonomyAlignmentCase`'s contract to
reflect what it actually proves (endpoint similarity under blend,
not structural-derivation equivalence). Honest documentation of a
weaker property beats a stronger claim that the test can't support.
**Priority.** Low-urgency, high-information. Not blocking any current
capability gate. Worth picking up whenever someone next touches the
language-pack architecture — the comment at the convergence-decision
site is the trip-wire.
Per CLAUDE.md §"Schema-Defined Proof Obligations" — this is the
prototypical example of a schema-defined obligation that is executed
but where the test may not meaningfully fail under the violation it is
written to catch.
---
## 7. Wave-Next findings + schema-gap backlog
The Wave-Next injector dispatch (A1A4) surfaced four findings that
materially change the next-capability sequencing. **See
`docs/handoff/WAVE-NEXT-REVISED.md`** for the full pivot — short
version below.
- **A1 currency_amount** — sandbox-blocked write; real lift potential
(`charges`/`earns` verbs not in `_INITIAL_HAS_RE`); reimplementation
queued
- **A2 rate_with_currency** — schema gap (PR #369 merged): `Rate` not
in `SentenceChoice` union. Concrete 4-step extension plan in
`WAVE-NEXT-REVISED.md` §Schema-Gap 1
- **A3 multiplicative_aggregation** — emission shape correction needed
(`CandidateInitial(product)`, not `Operation(multiply)`). Zero current
GSM8K cases match the canonical narrow form anyway; folds into the
CompositionClaim ADR
- **A4 temporal_aggregation** — schema gap: needs `apply_rate`
primitive that doesn't exist in the algebra
The actually-tractable next wave is **ADR-0170 injector contract
widening** + per-category injector follow-up PRs. See
`WAVE-NEXT-REVISED.md` and `ADR-0170-injector-contract-widening.md`
for the full plan; `DCS-S1-FINDING.md` for the investigation that
surfaced the contract gap.
---
## Sequencing recommendation
For the operator picking this up next:
1. **First**, decide which of the four frame-opener sub-types (§1) the
next capability gate actually demands. ADR-0166 still gates this —
the three-question test must pass for whichever sub-type is chosen.
2. **Next**, parameterise contemplation pack indexing and replay-gate
selection by `candidate.domain` before the second sub-type lands.
3. **Then**, begin ADR-0168 (likely FrameClaim-first) with explicit
wrong=0 hazard pins carried forward from case 0050.
4. **Finally**, workbench rendering can follow once a second sub-type
actually exists.
No timelines. Order is by leverage, not calendar.