Commit graph

3 commits

Author SHA1 Message Date
Shay
de6df1edc9
feat(adr-0163-f): scale sealed practice case set to 150 additive cases (#459)
Adds `evals/gsm8k_math/practice/v1/cases.jsonl` — 150 GSM8K-style word
problems covering only additive/subtractive operations.  All cases carry
`<<a+b=c>>` / `<<a-b=c>>` annotations; none contain `*` or `/`, so every
case classifies as `"additive"` under `classify_operation`.

Four difficulty bands:
  0001–0030  single add (14 distinct units, 15 entity names)
  0031–0060  single subtract
  0061–0090  two same-direction operations
  0091–0150  mixed add+subtract and multi-step (2–4 steps)

IDs are `gsm8k-practice-v1-NNNN`, deterministically ordered.
`train_sample/v1/cases.jsonl` and its pinned SHA are untouched.
`build_search_report` continues to run unchanged.

Adds `_PRACTICE_CASES_PATH` constant and `_load_practice_cases()` /
`build_practice_report()` to `practice/v1/runner.py` as additive
symbols; `build_report()` and all existing imports are preserved.

New practice case count: 150.
2026-05-29 10:02:00 -07:00
Shay
872ed3b52d feat(adr-0175-phase3b): bounded multiplicative search in the sealed practice lane
ADR-0175 Phase 3b — the first live attempt generator. Runs only in the sealed
practice lane, only on cases the engine refused; every proposal is gated by the
Phase 3a self-verification gate.

generate/derivation/:
- extract.py: extract_quantities() — lexeme-level (number + unit word; ADR-0165).
- search.py: search_multiplicative() — one in-clause product candidate per
  sentence with >=2 quantities + a present multiplicative cue; gated by
  select_self_verified. Per-sentence scope + multi-candidate disagreement give
  the uniqueness gate real teeth (two qualifying sentences -> refuse). The cue
  set {each,every,for,per,times} is an explicit PROVISIONAL hypothesis the
  practice loop refines, not a claimed-correct grammar.
evals/gsm8k_math/practice/v1/search_runner.py: search_augmented_scorer +
  build_search_report — base scorer, then a practice-only attempt on refusals.

MEASUREMENT (the deliverable, per the breadth-of-impact test):
  practice with search:  correct=4  wrong=9  refused=37   (baseline 3/0/47)
- Flips +1 (0021, the clean in-clause aggregate) and its renumbered/reworded
  variants (ADR-0114a perturbation guard) -> a real capability, not memorisation.
- 9 wrong attempts -> elimination records (§9), the learning signal. The naive
  full-product cue model over-attempts; the eliminations are exactly the signal
  that refines it.

HONEST FINDING: self-verification (grounding ∧ cue ∧ unit ∧ uniqueness) is
NECESSARY but NOT SUFFICIENT — 9/13 self-verified attempts were wrong vs gold.
The gap is cue PRECISION / which-quantities-compose (the knowledge axis), not
'can we multiply' (skill). This is why the search runs sealed: gold catches the
9, and case 0050 (canary) attempted-and-failed IN PRACTICE without touching
serving -> validates the seal.

Invariants: #1 seal (serving still 3/47/0; 0050 refuses in serving; no
generate/chat import of the lane), #3 determinism. Serving wrong=0 untouched.

Verified: 3a+3b 31/31; ruff clean; serving lane 4/4; smoke 67/67.
2026-05-28 15:29:08 -07:00
Shay
d90887b80f feat(adr-0175-phase2): sealed practice lane over GSM8K train
ADR-0175 Phase 2 — a NEW lane (evals/gsm8k_math/practice/v1/), separate from the
wrong=0-pinned serving runner which is NOT modified. Runs the 50 cases in
practice mode: scores correct/wrong/refused as practice metrics, feeds per-class
counts into the Phase 1 ledger, diagnoses every refusal (§8), emits an
elimination record per wrong.

- classify_operation: gold-derived primary op class {multiplicative,divisive,
  additive} from <<a*b=c>> calc annotations (Tier-1 checkable in practice).
- diagnose_refusal (§8): skill_gap / knowledge_gap / genuine_ambiguity router.
- EliminationRecord (§9): wrong attempt gold caught -> pruning signal.
- PracticeReport: counts + per-class ledger + diagnoses + eliminations; as_dict.
- run_practice(cases, scorer=...): injectable scorer for tests; defaults to the
  candidate-graph scorer (read-only — never alters serving).

Live result mirrors serving (3 correct / 0 wrong / 47 refused of 50) because the
engine still refuses rather than guesses — attempts/eliminations go live in
Phase 3. But the diagnosis is already actionable: 35 skill_gap / 12 knowledge_gap
/ 0 genuine_ambiguity — 74% of refusals are skill gaps (Phase 3's search target),
quantifying the skill-vs-knowledge split.

Invariants: #1 seal (serving still 3/47/0; no generate/chat import of the lane),
#3 determinism (report byte-identical across runs). Elimination + wrong-tolerance
paths unit-tested via injected scorer (no live wrongs yet).

Verified: Phase 1+2 53/53, serving train_sample tests 4/4 (seal), smoke 67/67,
ruff clean.
2026-05-28 15:12:33 -07:00