Skip to content
ML Academy

project-043 · LLM and GenAI · insurance

Golden-set regression suite that gates prompt changes for a claims-intake triage assistant

An insurer's first-notice-of-loss assistant reads a customer's message and returns a triage record (claim type, urgency, documents to request, escalate or not). Prompt engineers change the prompt every few weeks. How do you know a new prompt version is safe to release - that it does not break critical behaviours such as escalating an injury or refusing to promise coverage - and how do you keep the test itself trustworthy when model outputs vary from run to run?

Dataset
Synthetic claims-intake golden set (academy/learner-authored), with labelled recorded-output fixtures for harness testing
Licence
Synthetic, learner-authored; no third-party licence
Reference run
executed

At a glance

  • Data

    Synthetic claims-intake golden set (academy/learner-authored), with labelled recorded-output fixtures for harness testing (synthetic) · Planned: about 120 base cases plus about 80 behavioural variants (invariance and directional pairs)

    Details on data
  • Baseline

    The current approach to beat: an engineer eyeballs ten outputs before a release. The minimal automated baseline is exact-match on claimtype and escalate over the base…

    Details on baseline
  • Validation

    Validate the suite, not only the prompt: (1) mutation test - run deliberately broken prompt versions (removed escalation instruction, added coverage promise) and confirm…

    Details on validation
  • Metric

    Critical-test failures (count, must be zero), per-property pass rates, aggregate score with paired bootstrap interval between versions, flaky-case rate, mutation catch…

    Details on metric

Success criterion

The suite is fit for purpose when (a) it blocks a deliberately broken prompt version on every run, (b) it passes the unchanged prompt on at least 95% of repeated runs (low false-alarm rate from sampling noise), and (c) its release rule is written down: zero failures on critical tests across three runs, and the aggregate score of the new version not worse than the current version by more than a pre-set non-inferiority margin. These are design targets, not measured results.

Context

Day 45 introduces regression suites; Day 47 introduces prompt versioning; Day 52 puts them into CI. A golden set is a versioned list of inputs with expected properties, not only expected strings. Behavioural test types (minimum functionality, invariance, directional expectations) make the suite cover behaviours rather than a few happy paths. The claims messages are synthetic: the academy authors them, and no real policyholder data is used.

Data

Dataset
Synthetic claims-intake golden set (academy/learner-authored), with labelled recorded-output fixtures for harness testing (synthetic)
Licence
Synthetic, learner-authored; no third-party licence
Size
Planned: about 120 base cases plus about 80 behavioural variants (invariance and directional pairs)
Verification
unverified

Access

Written by the learner from a template list of claim situations (home water damage, motor collision, theft, storm, injury involvement), stored as versioned YAML in the project repository. Recorded-output fixtures - hand- written outputs labelled as fixtures for prompt versions v1 and a deliberately broken v1-broken - let the harness be tested without a model. No network, no login.

Grain

One test case = one message with expected properties and a criticality flag; one result = (case, prompt version, model version, run index).

ColumnMeaning
case_id / messageSynthetic customer message; may include distractors such as policy numbers in the wrong format
expectedExpected properties: claim_type, urgency level, required documents (set), escalate flag, must_not_contain list
test_typeMFT (minimum functionality), INV (invariance pair), DIR (directional pair)
criticalTrue for behaviours that block a release on any failure, e.g. injury mention must escalate, no coverage promise
parent_caseFor INV/DIR variants, the base case they were derived from
suite_versionVersion of the golden set itself; changes are reviewed like code

EDA and data-quality rules

  • Every expected property is checkable by code (enum equality, set comparison, regex for forbidden phrases); cases needing human judgement go to a separate review sample, not the gate.

  • Coverage table of claim type x urgency x test type; no cell that matters to the business is empty.

  • Invariance variants change only the declared factor (names, cities, dates, writing style) and are reviewed to confirm the expected output should not change.

  • The golden set is versioned; any change to an expected value records who changed it and why, so the suite cannot be edited to make a prompt pass.

Baseline

The current approach to beat: an engineer eyeballs ten outputs before a release. The minimal automated baseline is exact-match on claim_type and escalate over the base cases, single run. The project shows what this misses (behavioural regressions, flaky passes).

Features

Scorers per property (exact, set precision/recall for documents, forbidden-phrase checks), per-case pass/fail, critical-test aggregation, repeated runs (k = 3) with a pass-rate per case, flaky-case detection (cases that both pass and fail on the unchanged prompt), and a non-inferiority comparison of aggregate scores with a paired bootstrap over cases.

Candidate methods

  • Property-based golden set with CheckList-style behavioural variants

    Catches regressions in behaviours that exact-match on a few fields misses.

  • Repeated runs with flaky-case quarantine

    Separates sampling noise from real regressions so the gate does not train people to ignore it.

  • LLM-judged properties for free-text fields (secondary, not gating)

    Covers tone and clarity, but a judge is itself an instrument that needs validation (see project-042).

Validation design

Validate the suite, not only the prompt: (1) mutation test - run deliberately broken prompt versions (removed escalation instruction, added coverage promise) and confirm the gate blocks them; (2) null test - run the unchanged prompt several times and measure the false-block rate; (3) keep 20% of cases hidden from prompt engineers as a holdout so prompts are not tuned to the visible suite.

Leakage checks

If engineers see every golden case, prompts get tuned to them and the suite stops measuring generalisation. Keep a hidden slice and rotate new cases in each quarter. Never paste golden cases into few-shot examples.

Bias and representativeness

Synthetic messages are written in standard English by one author; real customers write with errors, mixed languages and emotion. Add style-variant invariance tests and report results by style.

Robustness checks

Rerun the suite after a model version change with the prompt held fixed; that is a regression too. Test empty, very long and multi-claim messages.

Technical metrics

Critical-test failures (count, must be zero), per-property pass rates, aggregate score with paired bootstrap interval between versions, flaky-case rate, mutation catch rate, null-test false-block rate, run time and token cost per suite run.

Business interpretation

Releases blocked correctly vs falsely, time from prompt change to release decision, and incidents that escaped the suite (tracked after launch).

Error slices

  • Test type: MFT vs INV vs DIR failures point to different prompt problems.

  • Claim type and urgency: escalation errors on injury-involved claims are critical regardless of averages.

  • Writing style variants.

Implementation steps

  • Write the triage schema and the golden set with expected properties, criticality and test types; version it.

  • Implement scorers and the gate logic; unit-test them against hand-written recorded-output fixtures, including the broken-version fixtures, without any model.

  • With a configured model: run v1 three times, identify flaky cases, then run candidate v2 three times.

  • Run mutation and null tests; compute non-inferiority with paired bootstrap; produce a release report.

  • Wire the suite into CI as a required check for prompt files, with model version recorded in the report.

Reproduction

Learner-authored; for example uv run python -m golden.check_fixtures (no model, tests the harness on recorded fixtures) and uv run python -m golden.run --prompt v2 --repeats 3 with a model configured through environment variables. Without a model, the deliverable is a tested harness and gate, and the report states that prompt quality was not evaluated.

Limitations

  • A passing suite shows that tested behaviours still hold; it cannot show untested behaviours are fine.

  • Repeated runs reduce but do not remove sampling noise; rare failures need more runs than CI can afford.

  • Expected properties encode the author's reading of claims policy; they need review by a claims expert.

Production and monitoring

Store prompt, model id, golden-set version and results together for every release. Re-run the suite nightly against the pinned model to catch provider-side changes. Sample live traffic for human review and convert every escaped defect into a new golden case. Rollback is re-pointing to the previous prompt version, which must stay deployable.

Interview questions

  • How do you stop a regression suite for an LLM feature from becoming either flaky or toothless?

  • What is the difference between a golden answer and a golden property, and when do you need each?

  • Your new prompt improves the average but fails one critical test once in three runs. Do you ship?

Postmortem and alternatives

The suite's own quality is the main finding: mutation and null tests show whether it can be trusted. Discuss which critical behaviours should move out of the prompt into deterministic code (e.g. keyword-triggered escalation), so the suite tests less and the system guarantees more.

Reference implementation

Status: executed — outputs below are from the recorded run

cd python && uv run python -m reference.r19_golden_set_regression_gate.run

r19 results - golden-set regression gate on synthetic recorded outputs

Synthetic recorded outputs: no model was evaluated. Every output string was drawn from an authored behaviour profile (fixtures.py, seed 20260043) and stored in fixtures/recorded_outputs_v1.json.gz. The regressions are seeded by construction, so these results describe the gate and its statistics, not any prompt or model. Numbers are copied from outputs/metrics.json and the CSV files written by cd python && uv run python -m reference.r19_golden_set_regression_gate.run.

ItemValue
Date, seed2026-10-12, 20260043 (fixtures); bootstrap seed 11; null-test seed 2026
Golden set200 cases: 120 MFT, 52 INV, 28 DIR; 103 critical; 44 hidden (18 hidden critical)
Versions1 baseline (16 reference runs + 60-run pool of the unchanged prompt), 8 candidates x 8 runs
Gate3 gate runs, 5 confirmation runs only for suspect critical failures, margin 3 points, 2,000 bootstrap resamples
EnvironmentPython 3.12.13, numpy 2.5.3, standard library otherwise
Runtime25 s full run (about 2 s --smoke); tests 3 s

Baseline (v1) on the 16 reference runs: aggregate case pass rate 0.864 (run-to-run range 0.830 to 0.900 on 200 cases). Property pass rates: claim type 0.931, urgency 0.977, documents 0.971, escalate 0.983, no forbidden phrase 1.000. 21 cases are unstable (pass rate between 0.2 and 0.8 over 16 runs); none fails every run.

Gate decisions on the recorded candidates (3 gate runs)

CandidateAggregate base -> candDiff, one-sided 95% boundsNon-inferiorityCritical: suspects / confirmedSlice alarmsDecisionNaive "single run went up" (128 run pairs)
v2-reworded0.864 -> 0.865+0.001 (-0.021, +0.023)non-inferior2 / 0noneSHIPships 47%
v2-improved0.864 -> 0.913+0.049 (+0.031, +0.068)non-inferior1 / 0noneSHIPships 89%
v2-fewshot0.864 -> 0.918+0.054 (+0.027, +0.080)non-inferior15 / 11noneBLOCK: criticalships 66%
v2-reassure0.864 -> 0.818-0.046 (-0.072, -0.021)inconclusive23 / 10critical=yesBLOCK: criticalships 1%
v2-tuned0.864 -> 0.917+0.052 (+0.033, +0.072)non-inferior0 / 0noneSHIP (visible-only flag)ships 99%
v2-trim0.864 -> 0.722-0.143 (-0.176, -0.110)inferior3 / 03 slicesBLOCK: non-inferiorityships 0%
v2-borderline0.864 -> 0.827-0.038 (-0.060, -0.017)inconclusive1 / 0noneHOLD: inconclusiveships 5%
v1-broken-escalation0.864 -> 0.482-0.383 (-0.437, -0.327)inferior82 / 8212 slicesBLOCK: criticalships 0%

Mean candidate-minus-baseline over all 8 candidate runs (naive column basis): reworded +0.001, improved +0.034, fewshot +0.021, reassure -0.043, tuned +0.048, trim -0.141, borderline -0.035, broken -0.371.

Findings

  1. The "average went up" gate ships a critical-slice regression, and the gate does not. v2-fewshot raises the aggregate (mean +2.1 points over its 8 runs; +5.4 on the 3 gate runs; the naive rule passes in 66% of the 128 single-run comparisons) while the escalate property falls from 0.983 to 0.938 overall and, in the seeded slice (injury mentioned in a property claim, 31 cases), the all-property pass rate falls from 0.915 to 0.753 on the gate runs. The gate blocks it on all 56 choices of 3 gate runs out of 8: 11 critical cases are confirmed failing (all in the seeded slice; 9 of the 11 are DIR cases, the directional tests written to detect exactly this).
  2. Slice statistics alone did not catch it. The majority-pass McNemar test on the slice had 2 pass-to-fail and 1 fail-to-pass cases (p = 1.0): a case that fails 30% of the time still passes by majority in most runs, so the slice test is the wrong instrument for "sometimes fails". The per-case critical rule with confirmation reruns is what blocked it. The slice test did fire for broken, reassure and trim, where failures are frequent.
  3. Flake handling decides whether the gate is usable. On the unchanged prompt (300 null replicates):
    • "any critical failure in 3 runs blocks": 300/300 false blocks (100%, Wilson 98.7% to 100%). The five flaky critical cases alone make this nearly certain.
    • quarantine of baseline-flaky critical cases but no confirmation reruns: 202/300 false blocks (67%), from single one-off failures among about 90 stable critical cases.
    • quarantine plus confirmation reruns: 0/300 false blocks (Wilson 0% to 1.3%).
  4. The cost of flake handling is sensitivity to small critical regressions. Seeded escalation-miss probability on the 31-case slice (100 fresh simulated replicates per level): confirmed-block rate 0% at 0 (null), 9% at 0.05, 47% at 0.10, 97% at 0.20, 100% at 0.40 and 0.80. A regression that makes the slice fail one run in ten is blocked less than half the time by this rule; the rule trades that against a false-block rate of zero.
  5. Aggregate non-inferiority is underpowered at 200 cases and 3 runs. The unchanged prompt ships in 239/300 null replicates (79.7%, Wilson 74.8% to 83.8%); the other 61 are HOLD (inconclusive), none are blocked. A uniform degradation (all of claim-type, urgency and document error rates doubled, mean true diff -5.0 points) is never shipped (0/100): 61 HOLD, 33 BLOCK non-inferiority, 6 BLOCK slice; at x3 (-10.0 points) every replicate is blocked. Same arithmetic from the other side: the gate cannot distinguish "no change" from "-3 points" with this much data.
  6. v2-reworded ships on 41 of 56 gate-run triples and holds on 15. Even a true no-op flips between SHIP and HOLD depending on which three runs are used; decisions for all other candidates were identical on all 56 triples.
  7. A tuned-on-visible prompt looks good everywhere except where it should not. v2-tuned gains +6.9 points on the 156 visible cases (interval +4.5 to +9.5) and -0.5 on the 44 hidden cases (interval -6.0 to +4.5). The gate ships it (non-inferiority holds) with the visible-only flag. The flag is weak: v2-improved (a real improvement) also trips it by chance (visible +5.4, hidden +3.3, hidden interval -2.5 to +9.9).
  8. Seeded regressions: v2-reassure does not trap the naive rule. Its coverage promises also reduce the aggregate (-4.3 points over 8 runs), so the naive rule blocks it (ships 1 of 128 comparisons); only the critical rule says why.

Success criteria (design targets from the project record)

CriterionResult
(a) Blocks a deliberately broken version on every runMet on this fixture: v1-broken-escalation blocked on 56/56 gate-run triples; v2-fewshot and v2-reassure also 56/56. By construction (90% miss rate on 91 cases).
(b) Passes the unchanged prompt on at least 95% of repeated runsNot met: 79.7% (239/300). No false block, all misses are non-inferiority HOLDs. Post-hoc alternatives on the same pool (not the pre-set rule): 5 gate runs 90.7% (272/300); 7 gate runs 95.0% (285/300, Wilson 91.9% to 97.0%); 3 runs with a 4-point margin 95.0%.
(c) Written release ruleMet: README.md "Release rule" and the constants in gate.py.

What this does not prove

  • It does not measure any prompt or model. No model produced these outputs; the gate's catch rates are properties of a world in which the author decided where the regressions are. A real regression may be diffuse, correlated across cases or outside the golden set, none of which was tested.
  • Seeded-regression sizes were chosen by the author and adjusted once after a first look (the v2-fewshot gain and loss). The first null run used an 8-run baseline and showed false critical blocks from three flaky critical cases that happened never to fail in the baseline; the reference was raised to 16 runs. Both are design choices made after seeing output.
  • The null replicates share a 60-run pool and overlap; Wilson intervals treat them as independent, so they are somewhat optimistic. The power study uses 100 replicates per level.
  • Per-run outputs are independent draws; real sampling noise is correlated within a prompt version and across similar cases, which would make both flakiness and the intervals worse.
  • The 44-case hidden set gives wide intervals; the visible-vs-hidden flag cannot establish overfitting.
  • Properties are surface checks (enum equality, document sets, regex). Tone, clarity and paraphrased coverage promises are not tested. Moving escalation into deterministic keyword-triggered code (the record's postmortem question) was not simulated.
  • The margin (3 points), the confirmation rule (2 of 5) and the slice thresholds were fixed before the run and not tuned to hit criterion (b); the alternatives listed are labelled post-hoc.

Reproduce

cd python && uv run python -m reference.r19_golden_set_regression_gate.run
cd python && uv run pytest tests/test_r19_golden_set_regression_gate.py

Builder-authored reference. It is not learner evidence and is never credited to your portfolio.

Rubric3 criteria

CriterionMeetsExceeds
Suite designCode-checkable properties, criticality flags, behavioural variants and a versioned golden set.Coverage table shows deliberate choices, and a hidden holdout slice exists.
Suite validationMutation and null tests run on recorded fixtures or live outputs.Flaky-case analysis drives a documented quarantine and re-test policy.
Release decisionWritten release rule applied to v1 vs v2 with intervals.Moves at least one critical behaviour into deterministic code and shows the effect on the suite.

References4