Weigh before/after eval harness
extraction-prompts · run 2026-10-20-v6 · 2026-11-12

v6 holds quality and uses 7.5% more prompt tokens.

Exchange Triage extraction prompts v1 to v4 over the 27-case golden set, through the production pipeline (intake, extraction, grounding, appetite; writer off) on claude sonnet via the CLI. Baseline v3 (production), candidate v6 (v5 with the per-unit clause corrected), v3-repeat as the noise floor, v5, v4, v2 and v1 for history. Reference: the golden labels. Judges: two source-attribution classifiers, validated against human labels in weigh/labels/extraction-prompts.jsonl. 27 cases, two variants, 7 binary checks. Tokens and cost are metered from the provider's usage report.

Gate passed. Pass-all did not drop and decision_correct, fields_correct did not fall.
Noise floor: the candidate's change is within it. The baseline run twice (v3 against v3-repeat) moved pass-all +0.0% against the candidate's +29.6%; decision_correct +3.7% against the candidate's +18.5%, fields_correct -3.7% against the candidate's +0.0%. A drop no larger than the baseline's own drift is not evidence of a regression.
48%v3
pass-all rate, baseline (13 of 27)
78%v6
pass-all rate, candidate (21 of 27)
+7.5%
prompt tokens per case, 5,096 to 5,479 (+7.2% to +7.8% on the mean)
+25.2%
cost per case, $0.0119 to $0.0149 (API-equivalent)
-3.0%
latency per case, 13.6 s to 13.2 s

Checks

Every check is pass or fail per case. Rates carry Wilson 95% intervals. A check both variants pass everywhere is saturated: it guards against regressions but no longer discriminates.

checkkindv3v6delta95% interval (candidate)
extraction_schema
Extraction JSON matched the schema within the pipeline's two attempts.
code27/27 100.0%27/27 100.0%+0.0%88% to 100%saturated
fields_correct
Every labelled field matches the golden value under the app's own field scorer (0.5% on dollar amounts, canonical construction class, null means null).
code27/27 100.0%27/27 100.0%+0.0%88% to 100%saturated
construction_canonical
constructionType is the canonical ISO class the appetite rules consume, not the broker's wording.
code18/18 100.0%18/18 100.0%+0.0%82% to 100%saturated
nulls_stay_null
Fields the source never states come back null (no guessed TIV, year built, state or subclass).
code5/5 100.0%5/5 100.0%+0.0%57% to 100%saturated
decision_correct
The routing decision matches the golden label.
code22/27 81.5%27/27 100.0%+18.5%88% to 100%
attribution_jev
Jev (TypeSafe yes/no classifier) says every `source` attribution is truthful: the value is stated in the document it names. Pass at probability 0.5 or above.
judge0/0 n/a0/0 n/an/a0% to 100%
attribution_claude
Claude Haiku, given only the source text and the extracted fields, says every `source` attribution is truthful.
judge17/27 63.0%21/27 77.8%+14.8%59% to 89%

No per-case regression: every check the baseline passed, the candidate passed too.

Prompt tokens, paired

One row per case. Grey is v3; the colored dot is v6. Mean change +7.5%, median change 376 tokens, bootstrap 95% interval on the mean difference 367 to 399 tokens.

01,4712,9424,4135,884prompt tokens
v3v6 used fewerv6 used more

Per-case ledger

Dots are checks in the order of the table above; hollow means the check did not apply. Tokens are prompt tokens the model read (fresh input plus cache read plus cache creation).

casev3v6tokens v3tokens v6changedecisionfitScoreretriesfieldsWrongmodelErrors
GOLD-015,3245,700+7.1%IN APPETITE9000
GOLD-025,3575,735+7.1%IN APPETITE8600
GOLD-035,5865,884+5.3%IN APPETITE8400
GOLD-045,1405,516+7.3%IN APPETITE8800
GOLD-055,3065,682+7.1%IN APPETITE8600
GOLD-065,4195,723+5.6%DECLINED1200
GOLD-075,2525,556+5.8%DECLINED1200
GOLD-085,1155,483+7.2%INCOMPLETE6200
GOLD-094,9865,362+7.5%INCOMPLETE7800
GOLD-105,2025,624+8.1%REFERRED3500
V-015,0475,423+7.4%IN APPETITE9000
V-024,9305,395+9.4%IN APPETITE8400
V-034,8515,316+9.6%IN APPETITE9200
V-044,9705,346+7.6%IN APPETITE8800
V-054,9995,375+7.5%IN APPETITE9000
V-065,0145,390+7.5%IN APPETITE8600
V-075,0205,396+7.5%IN APPETITE9200
V-084,9245,300+7.6%INCOMPLETE8600
V-094,9645,340+7.6%IN APPETITE8400
V-105,0415,417+7.5%DECLINED2800
V-115,0905,466+7.4%IN APPETITE8600
V-125,0495,425+7.4%IN APPETITE8400
V-135,0075,476+9.4%IN APPETITE9000
V-144,9085,284+7.7%INCOMPLETE7200
V-155,1085,484+7.4%IN APPETITE8800
V-164,9285,393+9.4%IN APPETITE8600
GOLD-275,0665,436+7.3%IN APPETITE8800

Judge validation

Each judge check is a classifier. Its verdicts count only as far as they agree with a person's labels on a split it never saw. Positive means a failure is present. TPR is the share of human-labelled failures the judge caught; TNR the share of human-labelled passes it left alone. Two judges on the same property can be compared row for row.

attribution_claude

splitnhuman failshuman passesTPRTNR
all54144071.4% 45% to 88%70.0% 55% to 82%
train121110.0% 0% to 79%90.9% 62% to 98%
dev22319100.0% 44% to 100%63.2% 41% to 81%
test20101070.0% 40% to 89%60.0% 31% to 83%

54 labels matched a judge verdict; 0 did not.

Where runs fail

Rows are the last stage that succeeded, columns the first that failed. The matrix says where to look before any judge is built.

v3

last success \ first failureappetitegrounding
grounding5
extraction2

7 of 27 traces failed a stage.

v6

last success \ first failuregrounding
extraction4

4 of 27 traces failed a stage.

Method

Variants. v2: Extraction prompt v2: canonical construction classes and the broker-working-value rule. Shipped 2026-07-27. v3: Extraction prompt v3, production: null-first subclass rule and source tied to a citable span, after a live over-extraction Arize caught. v3-repeat: v3 run a second time on identical inputs: the noise floor. v4: Extraction prompt v4, measured 2026-10-20: a bare construction word is a stated class (bare masonry is Joisted Masonry), both means each document states it, outside-knowledge values keep source null. From the measured v3 failures. v6: Extraction prompt v6, candidate: v5 with one clause corrected, a per-unit target rate times the unit count is the target premium. From the measured v5 misses on V-12 and V-16. v5: Extraction prompt v5, measured 2026-10-20: v4 plus one targetPremium rule; fixed GOLD-09 and GOLD-02, missed per-unit targets on V-12 and V-16. v1: Extraction prompt v1, frozen: plain instructions, no construction mapping, no few-shot examples.

Checks. extraction_schema (code): Extraction JSON matched the schema within the pipeline's two attempts. fields_correct (code): Every labelled field matches the golden value under the app's own field scorer (0.5% on dollar amounts, canonical construction class, null means null). construction_canonical (code): constructionType is the canonical ISO class the appetite rules consume, not the broker's wording. nulls_stay_null (code): Fields the source never states come back null (no guessed TIV, year built, state or subclass). decision_correct (code): The routing decision matches the golden label. attribution_jev (judge): Jev (TypeSafe yes/no classifier) says every `source` attribution is truthful: the value is stated in the document it names. Pass at probability 0.5 or above. attribution_claude (judge): Claude Haiku, given only the source text and the extracted fields, says every `source` attribution is truthful.

Gate. Candidate pass-all may not drop by more than 0%, and the rate of decision_correct and fields_correct may not be lower on the candidate. Regressions per case are listed, not gated.

Numbers. Token counts and cost come from the provider's usage report on every call (metered). Cost is the API-equivalent figure; these calls ran on a subscription. Latency is wall time per case including every call the variant made. Intervals: Wilson for rates, seeded percentile bootstrap (2,000 resamples) for paired means. No p-values.

Pairing. Only cases both variants completed are compared, in suite order, so every paired number has the same n (27). Errors: 0 on v3, 0 on v6.

Reproduce.

bun src/cli.ts run <path> --run-id 2026-10-20-v6 --concurrency 4
bun src/cli.ts report extraction-prompts 2026-10-20-v6