# v18 residue patterns — что осталось после 86.5% EA > Written 2026-05-19 night. Audit of the 27 fails in > `eval/reports/2026-05-18b/v18-gpt52-pro-merged.json` (n=200 BIRD original gold, > v18 = 173/200 = 86.5% EA). > > Цель: найти overlap-паттерны для prompt patch v19 + честная оценка > headroom + risk assessment regression'ов. ## Spread | Метрика | Значение | |---|---| | Total fails | 27 | | simple | 5 | | moderate | 16 | | challenging | 6 | | DBs covered | 11 (max 6 в thrombosis_prediction, 4 в formula_1) | ## Pattern classification (per-qid) | qid | diff | db | pattern | gold-arguably-wrong? | |---:|:---:|---|---|:---:| | 25 | mod | california_schools | C: WHERE-source (`District Name LIKE 'Riverside%'` vs `City='Riverside'`) | no | | 37 | mod | california_schools | C: ORDER BY scope (outer vs subquery; tied values) | no | | 125 | cha | financial | D: extra-table JOIN (pred adds spurious `client` → row explosion 45→5817) | no | | 207 | cha | toxicology | B: JOIN-FK choice (`connected.atom_id` vs `connected.bond_id`) | partial | | 349 | mod | card_games | A: gold nested-subquery for "most" — query structure | partial (Arcwise territory) | | 408 | mod | card_games | C: missing JOIN to `rulings` (`COUNT(DISTINCT id)` через JOIN) | no — pred bug | | 484 | mod | card_games | **A1: LIMIT mis-interp** (gold no LIMIT, pred `LIMIT 1`) | no | | 584 | mod | codebase_community | C: WHERE-source (`postHistory.Comment` vs `comments.Text`) | no | | 595 | mod | codebase_community | C: GROUP BY granularity (`UserId` vs `UserId,PostId`) | no | | 694 | mod | codebase_community | C: ORDER BY column (`users.CreationDate` vs `comments.CreationDate`) | partial | | 743 | cha | superhero | C: WHERE-filter + INNER vs LEFT JOIN + percentage form | no | | 894 | mod | formula_1 | A2: column projection (gold возвращает `milliseconds`, pred — нет) | no | | 902 | sim | formula_1 | B: JOIN-table choice (`driverStandings` vs `results`) | no | | 930 | sim | formula_1 | **A1: LIMIT mis-interp** ("ranked highest" → gold returns all rank=1 races, pred `LIMIT 1`) | no | | 959 | sim | formula_1 | C: time-format LIKE filter missing (`_:%:__.___`) | no | | 1029 | mod | european_football_2 | **E: gold wrong** (gold uses `ASC` for "highest", pred uses `DESC`) | **YES** | | 1094 | cha | european_football_2 | C: aggregation form (`SUM(CASE)` vs `MAX(CASE)`) | partial | | 1144 | sim | european_football_2 | **A1: LIMIT mis-interp** (gold subquery+LIMIT 1, pred JOIN no-LIMIT → 38 rows) | no | | 1168 | cha | thrombosis_prediction | A2: column projection (gold +Birthday col) | partial (Arcwise territory) | | 1205 | mod | thrombosis_prediction | **A1: LIMIT mis-interp** (gold no LIMIT 67 lab records, pred `LIMIT 1`) | no | | 1247 | cha | thrombosis_prediction | **E: gold wrong** (op precedence: gold `OR FG≥450 AND WBC>3.5 AND ...` without parens) | **YES** | | 1251 | sim | thrombosis_prediction | F: spurious `Examination` JOIN (gold) | partial — pred natural | | 1254 | mod | thrombosis_prediction | C: bounds form (`BETWEEN` vs `>`/`<`) + date format | partial | | 1275 | mod | thrombosis_prediction | C: wrong source table (`Laboratory.CENTROMEA` vs `Examination.CENTROMEA`) | no — pred bug | | 1399 | mod | student_club | A3: query-structure ("Did X attend Y?" → gold per-row CASE, pred boolean COUNT>0) | partial | | 1404 | mod | student_club | C: GROUP BY column (`event.type` vs `expense.expense_description`) | no | | 1531 | mod | debit_card_specializing | C: aggregation form (`SUM(P/A)` vs `SUM(P)/SUM(A)`) | partial | ## Pattern families collapsed | Family | Count | Notes | |---|---:|---| | **A1 — LIMIT mis-interpretation** | 4 (484, 930, 1144, 1205) | Gold uses subquery / no-LIMIT for "highest/lowest/best" when ties exist; pred adds `LIMIT 1` | | A2 — Column projection (gold +1 col) | 2 (894, 1168) | Gold returns extra grouping col not in question | | A3 — Query structure | 1 (1399) | "Did X attend Y?" → BIRD wants per-attendance-row CASE | | **B — JOIN-path / FK / source-table choice** | 4 (207, 902, 959, 1275) | driverStandings/results, results.fastestLap, Examination/Laboratory | | **C — WHERE/filter/GROUP-BY semantics** | 11 (25, 37, 125, 408, 584, 595, 694, 743, 1094, 1254, 1404, 1531) | Heterogeneous — каждый case уникален | | D — Extra-table JOIN expansion | 1 (125) | Spurious `client` → 5817 rows | | **E — Gold itself wrong (Arcwise catch territory)** | 2 (1029, 1247) | Confirmed Arcwise-style: ASC-for-highest, op-precedence bug | | F — Spurious JOIN in gold | 1 (1251) | Examination INNER drops valid patients | ## Realistic v19 prompt-patch headroom ### Patch P1 — LIMIT discipline (A1 family, 4 cases) — **CLOSED 2026-05-19 night: NEGATIVE** **Experiment** (config C codestral baseline, n=200, seed 0): | Run | simple | moderate | challenging | overall | |---|---:|---:|---:|---:| | P2+P3 only (baseline) | 71.6% | 50.5% | 41.2% | **56.0% (112/200)** | | P1+P2+P3 | 68.7% | 50.5% | 41.2% | **55.0% (110/200)** | | Delta | **−2.9pp** | 0 | 0 | **−1.0pp (−2 cases)** | Per-qid: - P1 wins (was FAIL, now PASS): 6 cases (118, 168, 327, 909, 1340, 1390) - P1 regressions (was PASS, now FAIL): 8 cases (98, 99, 189, 707, 865, 1281, 1500, 1528) - **Target qids (484, 930, 1144, 1205): 0/4 rescued** — все остались FAIL обоих runs. **Verdict:** P1 net-regressive at codestral baseline layer. The intended 4 targets (LIMIT mis-interp on v18 voting-survived residue) are **deep hard cases** the prompt patch alone cannot flip. Meanwhile the patch causes scattered regressions on simple-tier cases that previously chose correct `LIMIT 1`. P1 **reverted** from working tree. Не возвращаться без orthogonal mechanism (e.g., row-count-aware repair pass that catches tied-rows truncation). **Orthogonal mechanism attempt CLOSED 2026-05-19 night: NEGATIVE.** Codex implemented `row_count_repair` node (AST-level LIMIT 1 detection + tie-prone question regex + re-execute without LIMIT + column-shape acceptance). Tests 4/4 pass, gate green. Empirical n=200 config C codestral: P2+P3 baseline 56.0% → +rcrepair 55.5% (**−1 case, qid 1157 regression, 0 rescues**). Of 23 cases eligible (LIMIT 1 + tie-prone + pred_row_count=1), zero actually got repaired in the final state — pred_sql unchanged. Likely state-update propagation issue in langgraph wiring or run-to-run variance in codestral generation. Reverted. Artefacts: `eval/reports/2026-05-19/C_dense_cards-rcrepair.json`. **Vendor: the 4 target qids (484, 930, 1144, 1205) are truly hard.** Neither prompt patch nor execute-feedback heuristic at codestral baseline layer flips them. They sit in v18 86.5% residue precisely because the full voting stack (gpt-5.2 Pro, sonnet-thinking, grok, kimi) also couldn't rescue. Past 86.5% won't come from baseline-layer tooling — only from new voting-layer additions (cooldown-gated) or paid escalation. ### Patch P4 — CSC merge-revision (arXiv:2505.13271) — **CLOSED 2026-05-19 morning: NULL** Two independent research sources (r1.md, r2.md в корне репо) сошлись на CSC-SQL merge-revision как самом сильном free-tier lever (+2-4pp за счёт top-2 cluster judge между disagreeing самплов). Реализовал поверх `eval/self_consistency.py` (новая функция `vote_with_csc_merge` + prompt-шаблон) + флаг `--enable-csc-merge` в `scripts/eval_baseline.py`. **Experiment** (config F = codestral self-consistency × 4 temperatures [0.2,0.4,0.6,0.8], n=200, seed 0): | Run | simple | moderate | challenging | overall | wall | |---|---:|---:|---:|---:|---:| | F baseline (plain vote) | 71.6% | 56.6% | 47.1% | **60.0% (120/200)** | 29.5 min | | F + CSC merge-revision | 71.6% | 56.6% | 47.1% | **60.0% (120/200)** | 2.6 min (cache) | | Delta | 0 | 0 | 0 | **+0 cases (+0.00pp)** | — | Per-qid: 0 wins, 0 regressions. CSC merge-revision triggered on **6/200 = 3% cases** (qid 159, 407, 414, 1037, 1205, 1531 — pred_sql changed). None of the 6 flipped the match flag: на 5 случаях both candidates были одинаково wrong vs gold; на qid 414 both — semantically equivalent SQL, both PASS. **Target qids:** 484, 930, 1144 — top-1 cluster unanimous (codestral 4 temps все согласны на wrong LIMIT 1 SQL), CSC даже не fire'нул. qid 1205 — fired, но альтернативный candidate тоже неправ. **Verdict:** CSC null on this setup. Why: 1. **Codestral self-consistency homogeneous** — 4 temperatures sample from one model with same biases → 97% questions имеют top-1 strictly majority (>50%) → CSC threshold не пробивается. 2. **Judge LLM = generator LLM** — даже когда candidates disagree, codestral как judge не имеет independent ground truth (same training, same blind spots). 3. **Hard targets unanimous** — все 4 temps выдают одну и ту же неправильную SQL для LIMIT-mis-interp cases. **Когда CSC мог бы помочь:** N-rep (different schema representations per candidate) + diverse base models (codestral + Qwen + OmniSQL). На single-model homogeneous self-consistency lift = 0. Implementation reverted. Artefacts: `eval/reports/2026-05-19/F_self_consistency-{F_baseline_v2,F_csc_v2}.json`. Artefacts: `eval/reports/2026-05-19/C_dense_cards-p23_baseline.json`, `C_dense_cards-p1p23.json`. ### Patch P1 ORIGINAL proposal (для истории) **Proposed addition to system prompt:** > При вопросах формата "highest/lowest/best/most X" или "the player/card/team with the most/least Y": > если результат может содержать ties (несколько строк с одинаковым экстремальным значением), > верни все tied rows — используй subquery `WHERE col = (SELECT MAX(col) FROM ...)` либо > `ORDER BY col DESC` без `LIMIT 1`. Добавляй `LIMIT 1` **только** когда вопрос явно > требует одну запись ("the single", "the top one", "first" с явным указанием на одну). **Expected:** +2-4 cases on residue (484, 930, 1144, 1205 — all 4 are LIMIT-discipline). **Risk:** regression on legit `LIMIT 1` cases (e.g., qid 37 already removes LIMIT 1 правильно через subquery — но какой-то simple "the school with the lowest score" case в текущем passing-set может ослабнуть). Нужно прогнать на full n=200 чтобы померить regression cost. ### Patch P2 — driverStandings vs results disambiguation (B family, 1 case) **Proposed schema-doc addition (db_id=formula_1):** > `driverStandings.position` = season standings rank (per race snapshot of overall standings). > `results.position` / `results.positionOrder` = race finish position (per race). > "track number" / "in track number less than 20" → `driverStandings.position` (standings rank). > "finished in position N" / "Nth place in the race" → `results.position`. **Expected:** +1 case (902). **Risk:** low — schema clarification, не behavioral nudge. ### Patch P3 — postHistory vs comments disambiguation (C/B family, 1 case) **Proposed schema-doc addition (db_id=codebase_community):** > `postHistory.Comment` = the edit comment left by an editor. > `comments.Text` = a reader's comment on the post. > "comments left by users who edited" → `postHistory.Comment` (the edit message). > "comments to the post" / "comments under" → `comments.Text`. **Expected:** +1 case (584). **Risk:** low. ### Combined ceiling | Scenario | Best case | Worst case (regression) | |---|---:|---:| | P1 only | +4 cases (+2.0pp) | +0 cases (if regression equals gain) | | P2 + P3 only | +2 cases (+1.0pp) | +2 cases (low regression risk) | | P1+P2+P3 | +6 cases (+3.0pp) | +2 cases (P1 regression cancels) | **Headline target:** v19 = 87.5-89.5% EA (175-179/200), if P1 has zero regression. **Realistic:** v19 = 87.0-87.5% EA (174-175/200), expecting some P1 regression. ## What can't be patched cheaply - **Family A2/A3 (column projection, query structure)** — gold's choices for which columns to project or whether to return per-row vs aggregate are not derivable from question text alone. Would need example-driven few-shot patches per pattern. Marginal cost. - **Family C (heterogeneous)** — 11 unique semantics, each needs own example. Diminishing returns. - **Family D/F (extra JOIN, spurious JOIN)** — P3.F-style schema linker. Multi-day. p3f_design.md says don't speculate. - **Family E (gold wrong)** — Arcwise catches. Already credited in 72.36% Arcwise-Plat number. No v19 patch needed. ## Recommended action Apply P2 + P3 only (low-risk schema-doc patches). **Defer P1** until evidence that LIMIT-discipline patch на n=200 не регрессит. Запустить experimental v19 build with P2+P3 + run full n=200 eval — expected +1pp without regression. P1 экспериментально гонять на v18-passing subset (173 cases) и измерять regression rate напрямую. Если ≤+0 regression, добавлять; иначе skip. ## How to verify regression for P1 ```bash # 1. Apply P1 prompt patch # 2. Re-run full n=200 eval make eval ARGS="--limit 200" # 3. Compare per-qid match flags v18 baseline vs v19 python scripts/audit_rescore.py \ --baseline eval/reports/2026-05-18b/v18-gpt52-pro-merged.json \ --candidate eval/reports//v19-with-P1.json # 4. Count regressions (passing in v18, failing in v19) ``` If regression count > P1 gain count, **revert P1**.