* docs: consolidate governance anchors and clean up test registries * refactor(cli): decompose cli into dedicated modules * test: fix broken test baselines and formatting * docs: add domain boundary READMEs for governance anchors * test: update baseline for determination lane * test: fix capability_pass expectation * test: fix CORE_SHOWCASE_SKIP_BUDGET enforcement * chore: cleanup CLI extraction and unreachable code
12 KiB
ADR-0119 — GSM8K Eval Lane Roadmap (Phase 5)
Status: Proposed (roadmap-only) Date: 2026-05-22 Author: CORE agents + reviewers Type: Umbrella ADR; decomposes Phase 5 of ADR-0114 into sub-phases Depends on: ADR-0114, ADR-0114a, ADR-0115, ADR-0116, ADR-0117, ADR-0118
Context
ADR-0114 §Phase 5 designated the GSM8K eval lane as Phase 5 of the expert-capability arc, with a single line of scope:
"Phase 5 — GSM8K Eval Lane (ADR-0119, future). Author evals/gsm8k/: dev / public / holdouts; runner.py; contract.md. Exit criterion: lane runner produces deterministic results. Honest first number reported."
In practice this is a multi-week chunk that integrates:
- the parser / solver / verifier / realizer pipeline that Phases 1–4 shipped on main (ADR-0115/0116/0117/0118)
- the anti-overfitting obligations from ADR-0114a that are GSM8K-specific (#1 sealed-holdout enforcement, #6 depth-curve measurement, #7 frontier-baseline comparison, #8 adversarial generation)
- a CORE-original dev / public corpus (kept disjoint from actual GSM8K to preserve test-set integrity)
- the eventual sealed encryption of the real GSM8K test set as the holdout split
ADR-0119 is the roadmap that decomposes Phase 5 into sub-phases the same way ADR-0114 decomposed Phases 1–7. This document does not ship code. Each sub-phase ships under its own ADR and PR.
Decision: Phase 5 decomposition
ADR-0119 is the umbrella. Seven sub-phases below; each carries its own ADR id and discharge target. The sub-phases land in priority order but most can run in parallel.
Phase 5.1 — Sealed-holdout encryption for one lane (ADR-0119.1)
Goal: Convert one lane's holdout from the ADR-0105 dev-mode plaintext fallback to a proper age-encrypted seal. Establishes the key-management and runner-decryption pattern that the remaining lanes will mirror.
Lane choice: fabrication_control (smallest plaintext file,
fewest dependencies).
Discharges: ADR-0114a Obligation #1 for this one lane.
Acceptance:
evals/fabrication_control/holdouts/v1/cases.jsonl.ageexists- Plaintext fallback removed from the repo
- Age recipient public key documented in
docs/holdout_recipients.txt - Private identity path documented but NOT committed
holdout_runner._decrypt_holdoutreads the.agefile whenCORE_HOLDOUT_KEYis set; raises typed error otherwise- Test
tests/test_adr_0119_1_sealed_holdout.pypins: (a).agefile exists and is age-formatted (b) decryption with known identity reproduces plaintext byte-equal (c) missingCORE_HOLDOUT_KEYraises typed refusal
Status: Delegated (Gemini-style brief).
Phase 5.2 — CORE-original GSM8K-style corpus (ADR-0119.2)
Goal: Author 200 grade-school math problems for the lane's dev / public splits. NOT drawn from actual GSM8K — the real GSM8K test set is reserved for the sealed holdout (Phase 5.7). The dev / public splits are CORE-original work in the same style.
Distribution: 50 dev + 150 public, depths 1–8, every operation kind exercised ≥ 30 times, 80+ multi-entity cases.
Constraints: Must stay within the parser grammar shipped by
ADR-0115. Every case must round-trip:
parse_problem → solve → answer matches expected. A verify.py
script enforces this gate; PR cannot land if any case fails.
Discharges: lane corpus prerequisite for 5.3 / 5.4 / 5.6.
Acceptance:
evals/gsm8k_math/dev/cases.jsonl(50 cases)evals/gsm8k_math/public/v1/cases.jsonl(150 cases)evals/gsm8k_math/holdouts/v1/cases.jsonl.age(empty / placeholder pending Phase 5.7 GSM8K-test seal)evals/gsm8k_math/README.md+contract.mdevals/gsm8k_math/verify.py→ 200/200 OK
Status: Delegated (Codex-style brief).
Phase 5.3 — Lane runner (ADR-0119.3)
Goal: Build evals/gsm8k_math/runner.py that drives every case
through:
parse_problem(text) → graph
solve(graph) → trace
verify(graph, trace) → verdict
realize(initial_state, trace) → prose
Per-case outcome is exactly one of:
correct— verifier passes ANDtrace.answer_valueequals the case'sexpected_answerwrong— verifier passes ANDtrace.answer_valuediffers from the case'sexpected_answerrefused—ParseErrororSolveError(typed refusal at any stage)
Critical: ADR-0114a Obligation #4 requires wrong == 0. The
lane's pass threshold is correct + refused == total AND
wrong == 0. A nonzero wrong invalidates the lane regardless of
correct rate.
Discharges: lane runtime; the substrate every other Phase 5.X gate consumes.
Acceptance:
evals/gsm8k_math/runner.pyexposesrun_lane(cases, *, config) → LaneReport- Each case in
LaneReport.case_detailscarries the trace, the realized prose, and the outcome category - Determinism: same case file → same
LaneReport.canonical_bytes() tests/test_adr_0119_3_runner.pyparametrizes over dev/public
Phase 5.4 — Frontier-baseline comparison (ADR-0119.4)
Goal: Discharge ADR-0114a Obligation #7. Pair CORE's lane score with frozen-citation frontier-LLM numbers on the same problem distribution. Citation only — no live API. Pattern mirrors ADR-0045 (long-context comparison).
Acceptance:
evals/gsm8k_math/baselines/frontier.jsoncarries:- per-vendor (Claude / GPT / Gemini) headline GSM8K scores with publication dates and URLs
- note that vendor scores are on the full GSM8K test, not on our CORE-original public split (acknowledge the apples-vs- oranges; publish anyway)
- A comparison report (
evals/gsm8k_math/baselines/comparison_v1.json) ties CORE's CORE-public-split score to the cited vendor scores with the disclaimer in place - Test pins citation freshness (no broken URL, dated within last 18 months)
Discharges: Obligation #7.
Phase 5.5 — Adversarial generation (ADR-0119.5)
Goal: Discharge ADR-0114a Obligation #8. Generate problems designed to exploit weak grammar / solver coverage. Misparse rate must be zero; refused rate may be arbitrarily high.
Approach: Programmatic generator targeting:
- edge-case phrasings within the documented parser grammar
- combined patterns the parser supports separately but never jointly
- red-herring numbers (numbers in entity names like "Person 5"; numbers in questions that don't ask about quantities)
Runs through the same runner.py from Phase 5.3 and reports the
correct / wrong / refused triple. wrong == 0 is the gate.
Acceptance:
evals/gsm8k_math/adversarial/generator.pyevals/gsm8k_math/adversarial/cases.jsonl(≥ 100 cases)tests/test_adr_0119_5_adversarial_misparse.pyassertswrong == 0across all adversarial cases
Discharges: Obligation #8.
Phase 5.6 — Depth-curve harness (ADR-0119.6)
Goal: Discharge ADR-0114a Obligation #6 measurement-side. Bucket
the lane's correct rate by reasoning depth (len(graph.operations))
and emit the depth-vs-correct curve.
Acceptance:
evals/gsm8k_math/scoring/depth_curve.pyproduces a JSON report:{ "depth_1": 1.0, "depth_2": 1.0, ..., "depth_8": 0.97 }- A documented threshold
ε(per-step error tolerance) below which accuracy at depth N must stay:accuracy(N) ≥ (1 - ε)^N. ADR-0120 picks the productionεvalue when it sets theexpertthreshold; ADR-0119.6 ships the harness, not the threshold
Discharges: measurement-half of Obligation #6.
Phase 5.7 — Sealed GSM8K test (ADR-0119.7)
Goal: Encrypt the real GSM8K test set as the holdout split.
Final piece before any expert promotion attempt under ADR-0120.
Acceptance:
evals/gsm8k_math/holdouts/v1/cases.jsonl.agecarries the real GSM8K test set, encrypted to the recipient established in 5.1- A sanity check (developed against a tiny held-out subset of GSM8K train) confirms the runner reads the sealed file and produces a lane report
- Documentation explicitly states the seal is one-way: the development team operates blind to the test contents until a release event signed-by-reviewer opens the lane
Discharges: Obligation #1 for the lane that ultimately gates ADR-0120.
Phase 5.8 — Overall lane gate (ADR-0119.8)
Goal: Compose the per-sub-phase gates into a single lane verdict. The lane "passes" when:
- 5.1 sealed holdout active for the lane
- 5.2 dev + public corpora populated AND
verify.py200/200 - 5.3 runner produces deterministic
LaneReportacross two runs - 5.4 frontier comparison report exists and is dated
- 5.5 adversarial generator's
wrong == 0 - 5.6 depth-curve report exists
- 5.7 sealed GSM8K test in place
- Public split:
correct + refused == total,wrong == 0 - Holdout split: same shape, scored only at release events
A new lane shape gsm8k_capability_shape is registered in
LANE_SHAPE_REGISTRY with the above thresholds. ADR-0119.8 ships
the shape; ADR-0120 invokes it.
ADR-0114a obligation roll-up after Phase 5
| # | Obligation | Discharge target | Status today |
|---|---|---|---|
| 1 | Sealed-holdout discipline | 5.1 (one lane) + 5.7 (GSM8K test) | substrate present; per-lane enforcement deferred |
| 2 | OOD surface variation | ADR-0118a | discharged |
| 3 | Replay-equal trace | ADR-0117 verifier | discharged |
| 4 | Typed refusal; wrong == 0 |
ADR-0116 + 5.3 + 5.5 | discharged at runtime layers; lane gate enforces |
| 5 | Reasoning-isolation perturbation suite | ADR-0125 | discharged |
| 6 | Compositional-depth curve | 5.6 (harness) + ADR-0120 (threshold) | harness pending; threshold lives in ADR-0120 |
| 7 | Frontier-baseline comparison | 5.4 | pending |
| 8 | Adversarial generation; wrong == 0 |
5.5 | pending |
| 9 | Determinism | solver + verifier + realizer | discharged |
| 10 | Operation provenance via pack | ADR-0116 | discharged |
Six of ten obligations land before Phase 5 starts. The remaining four cluster under ADR-0119.
Invariants
adr_0119_decomposes_phase_5
Phase 5 ships as eight sub-ADRs (5.1 through 5.8). Adding, removing, or reordering sub-phases requires a numbered amendment to this ADR.
adr_0119_no_actual_gsm8k_in_dev_public
The dev and public splits of evals/gsm8k_math/ are CORE-original
work. The actual GSM8K test set enters the lane ONLY via the
encrypted holdout under 5.7. A pre-PR check in 5.2's verify.py
flags any case whose problem text matches a known GSM8K entry
(via fingerprint comparison against a hashed manifest of GSM8K
prompts; the manifest itself does not contain the GSM8K texts
verbatim).
adr_0119_wrong_count_is_load_bearing
For any sub-phase that runs cases through the runner (5.3, 5.5),
the lane's per-split wrong count must be reported with the same
prominence as correct. ADR-0114a Obligation #4 requires
wrong == 0; a sub-phase with wrong > 0 invalidates that sub-
phase regardless of correct rate.
Acceptance evidence (for this roadmap ADR)
ADR-0119 is accepted when:
- The ADR file exists in
docs/adr/and is linked fromdocs/adr/README.md(index + frontier) - No code lands with this ADR; it's pure roadmap
- README cross-references update to mention Phase 5 sub-phasing
Each sub-phase is accepted independently under its own ADR.
Consequences
- The Phase 5 work now has explicit decomposition. Each sub-phase has clear scope, clear acceptance, clear obligation-discharge target.
- Parallel work is enabled: 5.1 (Gemini), 5.2 (Codex), 5.3 (me) can run concurrently without conflict.
- ADR-0120 (first
expertpromotion contract) cannot land until all sub-phases of 5.1 through 5.8 have landed. The roadmap makes that dependency explicit. - ADR-0114a Obligation #6's threshold (
ε) lives in ADR-0120, not here. ADR-0119.6 ships the measurement harness only.
Out of scope
- Specific numeric thresholds for the
gsm8k_capability_shapelane gate. Those belong to ADR-0120. - A second capability domain after GSM8K. ADR-0114 §Phase 7 proposes symbolic logic; that's ADR-0121+.
- Multi-vendor adversarial cross-runs (CORE adversarial cases ⊗ frontier LLMs). Out of scope for Phase 5 first cut; potential Phase 5.X future amendment.
- Renaming
evals/gsm8k_math/to something else if the corpus expands beyond grade-school math. Future amendment.