# ADR-0163 — Path to GSM8K mastery: candidate-graph admissibility via the contemplation/HITL corridor **Status:** Proposed — *Phases B–E prescription superseded by [ADR-0164](./ADR-0164-incremental-comprehension-reader.md) (2026-05-26)* **Date:** 2026-05-26 **Author:** Shay **Anchor:** [[thesis-decoding-not-generating]] **Parent:** [ADR-0114a — Capability Obligations](./ADR-0114a-capability-obligations.md), [ADR-0119 — GSM8K eval lane](./) **Companions:** [ADR-0149 — Recognizer pipeline](./), [ADR-0151 — Auto-proposal pipeline](./ADR-0151-auto-proposal-pipeline.md), [ADR-0152 — Learning-arc proof corridor](./ADR-0152-learning-arc-demo.md), [ADR-0155 — CI contemplation runner](./ADR-0155-ci-contemplation-runner.md), [ADR-0161 — HITL async queue](./ADR-0161-hitl-async-queue.md), [ADR-0132/0133/0134/0135 — Binding graph](./) **Superseded in part by:** [ADR-0164 — Incremental Comprehension Reader](./ADR-0164-incremental-comprehension-reader.md), [ADR-0165 — Regex Scope Rule](./ADR-0165-regex-scope-rule.md) --- ## Amendment 2026-05-26 — Prescription superseded by ADR-0164 After observing the post-D.2 train-sample baseline (`correct=3 refused=47 wrong=0`, with 34/47 refusals at the question gate), this ADR's *diagnosis* is reaffirmed and its *prescription* is partially superseded. **Preserved (load-bearing):** - The diagnosis that the front-end (`math_candidate_parser.py`, `math_candidate_graph.py`) is the bottleneck, not the binding graph or the solver. - The `wrong = 0` invariant doctrine. - The contemplation → proposal → review HITL corridor as the population mechanism for new recognition capability (now applied to lexicon entries and lexeme primitives instead of regex recognizers). - Phase A — the refusal taxonomy work. Its outputs (`refusal_taxonomy_v*.json`) remain valid input evidence. - Phase F — the scope expansion to public / holdout / full GSM8K. **Superseded by ADR-0164:** - Phases B–E *prescription* — specifically, the production of regex-based `DerivedRecognizer` records that land in `generate/recognizer_match.py`. ADR-0164 replaces this with an incremental compositional reader that consumes lexicon entries and lexeme primitives. The corridor is unchanged; what flows through it changes. - Constraint #2 of this ADR ("No hand-rolled recognizers in `generate/`") is *tightened* by ADR-0165: regex sentence-templates are forbidden regardless of who writes them. Regex remains permitted at the lexeme-primitive level only. See [ADR-0164 §What's deprecated, what's preserved](./ADR-0164-incremental-comprehension-reader.md) for the full transition plan and acceptance gates. --- ## Context — what the audit found A scoping pass across the unlanded math branches and the actually-shipped state on `main` produced a result that reframes the math architecture question entirely. ### State of the math substrate on `main` The following components are **already landed** (worktrees on disk are stale forks of work that landed via other PR paths): | Component | Status | |---|---| | `generate/binding_graph/` (all 7 modules: model, allocation, adapter, admissibility, units, question_target, `__init__`) | ✅ landed (ADR-0132/0133/0134/0135) | | `generate/math_versor_arithmetic.py` (221 lines) | ✅ landed (ADR-0139/0140) | | `generate/math_symbolic_equivalence.py` (97 lines) + `math_symbolic_normalizer.py` (371 lines) | ✅ landed (ADR-0131.1) | | `generate/math_parser.py` (1,106 lines) | ✅ landed | | `generate/math_candidate_parser.py` (2,232 lines) | ✅ landed | | `generate/math_candidate_graph.py` (511 lines) | ✅ landed | | `generate/math_problem_graph.py` (490 lines) | ✅ landed | | `generate/math_solver.py` (506 lines), `math_verifier.py` (501 lines), `math_realizer.py` (422 lines), `math_roundtrip.py` (484 lines) | ✅ landed | | Capability axis lanes G1..G5, S1 | ✅ landed with v1 corpora | ### Capability axis lane results on `main` Every named capability axis passes its controlled lane at **100% with `wrong = 0`**: | Lane | Cases | Solved correct | Refused as expected | Wrong | Verdict | |---|---|---|---|---|---| | G1 verb classes | 20 | 20 | 0 | 0 | ✅ exit_criterion passed | | G2 comparatives | 29 | 29 | 0 | 0 | ✅ wrong_count_is_zero | | G3 numerics v1 | 26 | 20 | 6 | 0 | ✅ overall_pass: true | | G4 multi-clause | 32 | 32 | 0 | 0 | ✅ wrong_count_is_zero | | G5 aggregate | 20 | 20 | 0 | 0 | ✅ wrong_count_is_zero | | S1 rate events | 20 | 20 | 0 | 0 | ✅ wrong_count_is_zero | ### GSM8K train-sample result on `main` (50 cases, ADR-0126) ```text correct: 0 refused: 50 wrong: 0 exit_criterion: { correct_min: 10, wrong_max: 0, passed: false } ``` Every refusal reason is identical in shape: ```text candidate_graph: no admissible candidate for statement: "" ``` Sample refused statements: - `"Tina makes $18.00 an hour."` — rate with currency - `"She splits it up into 25-foot sections."` — division-into-sections + unit - `"The student council sells scented erasers in the morning before school starts to help raise money for school dances."` — descriptive setup, no extractable quantity - `"There are some kids in camp."` — indefinite quantity ("some") - `"In one hour, Addison mountain's temperature will decrease to 3/4 of its temperature."` — rate of change + fraction ### The reframe The gap is **not** in operator algebra, **not** in the binding graph internals, **not** in symbolic equivalence, **not** in the capability axes themselves. The gap is in `generate/math_candidate_graph.py` — the admissibility surface that turns a natural-language statement into a candidate the downstream pipeline can consume. > **The capability axes pass at 100% because they test statement shapes > the candidate-graph already admits. GSM8K refuses at 100% because its > statements span shapes the candidate-graph has never been taught.** Every downstream component (binding graph, versor arithmetic, symbolic equivalence, multi-clause decomposer, aggregator) is **mastered in isolation**. The lift to GSM8K is *admissibility expansion*, not operator development. This is the most consequential single finding in the math work to date. It reframes the entire roadmap. --- ## Decision — what to build, in what order, under what doctrine ### Doctrine Three non-negotiables: 1. **`wrong = 0` is invariant at every phase.** A `wrong` answer is an architectural regression, not a tuning miss. A `refused` answer is honest; a `wrong` answer is not. Every exit criterion in this ADR reads `wrong_max: 0`. 2. **No hand-rolled recognizers.** New statement shapes land via the `DerivedRecognizer` pipeline that ADR-0149/0154 already wired. The recognizer comes from corpus exemplars, not from operator-written regex. This honors [[thesis-decoding-not-generating]]: we teach the engine to *find* better, not stuff it with more found patterns. 3. **Every new shape lands through the contemplation → proposal → review corridor.** No parallel learning path. Recognizers are proposed by contemplation (ADR-0150/0152), gated by replay-equivalence (ADR-0057), reviewed by the operator via the HITL queue (ADR-0161), and admitted to the active corpus only on ratification. These three rules, applied consistently, make admissibility expansion a **capability** of the engine rather than an editing task on the operator. ### Phases #### Phase A — Refusal taxonomy (measure before building) Goal: categorize every refused statement in the GSM8K train sample by *statement shape*, not by content. Deliverables: 1. `evals/gsm8k_math/refusal_taxonomy/v1/taxonomy.jsonl` — one record per refused statement, carrying `case_id`, `statement`, `refusal_reason`, and a typed `shape_category` enum. 2. Initial shape categories (extend as the corpus grows): - `rate_with_currency` — "Tina makes $18.00 an hour." - `unit_partition` — "She splits it up into 25-foot sections." - `descriptive_setup_no_quantity` — pure context with no extractable measurement. - `indefinite_quantity` — "some", "a few", "several". - `fractional_rate_of_change` — "decreases to 3/4 of its temperature". - `comparative_with_unit` — "20% more than", "twice as long as". - `nested_question_target` — "How many more than X did Y have?" - `temporal_aggregation` — "over five days, she earns…" - `conditional_quantity` — "if she had 2 more, she would have…" 3. A new eval lane `evals/refusal_taxonomy/` that runs the categorizer over an arbitrary refused-statement set and emits the histogram. 4. Acceptance: every refused statement in the 50-case sample has a typed `shape_category`; "uncategorized" count is reported but non-blocking. This phase produces no recognizers and no corpus changes. It is the load-bearing measurement that prevents Phase B from chasing the wrong gap. #### Phase B — Exemplar corpus per shape category Goal: for each top-N shape category from Phase A, hand-author a small exemplar corpus (≤ 20 statements per category) with the expected `MathProblemGraph` shape annotated. Deliverables: 1. `teaching/admissibility_exemplars/_v1.jsonl` per category, each line carrying `statement`, `expected_graph`, and `provenance`. 2. The exemplar corpus is **reviewed-evidence floor** material under ADR-0057 — pack-consistent, boundary-clean, polarity affirms. 3. Top-N is chosen by Phase A's histogram. Three categories per round; ratchet rather than scope creep. This phase is the only place hand-authoring happens. Twenty statements per category, three categories per round — sixty hand- authored statements total per round. Each one is a *seed* the contemplation loop generalizes. #### Phase C — Contemplation ingests exemplars and emits recognizer proposals Goal: the contemplation runner (ADR-0150/0152/0155) ingests each exemplar corpus, decomposes the statements, and emits one or more `DerivedRecognizer` proposals per shape category. Deliverables: 1. Contemplation runner extended to ingest the exemplar corpus path as a candidate source (alongside `discovery_candidates.jsonl`). 2. Each proposal carries: - the shape category it generalizes, - the recognizer's pattern in canonical form, - replay-equivalence evidence against the active corpus + the exemplar set, - per-shape coverage metrics. 3. Proposals land in `teaching/proposals/proposals.jsonl` as usual (ADR-0057), visible in the HITL queue (ADR-0161 §1). 4. **`wrong = 0` invariant**: each proposal's replay-equivalence gate runs against the GSM8K train sample. If accepting the proposal would lift `wrong` above 0 even on a single case, the proposal is auto-rejected at the gate. #### Phase D — Operator ratifies through HITL queue Goal: the operator reviews each recognizer proposal through the existing surfaces (CLI / workflow_dispatch / GitHub PR review) per ADR-0161 §2. Deliverables: - No new operator surface. The proposals appear in the queue with their shape category, exemplar coverage, replay evidence, and the ratification CLI command. - Operator accepts, rejects, or withdraws. - Engineering wiring (landed alongside the operator surface, ADR-0163.D PR): - `generate/recognizer_registry.py` — pure projection of accepted `exemplar_corpus` proposals from the proposal log into a sorted-tuple of :class:`RatifiedRecognizer` records. In-process cache keyed on the log's (mtime, sha256). - `generate/recognizer_match.py` — per-category rules-only matchers (no LLM, no embedding) honoring the Phase C synthesizer's narrowness rule: out-of-corpus surface forms return None. ``parsed_anchors`` carry extracted tokens from the statement. - `generate/math_candidate_graph.py` — narrowest-edit guard at the per-statement choice loop: before the existing "no admissible candidate for statement" refusal, consult the ratified registry. Recognized statements are skipped from ``per_sentence_choices`` (contribute zero math state), preserving wrong=0 by construction. Empty registry is a no-op. - Downstream consumption of ``parsed_anchors`` (turning recognized rate/temporal surfaces into solver state) is Phase E follow-up. #### Phase E — Re-baseline GSM8K train sample Goal: after each ratification round, re-run the train-sample eval and update the counts. Deliverables: 1. Automated re-baseline triggered by any merge that adds a recognizer. 2. Pass criteria for this ADR: - **Round 1 exit**: `correct ≥ 10`, `wrong = 0` on the 50-case sample (matches the existing exit criterion in the report's `exit_criterion` block). - **Round 2 exit**: `correct ≥ 25`, `wrong = 0`. - **Round 3 exit**: `correct ≥ 35`, `wrong = 0`. 3. Each round runs Phases A → B → C → D → E in sequence. #### Phase F — Scale to public, holdout, full GSM8K Once the train sample clears Round 3, scope expands: | Split | Cases | Target | |---|---|---| | `public/v1` | 200 | `correct ≥ 0.5 × cases`, `wrong = 0` | | `holdout/v1` | 200 | first run is measurement-only; do not tune against | | Full GSM8K (8,500) | 8,500 | post-Phase F follow-up ADR; out of scope here | The holdout run is **never** used to drive recognizer additions. Per ADR-0114a doctrine, holdout is the OOD ratio check; tuning against it would invalidate the eval. --- ## Constraints (non-negotiable) 1. **`wrong = 0` at every phase, every round, every split.** Refusals are honest; wrong answers are architectural regressions. Any recognizer that would lift `wrong` above 0 is auto-rejected by the replay gate, never by operator judgment alone. 2. **No hand-rolled recognizers in `generate/`.** Every recognizer added to the runtime comes from the contemplation → proposal → review corridor. Phase B's exemplar corpus is **input** to that corridor, not output of it. A PR that adds a regex-style recognizer directly to `math_candidate_parser.py` violates this ADR and must be rejected. 3. **Replay-equivalence is a precondition, never permission.** Per ADR-0057, replay-equivalence makes a proposal *eligible for review*, not *automatically accepted*. This ADR does not weaken that. 4. **Active corpus mutation only via `accept_proposal`.** Per ADR-0152 and ADR-0156/0158, the only path that mutates the active teaching corpus is the reviewed accept path. Recognizer additions land via that path or not at all. 5. **No tuning against holdout.** Phase F's holdout split is measurement-only. Tuning against it makes the eval lie. 6. **Determinism preserved.** Each round's recognizer addition is a reviewed, append-only mutation. GSM8K runs at any historical SHA replay byte-identically given the corpus at that SHA. --- ## Out of scope This ADR does not commit to: - a frontier-model comparison harness beyond what ADR-0119 already scoped; - a benchmark publication strategy; - patent prep work; - Rust backend parity for the math path (waiting on Python semantics to lock, per CLAUDE.md work-sequencing); - the full GSM8K split (8,500 problems) — that lives in a follow-up ADR after Phase F clears `public`; - non-GSM8K math benchmarks (MATH, AQuA, ASDiv) — scoped by separate ADRs once the corridor proves itself on GSM8K; - multimodal math (charts, geometry images); - a math-specific workbench surface — the existing Workbench (ADR-0160 / 0162) is sufficient; lane-level inspection of refusal histograms becomes a `RefusalHistogramPanel` in the Eval Center (W-030) once that lands. --- ## Implementation plan — first three PRs ### PR 1 — Phase A scaffolding (refusal taxonomy) - `evals/refusal_taxonomy/` lane: contract.md, runner.py, v1/cases.jsonl (mirrors the 50 refused statements from `train_sample/v1/report.json`). - `evals/refusal_taxonomy/v1/shape_categories.py` — the enum. - `core teaching refusal-taxonomy --input ` CLI command for re-running over an arbitrary refused set. - Tests pin the enum coverage and the shape-categorizer's deterministic output. - Produces an initial histogram of the 50-case sample. ### PR 2 — Phase B round 1 exemplar corpora For the top three shape categories from PR 1's histogram, hand-author ≤ 20 exemplar statements each with expected `MathProblemGraph` shape. No runtime change. ### PR 3 — Phase C contemplation extension Extend the contemplation runner to ingest exemplar paths as candidate sources. Surface the per-shape coverage metric in the proposal log. No new ratification path; existing HITL queue (ADR-0161) handles it. After PR 3 lands, the contemplation runner produces recognizer proposals; the operator ratifies; Phase E re-baseline confirms `correct ≥ 10, wrong = 0`. Round 1 closes. --- ## Round 1 — what actually shipped (2026-05-26 amendment) The corridor closed end-to-end in a single session, faster than the implementation plan above projected. Five PRs landed in order: | Phase | PR | Title | |---|---|---| | A | #297 | refusal taxonomy lane — 9 shape categories, 72% of 50-case sample categorized | | B | #298 | exemplar corpora — descriptive_setup_no_quantity / temporal_aggregation / rate_with_currency (20 each) | | C | #301 | recognizer synthesis + admissibility replay gate; three pending proposals in live log | | D | #302 | candidate-graph wiring via single-edit skip-only `continue` | | D-ratify | #304 | operator accepted all three Phase C recognizers | ### First measured lift on GSM8K train_sample ``` correct: 3 (up from 0 — first non-zero correct count ever) refused: 47 (down from 50) wrong: 0 (unchanged — the invariant holds) exit_criterion: { correct_min: 10, wrong_max: 0, passed: false } ``` Lifted cases: - `gsm8k-train-sample-v1-0014` — "Bob can shuck 10 oysters in 5 minutes. How many oysters can he shuck in 2 hours?" → 240 - `gsm8k-train-sample-v1-0018` — "Xavier plays football. During 15 minutes Xavier can score 2 goals on average..." → 16 - `gsm8k-train-sample-v1-0042` — "Ella has 4 bags with 20 apples in each bag and six bags with 25 apples in each bag. If Ella sells 200 apples, how many apples does she have left?" → 30 **Capability-axis floor preserved** — G1..G5 + S1 all report `wrong = 0` post-ratification, byte-identical to the pre-Phase-D baseline. ### Unexpected positive observation None of the three lifts are pure `descriptive_setup_no_quantity` cases — they all involve temporal or aggregation framings. Phase D's skip-only wiring is doing more useful work than the projection suggested: when a previously-refusing statement is skipped, the *question* + *remaining statements* together carry enough math for the existing solver to produce the right answer. **A Phase B round 2 (more shape categories from the uncategorized 14) may be a more direct path to clearing Round 1 exit (`correct ≥ 10`) than the originally-planned Phase D.2 (parsed_anchors solver plumbing).** Worth measuring before scoping Phase D.2. ### Phase E status The Phase E re-baseline harness (versioned baselines under `evals/gsm8k_math/train_sample/v1/baselines/`, workflow_dispatch + nightly schedule, `LiftReport` schema, append-only history) was briefed but not dispatched in this session. The re-baseline above was produced by running `evals.gsm8k_math.train_sample.v1.runner` against `origin/main` post-#304. Phase E will automate this. See [SESSION-2026-05-26-corridor-closure.md](../sessions/SESSION-2026-05-26-corridor-closure.md) for the full session ledger. ## Phase D.2 amendment — discrete_count_statement injection v1 Phase D.2 v1 plumbs `parsed_anchors` from one round-2 recognizer (`discrete_count_statement`) into the candidate-graph as `CandidateInitial`. The wiring is the first PR where a recognizer's matcher output becomes solver input; wrong=0 moves from "skip-only by construction" to **five layered safety nets** that all must hold: 1. **Matcher narrowness** — `_try_extract_discrete_count_anchor` refuses on ambiguity: requires a single proper-noun subject, a closed possession-verb whitelist (`has`/`have`/`had`), exactly one numeric token, `count_kind ∈ observed_count_kinds`, `counted_noun ∈ observed_counted_nouns`, no clause-split connectives. 2. **Extraction correctness** — the recognizer's match returns `parsed_anchors=()` (detection-only fallback) when the narrowness rules fail; the per-category injector returns `()` on any construction failure. 3. **Injection correctness** — the built `CandidateInitial` is gated by `_initial_admissible` upstream of the Cartesian product; failures under-admit (return `()`) rather than over-admit. 4. **Replay gate** — propose-time `run_admissibility_replay_gate` auto-rejects extraction changes that lift GSM8K wrong count. 5. **Multi-branch decision rule** — when an injected candidate disagrees with another branch's answer, the candidate-graph refuses. **Re-baseline (GSM8K train_sample v1, post-D.2 v1):** `correct=3, refused=47, wrong=0` — **identical to the pre-D.2 baseline**. The framework lands and is operational, but no GSM8K train_sample case has a discrete_count statement that simultaneously (a) the existing parser misses, (b) carries a counted_noun in the spec's observed lemma set, (c) carries exactly one numeric token, and (d) carries no clause-split connectives. Empirical lift in v1 = 0 cases; the bottleneck is **other recognizer categories** (rate_with_currency, temporal_aggregation, multiplicative_aggregation, currency_amount) whose injectors return `()` (skip-only fallback) until follow-up PRs D.2.2..D.2.5 plumb them. **Operator caveat — matcher behavior, not canonical_pattern.** Round-1's ratified `discrete_count_statement` spec is unchanged. The matcher's behavior on the spec's `canonical_pattern` has been extended from detection-only to populated `parsed_anchors`. Re-ratification is not required for this extension; if policy requires re-ratification when matcher behavior changes, the registry digest provides byte-stable provenance. **G1..G5 + S1 wrong=0 invariant:** 222 passed / 2 pre-existing report-comparison failures / 3 skipped — byte-identical to pre-D.2. **Solver code: unchanged.** The injector returns the same `CandidateInitial` type the existing parser produces; the solver runs unchanged. **Follow-up PRs (D.2.x):** - D.2.2 — `rate_with_currency` parsed_anchors → solver state - D.2.3 — `temporal_aggregation` parsed_anchors → solver state - D.2.4 — `multiplicative_aggregation` parsed_anchors → solver state - D.2.5 — `currency_amount` parsed_anchors → solver state Each ships in its own PR after the operator reviews D.2 v1's framework and empirical lift; the dispatch table in `generate/recognizer_anchor_inject.py` is the single registration site. --- ## Acceptance criteria This ADR is ratifiable when: 1. The audit findings above are independently verifiable by running each capability axis lane on `main` and observing `wrong = 0`. 2. The GSM8K train-sample `correct: 0, refused: 50, wrong: 0` baseline is reproducible at the current commit SHA. 3. The phase ordering (A → B → C → D → E → F) does not allow Phase B to start before Phase A produces a histogram, nor Phase C before Phase B writes exemplars. 4. The `wrong = 0` invariant is enforced as an auto-reject in the replay-equivalence gate, not as a post-hoc operator check. This ADR is **delivered** when: 5. GSM8K `public/v1` (200 cases) reaches `correct ≥ 100, wrong = 0`. 6. GSM8K `holdout/v1` measurement-only run is recorded once at the end and never used to drive recognizer additions. --- ## Consequences ### Positive - The math roadmap is reduced from "build operators, build axes, build decomposer, build aggregator" to **one** problem: expand the candidate-graph's admissibility surface through the contemplation corridor. Every other math component is mastered. - Recognizer additions become a *capability* of the engine, not an editing task on the operator. The thesis ("decodes, not generates") manifests in the math lane directly. - The exit criterion (`wrong = 0` at every round) is enforceable by the replay gate, not by operator vigilance. - The HITL queue (ADR-0161) absorbs the curriculum-expansion pressure the master plan flagged as a future risk. Math is the first lane that scales through it. ### Negative - Phase A (refusal taxonomy) is upfront measurement work that ships no capability. Two-three days of audit before any GSM8K case starts passing. Worth it; the alternative is operators chasing whichever problem shape caught their eye first. - The exemplar corpus (Phase B) is hand-authored. Sixty statements per round, hand-checked for shape correctness, is real work. The alternative — auto-mining exemplars from GSM8K itself — would violate the holdout discipline and tune against the benchmark we're trying to honestly measure. - The `wrong = 0` auto-reject gate may auto-reject proposals that are *almost* right. This is intentional. An almost-right recognizer that produces one wrong answer is worse than a refusal. ### Risks - **The taxonomy could fragment.** Mitigation: cap initial shape categories at ~9 and require every new category to cite ≥ 3 refused statements. Phase A acceptance test enforces this. - **The HITL queue could backlog.** ADR-0161 §4's pending cap (256) applies here. If math proposals saturate the queue, the operator raises the cap via repo variable or pauses contemplation runs. - **Recognizer generalization could overfit to exemplars.** Mitigation: every recognizer is replayed against the *entire* GSM8K train sample and the public capability axes; regression on any axis auto-rejects. --- ## Cross-references - [ADR-0114a — Capability Obligations](./ADR-0114a-capability-obligations.md) — perturbation, OOD ratio, depth curve obligations the math lane must keep honoring - [ADR-0119 — GSM8K eval lane](./) — eval lane definition - [ADR-0131.G.* — capability axis lanes](./) — G1..G5, S1 mastered - [ADR-0132/0133/0134/0135 — binding graph](./) — landed substrate - [ADR-0139/0140 — versor arithmetic](./) — landed operator algebra - [ADR-0149/0154 — recognizer pipeline](./) — substrate this ADR builds on - [ADR-0150/0152 — autonomous contemplation + learning-arc corridor](./ADR-0152-learning-arc-demo.md) — proposal source - [ADR-0155 — CI contemplation runner](./ADR-0155-ci-contemplation-runner.md) — async producer - [ADR-0057 — proposal review + replay-equivalence](./ADR-0057-teaching-chain-proposal-review.md) — gating discipline - [ADR-0161 — HITL async queue](./ADR-0161-hitl-async-queue.md) — review surface - [CLAUDE.md](../../CLAUDE.md) — `wrong = 0` discipline, no hidden normalization, exact recall, proposal-only learning ### Memory cross-references - [[thesis-decoding-not-generating]] — the load-bearing thesis this ADR applies to math. Every recognizer comes from the engine learning a shape, not from the operator stuffing a regex. - [[feedback-address-critiques-dont-waive]] — the audit critique ("the gap is admissibility, not operators") is acted on here, not noted. - [[feedback-adr-cross-reference-discipline]] — every substrate this ADR builds on is cited; no parallel mechanism is introduced. - [[feedback-cleanup-as-you-find]] — the stale `feat/adr-0131-*` and `feat/binding-graph-phase*` branches on disk should be deleted as a hygiene PR after this ADR ratifies; the work is already on main. - [[feedback-scope-time-is-cheap]] — Phase A is the "pause and scope" move applied to math. Two-three days of taxonomy before any recognizer work prevents weeks of chasing the wrong gap.