Skip to content

Pin the October 5 audits' leaderboard impact, proposals and answers to the passes' inputs - #206

Merged
MaxGhenis merged 7 commits into
mainfrom
impact-evidence-pinned-inputs-1005
Oct 11, 2026
Merged

MaxGhenis merged 7 commits into
mainfrom
impact-evidence-pinned-inputs-1005

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR does what #205 does for the reference adversary, for the four other October 5 audits (2026-10-05 SALT withholding, Louisiana, Medicare Part B, payroll). Their scripts/leaderboard_impact.py copied the working tree's run and compared it against the working tree's data.json.gz. Release dashboard-data-20261006 (#202, 9ce4ade8) rewrote that run, so the scripts no longer regenerate their evidence. Three non-engine scripts in the same audits read the run the same way, and this PR pins those too.

No committed evidence, proposal, reference, exclusion or score changes. The diff touches seven scripts, four READMEs and one new test file.

The bug, reproduced

I ran every unmodified script in two scratch clones of main (4db91b5f):

Script On main With the run from 8b4c0ca1
2026-10-05/…/leaderboard_impact.py exit 1: duplicate exclusion for ('scenario_022', federal …). #202 installed all three records. reproduces all 3 files
2026-10-05-louisiana/…/leaderboard_impact.py exit 0, rewrites both files: every option scores eight fewer outputs (1,920 instead of 1,928; 1,918 instead of 1,926 for exclude), and the top-five orders and rank changes move reproduces both files and the log (its stdout)
2026-10-05-medicare-part-b/…/leaderboard_impact.py --weights-check exit 1: duplicate exclusion for scenario_114 state reproduces all 3 files
2026-10-05-payroll/…/leaderboard_impact.py --with-salt exit 1: duplicate exclusion at the salt copy reproduces all 11 files
2026-10-05/…/propose_exclusions.py exit 0, rewrites proposed_exclusions.json as "0 proposed, 5 already excluded" reproduces
2026-10-05-medicare-part-b/…/propose_exclusions.py exit 1: already-excluded outputs moved reproduces both files
2026-10-05-payroll/…/model_answers.py exit 0, rewrites model_answers.csv: scored flips to False on the four outputs' 184 rows, and no other column changes reproduces both files
2026-10-05-payroll/…/propose_changes.py reproduces reproduces (it never reads the run, so it is unchanged here)

The eight records #202 installed are exactly these audits' records: SALT's three, Part B's Virginia record and payroll's four.

The fix

Each script now has one INPUTS table, {repo path: (commit, sha256)}, with an entry for every file it reads from the repository:

  • The run. Pinned at 8b4c0ca1: payload, predictions, references, sidecars, exclusions and scenarios. Part B also pins analysis/impact_summary_by_model.csv, and its proposals also pin app/src/modelMeta.ts.
  • The audit's own inputs. Pinned at 9ce4ade8, the squash merge that brought these directories in: proposals, sweep CSVs and JSONs, and the classification.

How the scripts read them:

  • git_input() / git_bytes() read each file with git show <commit>:<path>, and stop with SystemExit unless the bytes match the pinned sha256. The impact scripts stage every input under <scratch>/pass_inputs/<path> before anything else, and read only that copy. The other three scripts check every pin before they read or write anything.
  • --out-dir writes the evidence elsewhere; the default is unchanged. The impact scripts also refuse a --scratch that overlaps the repository, whether inside it, equal to it or containing it, because pass_inputs() and stage() delete and recreate scratch/<name>. The guard, overlaps(), compares filesystem identity (device and inode), so a link or another spelling of case cannot hide an overlap. Pin the reference adversary's leaderboard impact to the pass's inputs #205's guard rejects only the inside case.

#191's SALT records: the payroll script used to read them with an unchecked git show 8af912a0:…. 8af912a0 is #191's head, which exists only on its closed branch, not on main. #202 merged the same bytes (sha256 3c330177…), so the script now reads them from 9ce4ade8. leaderboard_impact.json still records salt_commit: 8af912a0. Part B's committed copy of those records is pinned to the same sha256, and a test checks that #191's head holds those bytes whenever the branch is fetched.

The scoring code (policybench, and scripts/freeze_snapshot.py for Part B) is still the checkout's. Each impact script's published-reproduction check, and the slow test, catch drift there.

READMEs. Each audit gains a "Pinned inputs" section: a table per script with every input, its commit and its full sha256, generated from the scripts' INPUTS. It also says what the unpinned script did on #202's run, and gives the reproduce commands.

Corrections in the touched sentences:

  • Step text that listed a leaderboard_impact.log for SALT, Part B and payroll is fixed; none of those logs was committed.
  • Part B's "1,928 today" now names the release it scored.

Tests (tests/test_reference_audit_pins.py)

  1. Coverage. Each script's pins are exactly the set of files it reads, at the expected commit, and each matches git show. The impact scripts stage exactly those files and remove stale files. The payload is the README's 46 models × 1,928 scored outputs.
  2. Differential. Every input shared between scripts has the same pin everywhere. The payload pin equals PAYLOAD_SHA256 in the adversary's definition_conformance.py and publication_sources.py. The SALT records are one sha256 across four pins and equal Audit the state income tax withheld in federal SALT; propose three exclusions #191's head (skipped if 8af912a0 is not fetched).
  3. On main. Every pinned commit is an ancestor of HEAD, so no pin depends on a branch that may be deleted.
  4. Property (Hypothesis, 80 examples). Flipping, truncating or extending any pinned input of any script is refused, and nothing is returned or written. The unchanged bytes are accepted.
  5. Refusal. For every input of every script, a wrong pin stops the script before it scores or writes, and the out dir is never created. Also refused:
  6. Junk checkout. A git clone --shared --no-checkout in which every input path is junk and every other file is absent, except the script itself (and Part B's scripts/freeze_snapshot.py). The test loads the script from that clone and runs it from inside the clone, with argv[0] naming the clone's copy. So ROOT, HERE and relative paths all point into the junk.
    • Each impact script runs with only analyze (the analyze CLI) stubbed. Every copy starts from the pinned bytes, and each variant changes only the files its records touch (exclusion record, or reference CSV and sidecar). The script writes exactly the committed file names. Every summary field computed from the inputs alone equals the committed one. That includes the always-zero baselines and Part B's legacy impact summaries, whose helpers run for real.
    • The three direct scripts run for real from that clone and reproduce every committed file byte for byte. This needs no mocks and takes a few seconds, so CI runs it.
  7. @slow. Each impact script really runs from this checkout, whose run is Stop scoring eight tax outputs and date the response window from the last answer (release dashboard-data-20261006) #202's, and must reproduce every committed file byte for byte; for Louisiana that includes the stdout log. This takes about six minutes in total, so CI deselects it.

Results, all on this branch (outputs saved under ~/reviews/policybench-impact-pins-1005/tests/):

Test runs use a self-cleaning scratch directory rather than tmp_path, which pytest would keep for three runs (about 2 GB).

Invariants

  • Pinned inputs. Every byte a script scores, compares or writes from equals the pinned bytes, whatever the working tree holds. Covered by tests 1, 4 and 6.
  • Refusal before use. A mismatched input stops the script before any scoring or write. Covered by test 5.
  • Reproduction. A regeneration equals the committed evidence byte for byte. Covered by tests 6 and 7.
  • Variant isolation. The published copy is byte-identical to the pins, and each variant changes only the files its records touch. Covered by test 6.

Release interplay

No file the Haiku 5.5 release pins is touched. That release has since merged as #208 (dashboard-data-20261010, policyengine-us 2.38.6) and rewrote the run again. This branch is rebased onto it, and the slow regenerations pass from that checkout. #208 only added reference_audit/2026-10-05-louisiana/proposed_exclusions.json in these directories, which this PR leaves alone. Nothing in 2026-10-05-reference-adversary/ changes. #207 moves that audit's pins into scripts/pass_inputs.py; the cross-check test reads either form, so #206 and #207 can merge in either order.

Review

  • Round 1 (GPT-6.1 Sol via Subfleet, at 0fbcba80): REQUEST_CHANGES.

    • Should-fix: the scratch guard let through a directory containing the checkout.
    • Should-fix: the junk-checkout tests rebased only ROOT, so a read through HERE escaped.
    • Nit: mocked helpers hid their reads.
    • Nit: a Louisiana count was wrong.

    All four are fixed in 8e97a320.

  • Round 2 (at 8e97a320): REQUEST_CHANGES.

    • Should-fix: on a case-insensitive filesystem, a parent spelled in another case passed the lexical guard.
    • Should-fix: the junk-checkout tests still ran from the real checkout, so reads relative to the working directory escaped.

    Both are fixed in d66e02a2.

  • Round 3: pending.

Out of scope

axiom: n/a: audit tooling; no policy encoding changes.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
policybench-site Ready Ready Preview Oct 10, 2026 12:25pm UTC

Request Review

MaxGhenis and others added 5 commits October 10, 2026 07:16
The leaderboard_impact.py scripts in reference_audit/2026-10-05,
2026-10-05-louisiana, 2026-10-05-medicare-part-b and 2026-10-05-payroll
read the frozen run from the working tree. Release dashboard-data-20261006
(#202) rewrote it, so on main three of them stop on duplicate exclusions
and the Louisiana one exits 0 after rewriting both of its evidence files.

Each script now stages every input it reads with git show at the pass's
commit (the run at 8b4c0ca, the audit's inputs at 9ce4ade), checks a
pinned sha256, and reads only the staged copy. --out-dir writes the
evidence elsewhere, and --scratch must lie outside the repository.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es' inputs

reference_audit/2026-10-05/scripts/propose_exclusions.py,
2026-10-05-medicare-part-b/scripts/propose_exclusions.py and
2026-10-05-payroll/scripts/model_answers.py also read the frozen run from
the working tree. On the run #202 left, the SALT proposals exit 0 with no
proposals, the Part B proposals stop on already-excluded outputs, and the
payroll answers flip the scored column on 184 rows.

Each now reads every input with git show at the pass's commit, checks
every pin before reading or writing anything, and takes --out-dir. The
tests (renamed tests/test_reference_audit_pins.py) rerun all three from a
checkout whose working tree is junk and require the committed files byte
for byte. Each audit's README lists every pinned input with its sha256.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… junk checkout

- The four impact scripts refuse a --scratch that contains the repository,
  not only one inside it: pass_inputs() and stage() delete scratch/<name>,
  so --scratch /tmp with the checkout at /tmp/pass_inputs/... deleted it.
- The junk-checkout tests now load each script from the junk checkout, so
  HERE and ROOT both point there; a read through HERE no longer escapes.
- They run always_zero and Part B's legacy impact summary for real on the
  staged copies, and require the committed always-zero baselines and legacy
  summaries, so reads inside those helpers are covered too.
- Tests use a self-cleaning scratch directory instead of tmp_path, which
  pytest keeps for three runs (about 2 GB here).
- Louisiana's README: the exclude option scored 1,918 instead of 1,926.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s in the junk

- The impact scripts' overlap guard compares device and inode instead of
  path spelling, so a parent spelled in another case on a case-insensitive
  filesystem (or reached through a link) is refused too.
- The junk-checkout tests chdir into the junk checkout and pass its copy of
  the script as argv[0], so a read relative to the working directory no
  longer reaches the real checkout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds land in the junk

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis merged commit 2c74e8a into main Oct 11, 2026
5 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Squash-merged as 2c74e8a2, pinned to head 0bcbba285868132989c9338a6ac43383e2c9e65c:

This branch was successfully deployed

1 active deployment
Preview — 0bcbba28 Deployed Oct 10, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant