Captures the named follow-ups that surfaced during the ADR-0167 wave so they don't drift. Five items, each with scope / why-deferred / breadcrumbs / acceptance criterion: 1. Frame-opener sub-types (FrameClaim / CompositionClaim / ReferenceClaim / SlotClaim) — four additional handlers, each its own ADR 2. Partition test architectural fix — current git-status-at-test-runtime assertion is structurally brittle (3 options outlined) 3. Two pre-existing main failures (test_unparseable_statement, test_audit_real_corpus_runs_clean) — fix or quarantine, don't ignore 4. Workbench v1 math-candidate rendering — ADR-0167 §Q4 5. Cross-domain partition risks Gemini flagged (contemplation pack indexing, replay gate default) Includes leverage-based sequencing recommendation (no timelines per project convention). Docs-only. No code, no test, no eval, no pack change.
9.6 KiB
ADR-0167 — Follow-ups Queue
Date opened: 2026-05-27 (end of Wave 3) Parent: ADR-0167 Companion: SESSION-2026-05-27
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 neededteaching/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 raiseWrongClaimSubType; 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_CATEGORIESallowlist analogous to W2-D's{"drain_token"} - preserve the case 0050 hazard pin (see feedback-wrong-zero-hazard-case-0050)
- 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
Scope. Reframe or retire
tests/test_candidate_domain_partition.py::test_existing_cognition_tests_untouched.
Why deferred. The current test uses git status --porcelain at
test runtime to enumerate modified files, then asserts each name is in
a named allowlist. Opus's W3-A report flagged this as structurally
brittle: every future ADR-0167 PR has to edit the allowlist or the
test fails, regardless of whether the PR actually touched cognition
behaviour. Opus loosened from a single literal to a named set in W3-A
as a tactical fix, but the architectural problem remains — a partition
invariant doesn't belong as a git-state assertion in a pytest run.
Where breadcrumbs live.
tests/test_candidate_domain_partition.py::test_existing_cognition_tests_untouched— the current implementation- W3-A's PR description (#357) — the deeper brittleness flag in Opus's report-back
Acceptance. One of:
- (a) Retire the test entirely — partition is already enforced
structurally by the
domainfield default + type discriminator; the cognition test suite already runs against every PR and would break naturally if a PR modified cognition behaviour - (b) Move to CI — a GitHub Actions workflow that runs
git diff --name-only origin/main...HEAD -- tests/and fails on any cognition test path modification, with CODEOWNERS providing the human review layer - (c) Reframe as a diff-review constraint — drop the test, add a
CODEOWNERS entry requiring a cognition reviewer for any PR touching
tests/test_*cognition*.pyor similar
Pick whichever fits the project's CI discipline. Option (a) is simplest if the assertion is genuinely redundant; (b) is most precise; (c) is most operator-friendly.
3. Pre-existing main test failures (unrelated to ADR-0167)
Scope. Two tests fail on clean main and on every branch that
touches anything; W3-A's regression run surfaced them but they
predate the LexicalClaim wave.
tests/test_math_candidate_graph.py::TestRefusals::test_unparseable_statementtests/test_teaching_audit.py::test_audit_real_corpus_runs_clean
Why deferred. Out of scope for the LexicalClaim slice — these are not regressions caused by the wave. Confirmed by W3-A's report: both fail on origin/main with no ADR-0167 changes applied.
Where breadcrumbs live.
- Run
uv run pytest tests/test_math_candidate_graph.py -k test_unparseable_statement -von clean main to reproduce - Run
uv run pytest tests/test_teaching_audit.py -k test_audit_real_corpus_runs_clean -von clean main to reproduce
Acceptance. Each test either:
- gets fixed (root cause investigation + minimal patch), or
- gets quarantined via the existing test-quarantine mechanism with a written reason that names what's actually broken
The "fix or quarantine, don't ignore" principle stands. They are distracting noise during regression runs and obscure real regressions.
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).
Sequencing recommendation
For the operator picking this up next:
- 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.
- In parallel, do §2 (partition test fix) as a small docs/CI PR — it unblocks every future ADR-0167 PR's regression run.
- At convenience, handle §3 (pre-existing failures) — distracting but not blocking.
- Defer §4 + §5 until §1 actually ships a second sub-type — they only become load-bearing once a second domain candidate type exists.
No timelines. Order is by leverage, not calendar.
Cross-references
- ADR-0167 — parent
- SESSION-2026-05-27 — wave narrative
- ADR-0167 Parallel Work Plan — original dispatch plan
- W2-C Cross-Domain Audit — Gemini's site survey
- ADR-0166 — the gating rule every follow-up must answer