From 5ae377065e4cdd00028cc9bdc580845684ca980f Mon Sep 17 00:00:00 2001 From: Shay Date: Wed, 3 Jun 2026 21:14:02 -0700 Subject: [PATCH] =?UTF-8?q?docs:=20composition-wall=20execution=20scope=20?= =?UTF-8?q?(ADR-0207=20=C2=A75=20step=202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three reviewed, non-serving analysis/handoff docs for the COMPOSITION lever. Read-only; no serving code; train_sample 6/44/0 untouched. - analysis/wiring-promotion-gate-brief: product_bridge is the only serving derivation tendril (two-token target whitelist); resolve_pooled refuses all ten R1/R4/R5/R6 positives and wrong-commits 0016 -> 510. Wiring is trivial; the gate is the work. - analysis/composition-wall-execution-plan: per-case stage taxonomy (A/B/C/D) for all 15 corpus positives, reproduced live; R4-first scope (new goal-residual production, verified by code-read of accumulate.py, NOT a target tweak); promotion gate generalizes product_bridge, never disagreement alone; gates inherit ADR-0207 §6 (corpus + sealed 1,319). - handoff/stage-c-composition-investigation: dispatch task for the execution lane to pin the per-case bail for the production-wrong shapes (the real grouping/op-order wall), read-only, in-tree. --- ...position-wall-execution-plan-2026-06-03.md | 172 ++++++++++++++++++ .../wiring-promotion-gate-brief-2026-06-03.md | 166 +++++++++++++++++ ...-c-composition-investigation-2026-06-03.md | 69 +++++++ 3 files changed, 407 insertions(+) create mode 100644 docs/analysis/composition-wall-execution-plan-2026-06-03.md create mode 100644 docs/analysis/wiring-promotion-gate-brief-2026-06-03.md create mode 100644 docs/handoff/stage-c-composition-investigation-2026-06-03.md diff --git a/docs/analysis/composition-wall-execution-plan-2026-06-03.md b/docs/analysis/composition-wall-execution-plan-2026-06-03.md new file mode 100644 index 00000000..48d74b5c --- /dev/null +++ b/docs/analysis/composition-wall-execution-plan-2026-06-03.md @@ -0,0 +1,172 @@ + + +# Composition Wall — Execution Plan (R1/R4 first) + +This is the execution scope for **ADR-0207 §5 step 2 (COMPOSITION)** — *not* a new design. It +takes the ratified substrate as given and answers the only question that matters next: *what, +concretely, must change in the built `generate/derivation/` composer to move the live metric, +and where is each target shape actually blocked?* Every per-case claim below was reproduced +read-only against the tree on 2026-06-03 by running the actual composer on the corpus cases. + +## 1. The wall, restated from reproduction (folds in the wiring brief) + +- `resolve_pooled` (the general pooled composer, `pool.py:62`) **refuses all ten R1/R4/R5/R6 + corpus lift-targets**, so wiring it to serving yields **+0 correct**; and it **wrong-commits + `0016 → 510`** (gold 2), so wiring it wholesale is a live `wrong=0` regression. +- The only derivation symbol on serving is `product_bridge.resolve_promotable_product` + (`math_candidate_graph.py:530`), and its safety is a **two-token target near-whitelist** + (`money`+`make/earn`, `weight`+`total/move`) — it does not generalize. +- Therefore **WIRING is trivial and already done for the safe shapes**; the actual work is + making the composer *build the right chain for a new shape and certify it*. The wire is the + last, one-line step (mirror the `:530` block) once a shape builds-and-certifies. + +## 2. Grounded per-shape diagnosis (all 15 corpus positives) + +Ran `extract_quantities` → `extract_target` → the three composers +(`accumulation_candidates` / `multiplicative_candidates` / `candidate_chains`) on each. "Stage" +is where the shape is blocked (see §3). Golds are dataset-sourced (corpus invariant 6). + +| case | comp | gold | #qty | target-agg | acc/mul/chn | result | **stage** | +|---|---|---|---|---|---|---|---| +| cv-0001 | R1 | 64 | 1 | None | 0/0/0 | none | **A** extraction (`$16` not extracted) | +| cv-0003 | R1 | 9 | 6 | None | 0/0/0 | none | **B** target | +| cv-0002 | R1 | 400 | 3 | total | 0/0/4 | wrong-only | **C** production | +| cv-0004 | R1 | 3840 | 4 | None | 0/1/4 | wrong-only | **C** production | +| cv-0005 | R4 | 3 | 3 | None | 0/0/0 | none | **B** target | +| cv-0021 | R4 | 4 | 4 | None | 0/0/0 | none | **B** target | +| cv-0006 | R5 | 14 | 2 | None | 3/0/4 | wrong-only | **C** production | +| cv-0022 | R5 | 38 | 2 | total | 0/1/4 | wrong-only | **C** production | +| cv-0007 | R6 | 21 | 3 | None | 0/0/0 | none | **B** target | +| cv-0008 | R6 | 15 | 1 | None | 0/0/0 | none | **A**+**B** extraction+target | +| cv-0009 | compare_mult | 60 | 1 | altogether | 0/0/0 | none | **A** extraction | +| cv-0018 | compare_mult | 28 | 2 | None | 0/0/2 | wrong-only | **C** production | +| cv-0019 | additive | 1200 | 2 | None | 0/0/0 | none | **B** target | +| cv-0017 | *(control)* | 438 | 5 | None | 0/0/2 | wrong-only | control — solves on serving | +| cv-0020 | *(control)* | 450 | 3 | total | 0/1/2 | **GOLD-BUILT** | control — **D** gate exemplar | + +Controls (cv-0017=case 0024, cv-0020=case 0021) already solve on serving via other paths; they +are regression anchors, not lift targets. cv-0020 is the **proof the build-then-gate pattern +works**: the pool *builds the gold* (450) but only commits it on serving because +`product_bridge`'s gate promotes it. + +## 3. The four-stage failure taxonomy (and the `wrong=0` firewall at each) + +The composer is a pipeline: **extract → characterize target → build production → certify (gate)**. +A shape can be blocked at any stage; each stage refuses (never commits) when incomplete, so +`wrong=0` holds throughout. + +- **Stage A — extraction-thin.** The composer is starved of a needed quantity, so no chain is + possible. *cv-0001* (currency literal `$16` not extracted — the derivation reader has no `$N` + production; this is the gap I earlier *overstated as closed*), *cv-0008*, *cv-0009*. Firewall: + no quantity → no candidate → refuse. +- **Stage B — target-uncharacterized.** Quantities are present but `extract_target` returns + `aggregation=None`, so the composer doesn't know *what* to build. *cv-0003, cv-0005, cv-0007, + cv-0019, cv-0021*. **Both R4 cases live here.** Firewall: no target → no admissible chain → refuse. +- **Stage C — production-wrong.** The composer builds chains, but the *wrong* ones (none equals + gold), and the disagreement rule correctly refuses them. *cv-0002, cv-0004, cv-0006, cv-0018, + cv-0022.* This is the hard core — "which quantities group, via which ops, in what order." + Firewall: disagreement among wrong candidates → refuse. +- **Stage D — gold-built, needs gate.** The composer builds the gold (possibly among rivals); a + *structural* promotion gate certifies and commits it. Exemplar: *cv-0020* via `product_bridge`. + Firewall: the gate must prove the reading; a lone wrong chain with no rival (the *0016* pattern) + is exactly what disagreement cannot catch, so **the gate must be structural, never + disagreement alone.** + +## 4. Execution sequence — one shape, end-to-end, instrumented + +Each shape is a **hypothesis to test against the gates**, not a guaranteed win. Drive *one* shape +through its blocked stages to green on the corpus, then check the sealed 1,319, before starting +the next. + +1. **R4 first — but it is NEW PRODUCTION, not a target tweak** (verified 2026-06-03 by code-read + of `accumulate.py`: `_build_accumulation` is single-referent gain/loss running-total with **no + goal/target/residual concept** — target characterization alone does **not** unblock it). cv-0005 + (single-referent `goal − Σchanges`) is the nearest extension of GB-3b.1 and the first build; + cv-0021 (multi-referent give-away to a remainder) is two layers harder — separate, do not bundle. + Goal-recognition is a new `wrong=0` surface (must refuse on ambiguous goal-language), and beware + cv-0005 passing for the wrong reason (`10−3−4=3` also falls out of treating the goal as a start); + the gate must consume the goal *as a goal*, and the real test is the sealed set, not cv-0005. + Detailed first-build scope: **§10**. +2. **R1 next (cv-0001) — Stage A (extraction).** Add currency-literal (`$N`) extraction to the + derivation reader, then test whether the comparative-multiplicative production (multiplier × + base) fires and builds `4×16=64`. Extraction-first; different stage from R4, so it exercises a + different pipeline leg. +3. **Then Stage C shapes (cv-0002/0004/0006/0022)** — the genuine wall: building the correct + grouping/op-order. Highest risk, do last, with the most instrumentation. Investigation task: + `docs/handoff/stage-c-composition-investigation-2026-06-03.md`. + +## 5. The promotion gate (generalize `product_bridge`, do not relax disagreement) + +Every new production needs a co-designed structural gate, modeled on `product_bridge` but real: + +- Use `extract_target` + `target_units` to prove the built chain answers *the asked question in + the asked units* (op-class + target + unit agreement), replacing the two-token whitelist with a + general op-class/target proof. +- A chain may commit only if it is the unique reading that *structurally* certifies; otherwise + refuse. **Disagreement is not the defense** — *cv-0016/0016* shows a lone wrong chain commits + with no rival to disagree. The gate, not the pool, is the `wrong=0` firewall for committed + compositions. + +## 6. Acceptance gates (inherit ADR-0207 §6 verbatim) + +train_sample stays `wrong=0` (6/44/0 or better); the no-reference ` times` hazard stays +refused; no partial chain commits with an unbound quantity; **progress measured on the 22-case +corpus AND the sealed 1,319** — a train_sample/corpus gain that does not move held-out does not +count; each gain lands as composer/extractor enrichment behind a gate, audited to confirm it is +**not** a new serving recognizer/injector branch (the §4 freeze). + +## 7. Honest uncertainty + +This is the research wall, not engineering. The payoff against the **sealed 1,319** is genuinely +unknown: the composer building gold on a corpus case does not mean the same production fires on +held-out paraphrases, and Stage C (correct grouping/op-order) is an open research problem, not a +known build. I can scope the work and the gates; I cannot promise R1/R4 transfer until the +productions exist and the sealed number actually moves. The gates (§6) are what keep that honest +— they will tell us the truth either way. + +## 8. Correction recorded + +I earlier asserted "extraction is substantially done; only EX-3 deferred; extraction is not the +open lever." Stage A (cv-0001: `$16` present in text, not extracted) shows that was overstated — +the ADR-0179 lever was largely shipped *for its four cases*, but per-shape extraction gaps remain +(currency literals at minimum). This does not unwind ADR-0207; the per-shape gaps are execution +detail and live here, not in the ratification ADR. + +## 9. Reproduction-methodology correction + +The `target-agg` column was first computed by passing the **full problem text** to +`extract_target`; serving passes only the **question clause**. For cv-0004 and cv-0006 the +aggregation word is in the body, not the question, so full-text wrongly read `combined`/`total` +where the serving-faithful call returns `None` (now corrected above). The other agg cells are +unaffected (their agg word is in the question). This changes no stage (both are Stage C) and no +claim. Methodology fix carried forward: reproduce serving behaviour with serving's inputs — +`extract_target` gets the question clause, the composers get the full problem. + +## 10. R4 first-build scope (from code-read of `accumulate.py`) + +R4 is **new production, not a target tweak** — confirmed by reading the source (not a trace): +`compose_accumulation` / `_build_accumulation` (GB-3b.1) computes single-referent gain/loss +*running-total* `start ± changes` and consults **no goal/target/residual concept**. Hard bails: +the anchor must establish exactly one quantity (`accumulate.py:70`); a new named actor refuses +(`continues_anchor_referent`, `:76`/`:143`); no unambiguous licensed change cue refuses +(`:87`/`:149`). So R4's `goal − accumulated` cannot be expressed regardless of target — both R4 +cases build **0 candidates** at `d9fc7f9e` (latent, nothing passes for any reason yet). + +- **cv-0005 first (single-referent, nearest extension of GB-3b.1).** A new production recognizing + (a) a **goal** quantity as a distinct anchor type (*not* a running total), (b) accumulated + same-referent changes, (c) a **residual** question target, computing `goal − Σchanges`. Single + referent (Michael), so it reuses GB-3b.1's referent/cue guards. +- **cv-0021 second (harder).** Multi-referent give-away to a remainder — + `(start − desired_remainder) − Σgiven`. Outside GB-3b.1's single-referent scope (refused at + `continues_anchor_referent`); needs multi-referent accumulation **and** residual handling. Two + layers beyond cv-0005; do not bundle. +- **Gate (mandatory, co-designed).** The residual chain commits only if `extract_target` + structurally proves the residual question + op-class + unit agreement, and completeness consumes + the **goal** quantity. Never disagreement alone (the 0016 firewall). +- **`wrong=0` hazard (latent, build-time guard).** `10 − 3 − 4 = 3` also falls out of + *mis-anchoring* the goal as a running-total start — coincidental correctness. The production must + consume the goal *as a goal*; the real test is the **sealed set**, not cv-0005's arithmetic. +- **Build-time discipline.** Whoever builds instruments the exact `_build_accumulation` interaction + and the new production's path through `self_verifies` (completeness must require the goal + consumed) **in-tree** — the code-read scopes *what* to build; the runtime path confirms *that it + fires* before the one-line wire. diff --git a/docs/analysis/wiring-promotion-gate-brief-2026-06-03.md b/docs/analysis/wiring-promotion-gate-brief-2026-06-03.md new file mode 100644 index 00000000..a7ae8a8c --- /dev/null +++ b/docs/analysis/wiring-promotion-gate-brief-2026-06-03.md @@ -0,0 +1,166 @@ + + +# WIRING + Promotion-Gate Brief — feeding the derivation composer into serving + +**Status:** Analysis only. No serving, eval, or code edits. Every claim reproduced +read-only against `origin/main` @ `2cb0922` (corpus + branch state per PR +[core#536](https://github.com/AssetOverflow/core/pull/536)). + +**Scope.** ADR-0207 §5 step 1 (WIRING) is the named next lever: connect the disjoint +`generate/derivation/` composer to the serving candidate-graph so its output counts +toward 6/44/0. This brief reads the actual integration surface — `product_bridge.py`, +`pool.py`, `verify.py`, `target.py`, the `math_candidate_graph.py:530` boundary — and +defines what the wiring *and its promotion gate* must be. It also reports an empirical +finding that **partly corrects ADR-0207 §5's sequencing claim**; see §5. + +--- + +## 1. Bottom line + +"The wiring is trivial, the gate is the work" is correct — but incomplete, and the +honest version is sharper: + +1. **The general composition entry already exists** — it is `resolve_pooled(text)`, not a + thing to build. (The brief's earlier "there is no `resolve_composition`" was wrong.) +2. **The general self-verify gate already exists and is composition-agnostic** + (`select_self_verified`: grounding ∧ cue ∧ unit ∧ completeness ∧ uniqueness). +3. **`product_bridge` is already the promotion gate for one shape (pure products) and is + already wired** at `math_candidate_graph.py:530`. The wiring lever, for what the + composer can safely certify *today*, is **already done**. +4. **The composer refuses every R1/R4/R5/R6 target in the validation corpus** (§3). So + wiring `resolve_pooled` yields **zero lift** on the target shapes — there is nothing + correct yet to promote. +5. **Wiring `resolve_pooled` *wholesale* is a live `wrong=0` regression** — it commits + `0016 → 510` (gold 2) (§3). The promotion gate is mandatory from the first wire. + +**Therefore:** WIRING and COMPOSITION (§5 steps 1–2) are **not separable**, and WIRING is +**not the lowest-risk first step** as ADR-0207 §5 states. The safe wire already exists +(`product_bridge`); extending it to a new shape requires the composer to *build that +shape's chain* (it currently refuses) **and** a promotion gate to *certify it*, in +lockstep. The gate and the composition capability are the same problem (§6). + +## 2. The verified integration surface + +| Component | What it is | Serving-wired? | +|---|---|---| +| `math_candidate_graph.py:524–540` | The ADR-0195 boundary: `r = resolve_promotable_product(text); if r is not None: return CandidateGraphResult(answer=r.answer, branches_enumerated=1, branches_admissible=1)` | **yes** (the one tendril) | +| `derivation.pool.resolve_pooled(text) → Resolution \| None` | General composition resolver: pools accumulation + multiplicative + chain candidates, classifies each `complete`/`exempt`/`None`, refuses on disagreement or exempt-only, guards `asks_prior_state` | no (sealed) | +| `derivation.verify.select_self_verified(derivs, text, target_units=…)` | Composition-agnostic gate: grounding ∧ cue ∧ unit ∧ completeness, then uniqueness/disagreement; `target_units` drops chains answering the wrong dimension | no (sealed) | +| `derivation.verify.classify_derivation` | ADR-0182 commit-eligibility: `complete` (resolves) / `exempt` (pool-only, forces disagreement) / `None` (fails a clause) | no | +| `derivation.target.extract_target(question, known_units) → Target` | Question-target extraction (a general analogue of product_bridge's hardcoded target check) | no | +| `product_bridge.resolve_promotable_product` | The promotion gate for **one shape** (pure products) — see §4 | **yes** | + +**Wiring shape (mechanically trivial, confirmed).** A second block at the same `:530` +boundary: `c = resolve_promotable_composition(text); if c is not None: return +CandidateGraphResult(answer=c.answer, branches_enumerated=1, branches_admissible=1)`. +The work is entirely inside `resolve_promotable_composition` — the gate. + +## 3. The empirical crux (live `resolve_pooled`, all corpus positives) + +Ran `resolve_pooled` on the validation corpus's composition positives + diagnostics: + +| Cases | Composition | `resolve_pooled` result | +|---|---|---| +| 0029, 0038, 0008, 0027 | R1 | **refuse** (×4) | +| 0037, 0035 | R4 | **refuse** (×2) | +| 0030, 0015 | R5 | **refuse** (×2) | +| 0005, 0046 | R6 | **refuse** (×2) | +| 0033 | downstream | refuse | +| 0024 | extraction (EX-3) | refuse | +| 0040 | world-knowledge | refuse | +| **0016** | hazard-both | **COMMIT 510 — WRONG (gold 2)** | + +Two facts fall out, both load-bearing: + +- **Zero lift from wiring.** The pool commits *nothing correct* on the 10 R1/R4/R5/R6 + positives — it refuses all of them. The composers cannot yet assemble a committable + complete-unique chain for these shapes. Wiring the pool moves 6/44/0 by **+0 correct**. +- **A live wrong commit.** `0016` is a unique complete self-verifying reading that is + *wrong* (the chain `… → 510`, no rival to trigger the disagreement rule). This is + exactly the "known wrong commits" `product_bridge`'s docstring warns of. Wiring the pool + *ungated* makes serving **6/43/1** — a `wrong=0` violation. `product_bridge`'s + `_has_hazard_surface` blocks `0016` today via its `{less, more, per, …}` cues. + +## 4. What `product_bridge` actually proves (the gate to generalize) + +`resolve_promotable_product` is a **four-layer** promotion gate over `resolve_pooled`: + +1. `_has_hazard_surface` — a refuse-preferring **blocklist**: comma-thousands, `%`/percent, + text blockers `{left, more, less, gave, spent, profit, remaining, …}`, question + blockers `{per, after, before, remaining, profit, …}`. (This is what stops `0016`.) +2. `resolve_pooled` — the pooled candidate + disagreement rule. +3. `_is_complete_pure_product` — every step `multiply`, non-comparative, `classify == "complete"`. +4. `_has_product_target` — a **near-whitelist of two target shapes**: `money … make/earn`, + or `weight … total/move` with a mass unit. + +**The tell:** layer 4 is almost hardcoded to 0003 (revenue) and 0021 (weight). Its safety +comes from its narrowness — it admits essentially two target forms. **This does not +generalize.** A composition gate for R4/R5/R6 cannot copy a two-entry target whitelist; it +needs a *general* op-class/target proof (the natural tool is `extract_target` + +`select_self_verified(target_units=…)`), and that proof is the hard part. + +## 5. Correction to ADR-0207 §5 (flagged, not buried) + +ADR-0207 §5 step 1 calls WIRING "the crux … the lowest-risk of the execution steps … it's +wiring, with `product_bridge` already proving the pattern … the central task, not a +preliminary." The verified surface refines this: + +- **The safe wire is already done** (`product_bridge` at :530). What remains to wire is, by + shape, gated on composition capability that **does not exist yet** (the pool refuses every + R4/R5/R6 target). +- **WIRING is not lower-risk than COMPOSITION** — they are the same step. The risk lives in + the promotion gate, which is where "which composed readings are safe to promote" = "which + readings the composer got right" = the §5 step-2 composition wall. +- **The ungated pool is `wrong=0`-negative** (0016), so "just wire it in" is not a safe + preliminary. + +**This does not unwind the ratification.** ADR-0207's core — freeze the regex serving path, +design-of-record, the `wrong=0` gates, measure on the sealed set — all stand. The +correction is to §5's *sequencing optimism*. Recommended: amend §5 step 1 to "extend the +`product_bridge` promotion-gate pattern to one new composition shape, in lockstep with the +composer capability for it; never wire the pool ungated," or carry this brief as the §5 +execution refinement. Operator's call which. + +## 6. The promotion-gate contract (what to build, no code) + +`resolve_promotable_composition(text) → Resolution | None`, mirroring `product_bridge` but +**per chosen shape**, must prove all of: + +1. **Candidate source.** Obtain the shape's candidate (via `resolve_pooled`, or a + shape-scoped composer call) — only if the composer actually *builds* it (today: none of + R4/R5/R6, so this gate is empty until composition lands). +2. **General self-verify** (reuse, don't reinvent): `select_self_verified` — + grounding ∧ cue ∧ unit ∧ completeness ∧ uniqueness. +3. **Target proof** (generalize layer 4): the question's target op-class matches the + chain's, via `extract_target` + `target_units` — not a per-shape whitelist. +4. **Hazard firewall** (generalize layer 1): the residual `wrong=0` hazards that survive + self-verify (the `0016`-class: a unique complete reading that is still wrong) must be + refused. The `0016 → 510` commit is the **mandatory first firewall test** — the gate is + not done until `resolve_promotable_composition` refuses it. + +**`wrong=0` boundary contract:** every corpus case + every sealed case either **refuses or +returns exactly gold**. Proven on the 22-case `composition_validation/v1` corpus (the +instrument) **and** the sealed 1,319 (the real bar, ADR-0207 §6). A train_sample/corpus +gain that does not move the sealed set is overfitting and does not count. + +## 7. Recommended first slice + open questions + +- **First slice:** pick the *one* shape whose composer is closest to building a correct + committable chain (candidate: R4 accumulation/residual — `accumulation_candidates` already + exists and `compose_accumulation` is wired into the pool). Confirm whether the composer + can build `0037`/`0035` at all (today: pool refuses both — so step 0 is *composer* work, + not gate work). Only once a correct chain exists does the gate become the lever. +- **Open Q1:** *why* does the pool refuse the R4/R5/R6 positives — is it a missing composer + production (no chain built) or a gate over-refusal (chain built but fails completeness/ + uniqueness)? This split decides whether step 1 is composer or gate work, and it needs a + per-case `pooled_candidates` + `classify_derivation` trace read (the next brief). +- **Open Q2:** can `extract_target` express the R4/R5/R6 target op-classes (residual, + duration-sum, percent-of) precisely enough to replace product_bridge's whitelist without + admitting a `0016`-class wrong? This is the generalization risk. +- **Open Q3:** does any composer *currently* produce a unique-complete wrong on a sealed + case (not just 0016)? The hazard firewall must be characterized on the sealed set, not + only the corpus, before any pool output is wired. + +**Invariants observed by this brief:** read-only; `train_sample` 6/44/0 reproduced live; +no serving code touched; the no-ref ` times` hazard and 0016 remain refused on the +serving path (product_bridge blocks 0016). diff --git a/docs/handoff/stage-c-composition-investigation-2026-06-03.md b/docs/handoff/stage-c-composition-investigation-2026-06-03.md new file mode 100644 index 00000000..5cc83c14 --- /dev/null +++ b/docs/handoff/stage-c-composition-investigation-2026-06-03.md @@ -0,0 +1,69 @@ + + +# Stage-C Composition Investigation — dispatch task (execution lane) + +**Type:** Read-only, in-tree investigation. **No code changes.** Output is a per-case fix-spec. +**Dispatch:** execution lane (this is the fine-grained runtime tracing the spec-and-review lane +deliberately does *not* do from a sandbox — it must run the real code paths in-tree). +**Input:** [composition-wall-execution-plan-2026-06-03.md](../analysis/composition-wall-execution-plan-2026-06-03.md). +**Base:** current `origin/main` (`git fetch && git reset --hard origin/main` first — the tree +moves constantly; verify the SHA you run against and record it). + +## Why this is an execution-lane task, not a sandbox one + +The execution plan's stage taxonomy is a verified **symptom-map** (what's blocked, by candidate +count). It is **not** a fix-spec. Pinning *why* a Stage-C production builds the wrong chain needs +instrumenting the real production internals — the kind of fine-grained trace that has been +unreliable from the spec lane's sandbox. Run the actual functions, in-tree, faithfully. + +## The targets (Stage C — production-wrong) + +The composer builds chains but only **wrong** ones (none equals gold); the disagreement rule then +correctly refuses. Five cases, from the plan's §2 table: + +| case | comp | gold | acc/mul/chn | what it builds instead (plan) | +|---|---|---|---|---| +| cv-0002 | R1 | 400 | 0/0/4 | wrong chains only | +| cv-0004 | R1 | 3840 | 0/1/4 | wrong chains only | +| cv-0006 | R5 | 14 | 3/0/4 | wrong (e.g. accumulation + chain rivals) | +| cv-0022 | R5 | 38 | 0/1/4 | (plan: builds 80/160/18/36, none = 38) | +| cv-0018 | compare_mult | 28 | 0/0/2 | wrong chains only | + +## What to produce, per case + +For each of the five, using the **serving-faithful inputs** (`extract_target` gets the *question +clause*; the composers get the *full problem* — the §9 methodology fix): + +1. **Enumerate every candidate** each composer builds (`accumulation_candidates`, + `multiplicative_candidates`, `candidate_chains`): the exact step list (op, operand, unit) and + answer of each, not just the count. +2. **Locate the gold chain.** Is the correct grouping/op-order *expressible* by the current + composer primitives at all? If a sequence of existing ops yields gold, the gap is **search/ + ranking** (the production can build it but doesn't, or builds it and a wrong rival outvotes it). + If no sequence of existing ops yields gold, the gap is a **missing primitive/production**. +3. **Pin the divergence.** Where does the built (wrong) chain diverge from the gold reading — wrong + clause segmentation, wrong referent binding, wrong op for a relational cue, wrong grouping order? + Name the exact function and the exact decision (cite `file:line`). +4. **Minimal production fix.** State the smallest change that would make the gold chain *buildable + and uniquely certifiable*, and the **co-designed structural gate** that admits it without + admitting the wrong rivals (per plan §5 — `extract_target` + `target_units`, never disagreement + alone). + +## Hard constraints (non-negotiable — from ADR-0207 §6 / plan §6) + +- **Read-only.** No edits to `generate/` in this task. The output is a spec; building is a later, + separately-gated task. +- **`wrong=0` is the governor.** Any proposed fix must be argued to preserve: train_sample + `wrong=0` (6/44/0+), the no-reference ` times` refusal, and the 0016 firewall (a lone wrong + chain with no rival must still refuse — the gate, not disagreement, is the defense). +- **Sealed set is the real bar.** Note explicitly that building gold on a corpus case proves + nothing about transfer; the fix-spec must say what would be measured on the sealed 1,319. +- **Serving-faithful reproduction.** `extract_target(question_clause)`; composers get full text. + Record the `origin/main` SHA you ran against. + +## Output + +A markdown report, one section per case, with the four items above, ending in a ranked list: +which Stage-C case has the **smallest buildable gap** (search/ranking) vs which needs a **new +primitive** — so the build lane starts with the cheapest real lift. This report becomes the +fix-spec; it does not authorize a build.