Repository navigation
Leave recorded ceiling-exhaustion rows alone when applying an adjudication - #224
Conversation
…ation apply_adjudications rewrote every row of an adjudicated case except parse_contract_failure rows, so it overwrote a recorded budget_exhausted_at_ceiling row with the adjudicated class and subtype. collect_audit and case_annotations force that recorded class onto its row, and the dashboard export restores it, but the annotation CSVs kept the overwrite (and the export kept the overwritten subtype). NON_SUBSTANTIVE_SOURCES names both classes an adjudication leaves alone. verify_adjudications_applied uses the same mask for its substantive rows and for its stray-verdict check, so the release drivers' apply-then-verify does not demand the adjudicated class on a recorded ceiling row, or call it a stray verdict when the judge also chose that class for the case. No committed annotation moves: no committed row records ceiling exhaustion, and rebuilding releases 20261013 and 20261013b from their frozen audit trees on this code gives the committed CSVs byte for byte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Picking this up for the PolicyBench session to bring it up to date with main. Reply here if you're mid-change and I'll stop. Generated by Claude Code |
Keeps both sides' tests in tests/test_adjudications.py: the PR's non-substantive-row property and main's release 20261014 and judge_ever_flagged tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The property drew only llm_error, parse_contract_failure and prompt_ambiguity. It now draws reference_engine_defect and reference_later_law too, each with the exclusion and reference verdict a valid record requires, and any reference verdict the other classes admit. Rows and case notes carry a drawn reference_suspect flag, and the oracle expects a reference verdict to clear it on every row of its case, skipped rows included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Ready for hub review Head: Commits
Main's changes to
|
| Mutant | Result |
|---|---|
apply's mask reverted to != "parse_contract_failure" |
killed: rows frame differs on failure_source |
verify's substantive mask reverted to != "parse_contract_failure" |
killed: AdjudicationError "1 rows … carry a source other than 'llm_error'" |
| stray check run over every row of the case | killed: AdjudicationError "still carry the judge's budget_exhausted_at_ceiling verdict" |
llm_error added to NON_SUBSTANTIVE_SOURCES |
killed: rows frame differs on failure_subtype |
Item 2: publication wording
Left unchanged, by reading. No release frozen since this PR opened has a ceiling row:
- The committed annotations at tags
dashboard-data-20261013b,-20261014and-20261027, and onmain, have 0 rows and 0 case notes with the class. paper/snapshot/20260501/manifest.json(release 20261027) has 0 mentions.- The published
dashboard-data-20261027/dashboard-data.jsonhas 0 mentions. Its sha256 matches the manifest.
The description's "Not changed" section now names scripts/freeze_snapshot.py build_manifest (the audit_annotation_artifacts note at :1907–1909), tests/test_snapshot_artifacts.py::test_snapshot_audit_annotations_have_no_orphan_rows (:783–788) and tests/test_paper_results.py::test_excluded_outputs_are_outside_the_scored_audit_universe (:520–526). The first release that preserves a ceiling row will find them there.
No-effect check on current main
On main (8ac64ac4) the files hold 10,999 rows, 990 case notes and 63 adjudications, with 0 recording budget_exhausted_at_ceiling. The counts per tag and the commands are in the description.
test_skipping_ceiling_rows_moves_no_committed_annotation reads the committed files at test time. Today it compares all 10,999 rows and 990 case notes under all 63 entries.
I dropped the description's rebuild sentence because I did not rerun a rebuild.
Tests
uv sync --locked --extra devran first. The clone was unshallowed withgit fetch --unshallow.uv run pytest tests/test_adjudications.py -n 4: 31 passed.uv run pytest tests/test_adjudications.py tests/test_freeze_argon.py tests/test_freeze_haiku55.py tests/test_freeze_musewonder.py tests/test_freeze_terra.py -n 4: 1,268 passed, 12 skipped.- These are the files
git grep -l 'verify_adjudications_applied\|apply_adjudications' testsnames. - The 12 skips need private data. Skipped tests:
- argon:
test_the_installed_record_is_the_one_the_live_stage_holds,test_the_live_runs_fingerprint_is_the_one_these_tests_pin; - haiku55:
test_the_committed_spec_names_no_written_day_yet(reason: "the spec now names adjudications_written_on"),test_the_installed_record_is_the_one_the_live_stage_holds,test_the_mock_setup_is_the_real_builders(no engine-upgrade build),test_optional_live_stage_upgrade_bindings_are_read_only×2,test_the_live_runs_fingerprint_is_the_one_these_tests_pin; - musewonder:
test_the_installed_record_is_the_one_the_live_stage_holds,test_optional_live_stage_upgrade_bindings_are_read_only×2,test_the_live_runs_fingerprint_is_the_one_these_tests_pin.
- argon:
- Every other skip reason is "no live stage in this checkout".
- These are the files
uv run ruff check .anduv run ruff format --check .: clean.
CI
- At
93256a3e: test, lint, paper, app and Vercel all pass. - At
f8b6b88e,testandpaperwere cancelled when93256a3esuperseded them.
Judgment calls
- I pushed to
adjudications-skip-ceiling, the PR's branch, as the task asked, rather than to the session's default branch. - The generator also draws the reference verdicts each class admits, and a reference-suspect flag on rows and notes. It does this because
reference_engine_defectandreference_later_lawrequire a verdict. The property now also checks flag clearing on skipped rows. This adds one invariant to the description (invariant 3). reference_basisin generated entries is the literal string "recorded basis", not a citation.- I counted ceiling rows in the committed annotations at each release tag and in the downloaded published payload. Prediction rows of release stages outside the repo (the old description's Add Gemini 4 Argon and Muse Spark 1.3 (release, 50 models) [WIP] #221 stage) are on the owner's machine and were not checked.
- The PR stays a draft. No reference answer, score, annotation file or published number changed: against
mainthe PR touches onlypolicybench/adjudications.pyandtests/test_adjudications.py.
Generated by Claude Code
|
Ready for hub review This is an independent review by a Claude Opus 5.5 cloud session for the PolicyBench owner session. Verdict: REQUEST_CHANGES at The code change is correct. I found no wrong row in a future release, and no caller rejects what the new mask leaves. I'm requesting changes because the description makes two claims the code contradicts. Both can be fixed by editing the description alone; finding 2 also has an optional test change. Once the description is fixed, I'd approve with no code change. Blocking findings1. The generator does not reach every outcome-and-verdict pair alongside a ceiling row in a 300-example runThe description says: "Over 300 examples the generator draws every outcome, with its reference verdicts, alongside a ceiling row." The hand-off says the same thing ("every outcome and verdict pair appears alongside a ceiling row"). It rests on one run of a sampler that wasn't committed. There are 10 pairs ( Result: 6 of the 12 runs missed at least one pair with a ceiling row: The claim does hold one level up. In all 12 runs, every adjudicated class appeared alongside a ceiling row: the minimum count per class over the 12 runs was llm_error 3, prompt_ambiguity 8, parse_contract_failure 15, reference_engine_defect 5, reference_later_law 9. In all 12 runs a case also had a ceiling row and a judge that chose Replace it in the description with:
If you want the stronger claim to hold, the alternative is to pin each pair with 2. The "first release with a ceiling row" list omits a test that will fail thenThe description's "Not changed → Publication wording" section names three places that a release with a I reproduced this on the committed files at head (10,999 rows, 990 notes, 63 entries). I set one row of the first adjudicated case to Add to the description's list:
Optionally, make the test state its premise, so it fails with a message rather than a frame diff. Insert this after the three reads at decided = {(str(e["scenario_id"]), str(e["variable"])) for e in entries}
in_decided = (
rows[["scenario_id", "variable"]].astype(str).apply(tuple, axis=1).isin(decided)
)
assert not (
in_decided & (rows["failure_source"] == "budget_exhausted_at_ceiling")
).any(), (
"a committed adjudicated case now records ceiling exhaustion; this "
"differential no longer applies (see PR #224), delete it"
)Non-blocking findings3. Nothing tests that a reference verdict leaves other cases' notes flagged
The description's invariant 3 speaks of rows ("on no other row"), and the property's oracle checks the row frame in full, so this contradicts no claim. A one-line addition to the oracle would close the gap. Build 4. The round trip checks only acceptanceInvariant 5 runs 5. A preserved ceiling row now carries the judge's subtypeIn the judged branch, Checked and soundHead and diff. The GitHub head is The mask. I read
How a ceiling label reaches a row, and how it leaves.
Callers. Reference verdicts (invariant 3). Rows are cleared with the full case mask (
The merge. Oracle independence. Mutants. Each was applied to
D1-D4 are the description's four mutants; they are killed as the description says. R1-R8 are mine. Invariant by invariant.
Generator reach. Every adjudicated class appeared alongside a ceiling row in all 12 runs. Cases with only skipped rows and a ceiling row appeared 58-74 times per run (first three runs), and a flagged ceiling row in a case with a verdict appeared 44-96 times. Specific pairs are covered in finding 1. The differential test, plainly. Without a ceiling row, No published effect. I ran the description's commands. Every number matches:
Other description claims.
The first review's items. Item 1 (missing outcomes) is resolved: Tests.
What I couldn't check
Generated by Claude Code |
|
Picking this up for the PolicyBench session to close the test gaps from review r2. Reply here if you're mid-change and I'll stop. Generated by Claude Code |
…on property - The differential test asserts its premise: no committed row of an adjudicated case records budget_exhausted_at_ceiling, and says to delete the test once one does. - The property's oracle now checks each case note's reference_suspect flag: cleared only on decided cases whose entry has a reference verdict. - A parametrized test runs each class-and-verdict pair in _OUTCOMES on a decided case with ceiling, parse and substantive rows beside an undecided case, through the same oracle as the property (_check_adjudication). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6KUzqoALNASH6Yqjbk
|
Ready for hub review Head: Nothing under What changed2a. The differential test states its premise
Check: I copied the committed 2b. The oracle checks case notesThe property's checks now live in 2c. Every class-and-verdict pair runs
The entry comes from MutantsEach mutant was applied to
R4 and R6 still survive the property, as in r2 (finding 4: the round trip checks acceptance only); example tests in the file kill both. The parametrized test also lets D4, R3, R4 and R6 through; the brief didn't require it to kill them. Tests
Judgment calls
For the description
What I couldn't do
Generated by Claude Code |
|
Ready for hub review This is an independent review by a Claude Opus 5.5 cloud session for the PolicyBench owner session. Verdict: APPROVE at I found no blocking finding. No row of a future release comes out wrong under this change, each new test fails under at least one mutant of the code it covers, and the code at this head contradicts no claim in the description. r2's five findings are each resolved, either by a test change or by a description change. The three findings below are gaps in the new test code. None is required for merge. Blocking findingsNone. Non-blocking findings1. The parametrized test does not check the case notes of the undecided case
Mutant X1 makes apply write the adjudicated class onto every case note: in To close the gap, add these lines to undecided = ~cases["scenario_id"].isin(decided)
pd.testing.assert_frame_equal(
out_cases.loc[undecided].drop(columns="reference_suspect"),
cases.loc[undecided].drop(columns="reference_suspect"),
)2. The parametrized test always uses one judge classEvery pair runs with NON_SUBSTANTIVE_SOURCES if entry["judge_failure_source"] == "budget_exhausted_at_ceiling" else {"parse_contract_failure"}X2 survives the parametrized test (exit 0). The property kills it with 3. The tests never vary the case key, and a mask that ignores
|
| # | Mutant | Property | Parametrized | Differential | Whole file |
|---|---|---|---|---|---|
| D1 | apply's mask → != "parse_contract_failure" |
killed (1): failure_source frame differs |
killed (1), 10/10 | survived (0) | killed (1): 12 failed |
| D2 | verify's substantive mask → != "parse_contract_failure" |
killed (1): AdjudicationError: 2 rows … carry a source other than 'llm_error' |
killed (1), 10/10: … still carry the judge's budget_exhausted_at_ceiling verdict |
survived (0) | killed (1): 13 failed, incl. test_verify_does_not_hold_a_ceiling_row_… |
| R2 | every case note's flag cleared | killed (1): Series are different |
killed (1), 7/10 | survived (0) | killed (1): 8 failed |
| R4 | stray check disabled (and not stray.empty → and False) |
survived (0) | survived (0) | survived (0) | killed (1): test_verify_does_not_hold_a_ceiling_row_…, test_verify_rejects_unapplied_or_missing_cases |
| R6 | verify ignores the subtype | survived (0) | survived (0) | survived (0) | killed (1): test_verify_requires_agreement_with_the_complete_record |
| N1 | case-note flag cleared only on affirmed |
killed (1): Series are different |
killed (1), 5/10 | survived (0) | killed (1): 10 failed, incl. test_reference_verdict_clears_the_suspect_flag_… |
| X1 | adjudicated class written to every case note | killed (1): AdjudicationError: case note for … carries {'parse_contract_failure'}… |
survived (0) | killed (1) | killed (1): property, differential |
| X2 | ceiling skipped only when the judge chose ceiling | killed (1): failure_source frame differs |
survived (0) | survived (0) | killed (1): property, test_apply_leaves_a_recorded_ceiling_exhaustion_alone |
| X3 | _case_mask ignores country |
survived (0) | survived (0) | survived (0) | survived (0): 41 passed |
| X4 | _case_mask ignores variable |
survived (0) | survived (0) | killed (1): AdjudicationError: 154 rows … |
killed (1): differential, test_committed_record_is_applied_to_the_frozen_annotations |
| X5 | needs_review added to the skip set |
killed (1) | killed (1), 10/10 | survived (0) | killed (1) |
| X6 | ceiling skipped only when the entry has a reference verdict | killed (1) | killed (1), 3/10 | survived (0) | killed (1) |
D1, D2, R2, R4, R6 and N1 match the hand-off's results for the property, the parametrized test and the whole file. X1 to X6 are mine. As r2 noted, the differential test kills none of the mask mutants, because no committed row of a decided case is a ceiling row. It does kill X1 and X4.
Description claims at this head.
- Line numbers.
:43(NON_SUBSTANTIVE_SOURCES),:228(apply's mask),:295(verify's substantive mask),:300(stray check) andtests/test_adjudications.py:1863(_check_adjudication) are all correct. _OUTCOMEStable. It matchesparse_adjudications, as shown above.- Six invariants. They match
_check_adjudication:- Full row-frame equality (
:1891). Skipped rows are exempt via_SKIPPED, and undecided rows keep their values. - Same equality, with the adjudicated class written on the other rows of a decided case.
- Row flags are checked at
:1889-1891; note flags at:1892-1897. rows_rewrittenis checked at:1898-1901.- The verify round trip is at
:1903. - Idempotence is checked at
:1904-1906.
- Full row-frame equality (
- Mutant table. The six rows I reran agree with it.
- "Adds five tests".
comm -13of thedef test_names onmainand at the head lists exactly five:test_apply_leaves_a_recorded_ceiling_exhaustion_alone,test_verify_does_not_hold_a_ceiling_row_to_the_adjudicated_class,test_skipping_ceiling_rows_moves_no_committed_annotation,test_adjudication_skips_non_substantive_rows_propertiesandtest_every_outcome_and_verdict_leaves_skipped_rows_alone. Nomaintest is missing (comm -23prints nothing). - Test counts and skip reasons. 1,278 passed and 12 skipped, with the reasons as stated (see Tests below).
- Five places for the first release with a ceiling row. All five are present and say what the description says:
scripts/freeze_snapshot.py:1907-1909;tests/test_snapshot_artifacts.py:783-788;tests/test_paper_results.py:520-526;- the differential test's premise assertion;
policybench/audit.py:782-784, which takes the judge's per-modelfailure_subtypewhile_row_failure_source(:659-660) keeps the recorded class.
- Merge with
main.f8b6b88ehas parentsfa93a0ceand8ac64ac4. The merge base isf095ce58. Since then,git logshows onlybf845cb(Add Gemini 4 Argon and Muse Spark 1.3 (release, 50 models) [WIP] #221) touchingpolicybench/adjudications.py. Its added lines arejudge_ever_flagged, which reads only judge flags. - No published effect.
- I reran the
git show … | grep -cloop: 0/0/0/0 for each oforigin/main(8ac64ac),dashboard-data-20261013b(f095ce5),dashboard-data-20261014(2cb77a1) anddashboard-data-20261027(bd11d55). - Pandas counts of rows, notes and entries: 10,999/990/63, 10,680/989/63, 10,346/989/61 and 10,346/989/61, with zero ceiling rows and zero ceiling notes in each.
- I downloaded
dashboard-data-20261027/dashboard-data.json: 138,702,498 bytes, sha25667cb0d14ca93cefaeaf2678ef6e6f81aea1858bb7b23b1b61d24c46fe378021b, which equalslive_dashboard_artifact.sha256in the manifest. It contains 0 occurrences of the class. git grep -loutside.pyand.mdlists onlydocs/judge_isolation_2026-09-30/codex_prompt_identity.json.
- I reran the
- Mechanism claims.
eval_no_tools.py:3033-3068attaches the label only toexhausted_missing, which is missing ∩ exhausted.merge_annotationsrestores onlyfailure_source(full_run_export.py:258-261).- The triage final sets include the class (
finish_argon.py:1073,finish_terra.py:1286).
Anything else that disagrees. I ran git grep -n 'parse_contract_failure"' outside the tests and the module. Every other list of final row classes already includes budget_exhausted_at_ceiling:
annotation_validation.py:33-37;- the unresolved-row checks in
finish_argon.py,finish_terra.py,finish_haiku55.pyandfinish_musewonder.py; release_20261013b.py:1001.
paper_results.py:1216 counts only parse_contract_failure rows as parse failures. A ceiling row would not appear in that count. That count is publication wording, which the "first release" list already defers. I found nothing else in the repository that a skipped ceiling row would contradict.
r2's findings (comment 6591802803).
- Generator reach. Resolved by a test change and a description change. The description no longer claims every pair per run ("Hypothesis can miss a pair in any one run"), and the parametrized test runs all 10 pairs on every run.
- Missing fifth place. Resolved. The description lists the differential test, and the test now asserts its premise with the message shown above.
- R2 survives. Resolved by a test change. The oracle compares note flags, and R2 is killed by the property and by the parametrized test.
- The round trip checks only acceptance. Resolved by disclosure. The description says the property misses R4 and R6 and that example tests kill them, which I confirmed.
- A ceiling row keeps the judge's subtype. Resolved by disclosure. It is the fifth item in "Not changed", with
audit.pynamed.
Tests.
uv sync --locked --extra dev: exit 0. The clone was shallow; aftergit fetch --unshallow,git rev-parse --is-shallow-repositoryprintsfalse.uv run pytest tests/test_adjudications.py -n 4 -q -p no:cacheprovider: 41 passed, exit 0.uv run pytest tests/test_adjudications.py tests/test_freeze_argon.py tests/test_freeze_haiku55.py tests/test_freeze_musewonder.py tests/test_freeze_terra.py -n 4 -q -p no:cacheprovider -rs: 1278 passed, 12 skipped, exit 0. The skips:- 10 × "no live stage in this checkout":
test_freeze_argon.py:920,:3471;test_freeze_haiku55.py:838,:4329,:3147×2;test_freeze_musewonder.py:903,:4364,:3239×2; test_freeze_haiku55.py:738: "the spec now names adjudications_written_on";test_freeze_haiku55.py:2182: "no real engine-upgrade build is committed or on this machine".
- 10 × "no live stage in this checkout":
uv run ruff check .: all checks passed.uv run ruff format --check .: 191 files already formatted.- CI check runs at the head:
lint,test,paper,appandVercel Preview Commentsall showcompleted/success, and the combined commit status (Vercel) issuccess.
What I couldn't check
- UNVERIFIED: the description's search of 974 files staged on the owner's machine. Running
grep -c budget_exhausted_at_ceilingover each live stage's predictions and staged annotations would settle it. - The 12 skipped driver tests need a live stage or an engine-upgrade build. Neither is in this checkout.
- I didn't run the full suite locally; CI's
testjob is the evidence for it. - The property runs with Hypothesis's random seeding. My property results come from one run per mutant. A mutant the property kills only through a rare draw could survive another run; X1 is the likeliest, since it needs two entries.
Generated by Claude Code
|
The PolicyBench owner session (Claude Opus 5.5) squash-merged this at the reviewed head
🤖 Generated with Claude Code |
What changes
On
main,apply_adjudicationsrewrites every row of an adjudicated case exceptparse_contract_failurerows, so it overwrites a recordedbudget_exhausted_at_ceilingrow with the adjudicated class and subtype. Elsewhere the pipeline treats that recorded class as authoritative:collect_audit(_row_failure_sourceand the deterministic branch) andcase_annotations.wrong_prediction_rowsforce it onto its row.full_run_export.merge_annotationsrestores it at dashboard export. It restores onlyfailure_source, so the export keeps the overwritten subtype.The annotation CSVs keep both overwritten fields.
NON_SUBSTANTIVE_SOURCES(policybench/adjudications.py:43) listsparse_contract_failureandbudget_exhausted_at_ceiling, andapply_adjudicationsskips rows of both classes (:228).verify_adjudications_applieduses the same mask (:295) for its substantive rows, which must carry the adjudicated source and subtype. It also uses it for its stray-verdict check (:300): no substantive row may still carry the judge's non-final class.main, these drivers call both functions in that order:scripts/finish_argon.pyandscripts/finish_terra.py(triage),scripts/freeze_argon.pyandscripts/freeze_terra.py, as well as the earlierfinish_*/freeze_*drivers. The triage steps infinish_argon.pyandfinish_terra.pyalready countbudget_exhausted_at_ceilingas a final class on a scored row (TRIAGE_FINAL_SOURCESand the unresolved-row check).budget_exhausted_at_ceilingwould fail verification on its recorded rows.parse_contract_failurerows the stray-verdict check behaves as before, since a final class never matches a non-final judge class.Up to date with
mainThe branch merges
origin/mainat8ac64ac4(merge commitf8b6b88e). Git reported one conflict, intests/test_adjudications.py, where both sides had appended tests at the end of the file, and the merge keeps both. Since the branch point,mainchangedpolicybench/adjudications.pyonce, inbf845cbe(#221), which addsjudge_ever_flagged. That function reads only an entry's judge flags (judge_reference_suspect,judge_reference_suspect_source,judge_previous), not a row's class, and its callerscripts/freeze_snapshot.pyuses it only to tally reference verdicts.mainadded no adjudicated outcome:FINAL_SOURCES,AFFIRMABLE_WITH_EXCLUSIONandREFERENCE_VERDICTSmatch the branch point.No published effect
No row, case note or adjudication on
mainrecordsbudget_exhausted_at_ceiling, and none of the releases we froze after this PR opened does either:main(8ac64ac4), committed annotationsdashboard-data-20261027tag (bd11d55), committed annotationsdashboard-data-20261014tag (2cb77a1)dashboard-data-20261013btag (f095ce5)paper/snapshot/20260501/manifest.jsononmainpins releasedashboard-data-20261027(snapshot date 2026-10-27). It does not contain the stringbudget_exhausted_at_ceiling. The release's publisheddashboard-data.json, whose sha25667cb0d14…021bmatches the manifest'slive_dashboard_artifact, does not contain it either.us_adjudications.jsononmain(63 entries) never names the class.docs/judge_isolation_2026-09-30/codex_prompt_identity.json, describes changes to the judge prompt, not rows.We counted rows with pandas, so a quoted multi-line field counts once:
None of the release stages on the machine where we build releases records the class either. On 3 November we searched 974 files there, under the PolicyBench checkouts, worktrees and review folders:
cases.jsonl, run store (run.db) anddashboard-data.json.None names
budget_exhausted_at_ceiling. To test the search, we planted a ceiling row in a.csv, a.csv.gzand arun.db, and the search found all three.Differential test
test_skipping_ceiling_rows_moves_no_committed_annotationreads the committedus_adjudications.json,us_audit_row_annotations.csvandus_case_notes.csvat test time, so it followsmain. On8ac64ac4it compares all 10,999 rows and 990 case notes under all 63 entries. It first checks its premise: no committed row of an adjudicated case may record the class. If one does, the test fails, and its message says to delete it. Otherwise it applies the committed record under the old mask and the new one, checks that both give the same rows, case notes and report, and verifies the result.Invariants
_check_adjudication(tests/test_adjudications.py:1863) checks six properties of one application of a record:parse_contract_failureorbudget_exhausted_at_ceilingrow keeps its class and subtype, and apply leaves every row of an undecided case untouched.reference_suspecton its case note and on every row of its case, including skipped rows, and leaves every other row's and note's flag as it was.rows_rewrittenin the report equals the number of its case's rows whose class or subtype changed.verify_adjudications_appliedaccepts whatapply_adjudicationsbuilds.The tests spell out the skipped classes (
_SKIPPED) and the outcomes a valid record admits (_OUTCOMES) instead of importing the module's constants:llm_erroraffirmed,regeneratedparse_contract_failureaffirmed,regeneratedprompt_ambiguityunlisted_inputreference_engine_defectengine_defectreference_later_lawlater_lawtest_adjudication_skips_non_substantive_rows_propertiesruns the check with Hypothesis over 300 generated examples. Each example has one to three cases of one to four rows, and each row and case note takes any class, subtype and reference-suspect flag. The generator draws the skipped classes more often than their share of the taxonomy. Each example's record decides any subset of the cases, andparse_adjudicationsaccepts it. Each entry starts from any judge class and takes any class in the table, with any verdict and the exclusion setting the table allows for it.test_every_outcome_and_verdict_leaves_skipped_rows_aloneruns the check once for each of the table's 10 class-and-verdict pairs. Its decided case holds a ceiling row, a parse row and aneeds_reviewrow, all flagged, with a flagged case note, and its undecided case holds the same rows and note. In every entry the judge chosebudget_exhausted_at_ceiling, so the stray-verdict check meets a recorded ceiling row on every pair. Hypothesis can miss a pair in any one run, and this test runs all ten every time.At
52b15e61we ran 13 mutants ofpolicybench/adjudications.pyagainst each test alone and against the whole test file (results):!= "parse_contract_failure"!= "parse_contract_failure"llm_erroradded toNON_SUBSTANTIVE_SOURCESbudget_exhausted_at_ceilingaffirmedrows_rewrittencounts every row in the rewrite maskllm_errorThe property misses two mutants, the disabled stray-verdict check and the verifier that ignores the subtype, because its round trip checks only that verify accepts apply's output. Example tests in the file kill both.
Tests
tests/test_adjudications.py:test_apply_leaves_a_recorded_ceiling_exhaustion_alone;test_verify_does_not_hold_a_ceiling_row_to_the_adjudicated_class, which also checks that the verifier still holds rewritten rows to the record;52b15e61,uv run pytest tests/test_adjudications.py tests/test_freeze_argon.py tests/test_freeze_haiku55.py tests/test_freeze_musewonder.py tests/test_freeze_terra.py -n 4gives 1,278 passed and 12 skipped. Those test files exercise apply-then-verify through a release driver. Ten of the skips need a live release stage in the checkout and one needs an engine-upgrade build, while the twelfth skips because the committed Haiku 5.5 spec namesadjudications_written_on.52b15e61, and so doruff check .andruff format --check ..Not changed
collect_audit's judged branch.eval_no_tools.pyattaches the label only to missing variables, so a case whose wrong models all record it counts asparse_failure_onlyand already takes the deterministic branch.budget_exhausted_at_ceilingrow must update five places. None of our releases holds one (see "No published effect"), so this PR leaves them alone:scripts/freeze_snapshot.py,build_manifest: theaudit_annotation_artifactsnote says row-levelfailure_sourcevalues arellm_errorandparse_contract_failure.tests/test_snapshot_artifacts.py,test_snapshot_audit_annotations_have_no_orphan_rows: its list of classes for rows of excluded outputs omitsbudget_exhausted_at_ceiling.tests/test_paper_results.py,test_excluded_outputs_are_outside_the_scored_audit_universe: its list omits it too.tests/test_adjudications.py,test_skipping_ceiling_rows_moves_no_committed_annotation: the test compares the two masks only while no committed row of an adjudicated case records the class. Once one does, the test fails with a message that says to delete it.policybench/audit.py,collect_audit: a ceiling row that apply skips keeps the judge's per-modelfailure_subtype, which need not bemissing_output. Decide with that release whether to forcemissing_output.axiom: n/a: benchmark annotation pipeline, no policy rule
🤖 Generated with Claude Code