Skip to content

Tool v3: calculator features one at a time, for the ablation pilot - #243

Merged
MaxGhenis merged 9 commits into
v2-microcosm-batchesfrom
v2-microcosm-toolv3
Oct 24, 2026
Merged

MaxGhenis merged 9 commits into
v2-microcosm-batchesfrom
v2-microcosm-toolv3

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #240. It merges into v2-microcosm-batches now that the cheap batch 1 and the free-plan run, which both ran from that branch at 5bbd571, have finished (2026-10-24 05:31Z and 05:42Z).

What

The calculator's features become independent switches, so a study can change one at a time. Max, 2026-10-23: "measuring this as an experiment could be publishable", "do all these tests with a cheap model", "and tool v3".

feature what it does
names a name with spaces, or a benchmark output key, is read as its engine variable (tool v2)
labels a fact under any label the prompt shows it under (built from the prompt's own renderer: "gross wages and salaries", "usual weekly hours worked", the v2-pilot relabelings, the Marketplace plan line, names with spaces) is read as its variable. Stated hours are also set where the reference sets them (PE_INPUT_ALIASES), and facts the reference drops (PE_DROPPED_INPUTS) are ignored with a note
placement an input set on another entity moves to the one unit holding its people (tool v2)
overrides a realized contribution is read as _desired, and an input that replaces a formula is flagged (tool v2)
explain explain traces up to three variables (tool v2)
concise explanations are brief unless detail is "full"
flat the model describes household (state, people with role and facts, household facts), and the tool builds the units Scenario.to_pe_household builds

Arms: pe2 is unchanged (names, placement, overrides, explain), pe3 is all seven, and any other set is pe: + features, e.g. pe:names+flat.

Finding behind labels

The prompts label several facts in words, not as the variable name with spaces. Nearly every test household has at least one: hours appear in 17 of 20, employer coverage and premiums in 11 each.

  • Tool v2's names feature can't read these labels.
  • Its notice says the facts carry the engine's variable names.
  • A Flash-Lite smoke run fell back to employer_sponsored_insurance_premiums: 0 and weekly_hours_worked, and the SNAP work rules don't read the latter.

pe2 keeps that text because it ran with it; no other feature set says it.

Review round 1 (GPT-6.1 Sol, REQUEST_CHANGES, 7 findings): fixed in 6478e8f

  1. Model arguments could switch on features their arm doesn't offer. The worker read __tool_features__ (and, as at 5bbd571, __tool_version__) from the arguments. Pools now send features in a tuple frame that no JSON can produce. Workers validate the frame, and such keys in a model's arguments are refused. No run record ever carried them.
  2. A resume could mix treatments. Records now keep their tool features and calculator-schema hash, and a resume compares features, notice and schema.
  3. Labels missed rendered labels. The index is now built from the prompt renderer for every promptable, labeled and reference-stated input. Dropped facts are ignored, and a label that names two inputs isn't read.
  4. Person-level keys in flat. Keys other than name, role and facts are refused.
  5. Flat merged facts before normalizing. Facts are now placed under the name written and compared once normalized. Roles set the relationship inputs, and a stated relationship that contradicts its role is refused.
  6. Descriptions. They now promise only what each feature does.
  7. Diagnostics. They read people by the flat format's default names.

Review round 2 (GPT-6.1 Sol, REQUEST_CHANGES, 2 minor findings): fixed in d570b8e

All seven round-1 findings were confirmed resolved.

  1. A malformed repeat of a household fact was dropped silently. It now reports its validation problems, and only a repeat validated as equal is dropped quietly. A malformed first value is reported once, never as a conflict.
  2. One harness failure blocked a custom-arm resume. The fallback record (harness_error_record) now carries the notice hash and treatment. The resume check (resume_treatment_problems) looked only at records the resume keeps, on the view that a rerunnable record is replaced under the current profile; round 3 showed it need not be.

Review round 3 (GPT-6.1 Sol, REQUEST_CHANGES, 1 major finding): fixed in 6b00a6f

Both round-2 findings were confirmed resolved.

  1. A rerunnable record from another treatment could survive a resume and be scored. A budget stop, lost workers or a narrower --scenarios leave it in place, and score did no treatment check. Now treatment_problems checks every record in the folder, rerunnable ones included, and command_score refuses a folder that mixes treatments, rebuilding the expected notices on the board's engine.

One allowance at score, not at resume. Before 6e1578f, the tool notice and the calculate description always named policyengine-us 2.41.0, whatever engine ran. Test batch 0's frontier calculator arms (b6d835a) were told 2.41.0 while computing on 2.60.4, as every run manifest shows.

  • A folder written wholly under that text is one treatment and scores with a note.
  • A mix of the two texts is refused.
  • A resume into such a folder is refused, since its new records would state the board's engine.

Across all 39 run folders (660 records, free batch 1 included), score refuses none; the six frontier calculator folders take the note.

Review round 4 (GPT-6.1 Sol): AGREE at 6b00a6f

The round-3 finding is resolved, and there are no new findings. Sol re-ran the round-3 counterexample: a resume now refuses it before scheduling, including with lost workers or a narrower --scenarios, and score refuses it before analysis.

Two qualifications on how the score allowance is described:

  • It applies when some record fails on the board's engine and none fails on the reference engine.
  • It checks the recorded treatment, not the commit a record came from. So a synthetic post-6e1578fc record written with the reference engine's text would pass.

Neither gives a mixed-treatment bypass. Sol also found stating_engine sound under nesting and exceptions, hashless legacy records still accepted, and the hard-constraint reading sound: the guards restrict orchestration and change no request or calculation.

Invariants

  • pe, web+pe and pe2 behave exactly as at 5bbd571 (the commit the test batches ran). A Hypothesis differential ran 4,000 generated calls through versions 1 and 2. Requests, errors, notices, descriptions, schemas and 15 model profiles are identical.
  • Flat equals the benchmark's own situation. On policyengine-us 2.60.4, 8 frozen-board households described flat, and 12 with each fact written as the v2-pilot prompt writes it, compute every board output exactly as Scenario.to_pe_household does.
  • Each feature changes only its own behaviour. Per-feature unit tests; across all 95 valid feature sets, only pe2's notice makes the variable-name claim.
  • Labels alone reproduce the reference from the prompt's facts. Each household is built from what its prompt shows, under the labels shown, with the labels feature alone. Every board output equals the reference situation's: 30 frozen households in the test suite; all 100 frozen and all 20 test-set households in a one-off run; with or without take-up inputs.
  • Worker equivalence. pe and pe2 pool messages are read as 5bbd571's worker read them (2,000 generated). The intended exception is that forged metadata keys are refused.
  • pe, web+pe and pe2 send the same texts as 5bbd571 on this board's stated engine (2.60.4). 2 schemas and 18 profiles are identical. A teeth check fails, as it must, when 5bbd571 is left on 2.41.0.
  • One treatment per scored folder. Score refuses any folder whose records don't all match the arm's treatment on the board's engine, with one exception: a folder written wholly under the pre-6e1578fc text. A resume refuses any mismatched record.
  • Mutants. 32 hand mutants of the features and the review fixes are all caught: 19 for the features and round 1, 5 for round 2, 8 for round 3.

Status

  • Tests: 210 passed, 4 skipped (frozen-engine only) at 6478e8f
  • Review round 1: REQUEST_CHANGES, 7 findings, all addressed in 6478e8f
  • Review round 2 (GPT-6.1 Sol): REQUEST_CHANGES, 2 minor findings, both addressed in d570b8e (fb35d82 formats)
  • 5bbd571 differential rerun at d570b8e: identical (4,000 calls, 2,000 pool messages)
  • Full suite at fb35d82: ruff check and format clean; 214 passed, 4 skipped (gated on policyengine-us 2.41.0), 5 deselected (the round-2 selection)
  • Review round 3 (GPT-6.1 Sol): REQUEST_CHANGES, 1 major finding, addressed in 6b00a6f
  • 5bbd571 differential rerun at 6b00a6f: identical (4,000 calls, 2,000 pool messages); stated-engine comparison identical (18 profiles)
  • Full suite at 6b00a6f: ruff check and format clean; 218 passed, 4 skipped (gated on policyengine-us 2.41.0), 5 deselected (the round-2 selection). CI runs only on PRs into main, so this local run is the suite evidence.
  • Review round 4 (GPT-6.1 Sol): AGREE at 6b00a6f
  • End-to-end Flash-Lite pe3 smoke run through real workers: 0 tool errors on 3 households (first smoke run: 7)
  • Ablation pilot: 15 arms × 3 cheap models × 20 households, from a detached checkout of 6b00a6f (run_cheap_ablation.sh in the run folder). Batch 1, the free run and the review are done. It waits for the host: not before Route A's r3 window (route-a-release-d1811-r3) releases.
  • Batch 1 and the free-plan run finished; merging into Run v2 on fresh Microcosm households in judged batches #240's branch

No published number changes; this is the unpublished tool pilot.

🤖 Generated with Claude Code

MaxGhenis and others added 5 commits October 23, 2026 17:11
The calculator's six features (names, placement, overrides, explain,
concise, flat) are each on or off, so a study can change one at a time.
"pe2" keeps tool version 2 (the first four, its notice byte for byte),
"pe3" offers all six, and any other set runs as "pe:" plus its features,
e.g. "pe:names+flat".

- concise: an explanation gives the value, its direct inputs and up to
  five parameters unless `detail` is "full".
- flat: the household is described as a state, people with a role (head,
  spouse or dependent) and facts, and household facts; the tool builds the
  units the benchmark's own situations have and places each household
  fact on its entity.

Tests: the v2 notice is reproduced from its features; each feature adds
only its own behavior; flat builds the benchmark's units and refuses what
it cannot place; and on the installed engine eight frozen-board
households described flat compute every board output exactly as
Scenario.to_pe_household does. Five mutants of the flat and arm logic
are all caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The prompts label some facts in words rather than as the variable name
with spaces: employment_income is "gross wages and salaries",
hours_worked_last_week "usual weekly hours worked", has_esi "has
employer-sponsored insurance" (policybench.prompts.INPUT_LABEL_OVERRIDES).
In the 20-household test set nearly every household has at least one;
hours appear in 17, employer coverage and premiums in 11 each. Tool
version 2's names feature cannot read these, and its notice says the
facts carry the variable names. A Flash-Lite smoke test of the flat
format met three such errors and fell back to setting
employer_sponsored_insurance_premiums to 0 and weekly_hours_worked,
which the SNAP work rules do not read.

The new labels feature reads a fact under its prompt label (case and
punctuation aside, renames applied) and, as the reference situations
do, also sets stated usual weekly hours as weekly_hours_worked_before_lsr
(PE_INPUT_ALIASES). pe3 now offers all seven features. pe2 is unchanged
and keeps its notice as it ran; every other feature set's notice says
only what the tool reads.

Tests: label reading, the alias (and leaving a set value alone), pe2
unchanged, the variable-name claim only in pe2's notice across every
feature set, every prompt label reading back to its engine name, and a
differential: twelve frozen-board households described flat with each
fact as its prompt writes it compute every board output as the
benchmark does. Three mutants (no alias, no renames, strict label
matching) are caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v2-pilot prompt relabels two facts itself ("home energy assistance
received" for spm_unit_energy_subsidy, "employer-paid health insurance
premiums ..." for employer_sponsored_insurance_premiums); the labels
feature now reads them, derived from V2_PILOT_CONVENTIONS so the two
stay in step. In the flat format a person given no name is named by
role (head, spouse, dependent_1, ...): Flash-Lite's first flat call in
two smoke households left the names out.

The label differential now writes each fact as the v2-pilot prompt
does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two of three Flash-Lite smoke households gave the head's rent as a
household fact. pre_subsidy_rent is a person variable in policyengine-us,
so the flat format refused it. Under the placement feature a person fact
given for a household of one now goes to that person, as placement moves
a person variable off a one-person unit; with two or more people it is
still refused, now saying to give it under the person whose facts list
it. The test registry's entities now match the engine's
(pre_subsidy_rent is a person variable).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A differential against 5bbd571 (the commit the test batches ran) found
version 2 requests carrying detail "full"; only execute_request reads
it, through .get, so results were unchanged, but the request now matches
exactly. 4,000 generated calls through versions 1 and 2, the notices,
descriptions, schemas and 15 model profiles are identical to 5bbd571.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 23, 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 24, 2026 5:31am UTC

Request Review

GPT-6.1 Sol's review (REQUEST_CHANGES, 7 findings) at 9c43f4f:

1. A model's arguments could turn on features its arm does not offer:
   the worker read "__tool_features__" (and, as at 5bbd571,
   "__tool_version__") from the arguments dict. A pool now sends features
   in a tuple frame no JSON can be, the worker validates them (names,
   concise beside explain), and keys like "__tool_version__" in a model's
   arguments are refused as unknown arguments. No run record ever
   carried them.
2. A resume could mix treatments. Each household record now keeps its
   tool features and calculator schema hash; a resume compares
   features, notice and schema, and refuses a non-legacy record without
   them.
3. Labels missed what the prompt renders. The label index is now built
   from the prompt's own renderer (_format_input_line, then v2_pilot_text)
   for every promptable, labeled and reference-stated input: fallback
   labels, the Marketplace plan line, "state", partnership or S-corp
   income. Facts the reference drops (PE_DROPPED_INPUTS) are ignored with
   a note. A label that names two of the engine's inputs is not read.
4. Flat refuses person keys other than name, role and facts.
5. Flat stores household facts under the name written, so normalization
   compares them once normalized; roles set the relationship inputs and
   a stated one that contradicts its role is refused.
6. The flat example uses employment_income; placement replaces the
   wrong-entity error sentence; "full" detail is the trace, capped.
7. Diagnostics read flat people by their default names.

Evidence: 210 passed, 4 frozen-engine skips. A labels-only differential
builds 30 frozen households from their prompts' facts and matches the
reference situation on every output, and so do all 100 frozen and all
20 test-set households in a one-off run, with or without take-up inputs.
pe and pe2 are identical to 5bbd571 over 4,000 calls and 2,000 pool
messages. 11 mutants of the fixes are caught. An end-to-end Flash-Lite
pe3 smoke run had 0 tool errors on 3 households.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- flat: a household fact repeated with a malformed value was dropped
  without a word. _same_value now reports the repeat's validation
  problems, and only a repeat validated as equal is dropped quietly. A
  malformed first value is reported once, by normal validation, and
  never as a conflict.
- The fallback record for a household the harness failed on carried no
  treatment, so one failure blocked resuming any custom arm. The record
  is built by harness_error_record, which now includes the notice hash
  and profile_treatment. resume_treatment_problems checks only the
  records a resume keeps, since a rerunnable record is replaced under
  the current profile.

pe, web+pe and pe2 still behave exactly as at 5bbd571: 4,000 calls and
2,000 pool messages match. 5 mutants of these fixes were all caught.

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

A rerun is not sure to replace a rerunnable record: a budget stop, lost
workers or a narrower --scenarios leave it in place, and scoring read
whatever was there. treatment_problems now checks every record in the
folder, rerunnable ones included, and command_score refuses a folder that
mixes treatments, rebuilding the notices on the board's engine.

Runs written before 6e1578f (test batch 0's frontier calculator arms,
b6d835a) were told policyengine-us 2.41.0 while computing on 2.60.4. A
folder written wholly so is one treatment and scores with a note; a mix
of the two texts is refused, and a resume into it stays refused, since its
new records would state the board's engine. All 39 run folders score
(628 records); the six frontier calculator folders take the note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 24, 2026 05:53
@MaxGhenis
MaxGhenis merged commit 5d807bb into v2-microcosm-batches Oct 24, 2026
2 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged at the reviewed head 6b00a6f with a merge commit (5d807bb), so the reviewed commits stay reachable from #240's branch.

Reviews (GPT-6.1 Sol on Subfleet, review/hard):

Evidence: the full suite at 6b00a6f (218 passed, 4 skipped, ruff clean); the 5bbd571 differential (4,000 calls, 2,000 pool messages identical); the stated-engine comparison (18 profiles identical); the 39-folder treatment check (660 records, none refused by score). The ablation pilot waits for the host after Route A's r3 window.

This branch was successfully deployed

1 active deployment
Preview — 6b00a6f0 Deployed Oct 24, 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