Skip to content

Check statutory resumption after a freeze: Budget reform contract 2.0.0 (cos d1344) - #627

Merged
MaxGhenis merged 7 commits into
mainfrom
w1-d1344-statutory-resumption
Oct 17, 2026
Merged

MaxGhenis merged 7 commits into
mainfrom
w1-d1344-statutory-resumption

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #626

Status: policyengine-uk#2423 is merged and released (2.134.9, now 2.135.0).

Why this merges before certification, not after: under contract 1.1.0, main's contract today, the projected 2034 allowance check gates. It fails on every release with #2423 (2.134.9 and later), which resume from the frozen amount by statute. So those releases can only qualify under 2.0.0.

The gate tests need a real full run on the certified dataset (CERTIFIED_SHA), not a ledger-certified model, so this PR carries one on released 2.135.0. Policyengine-uk 2.130.1, still pinned, returns to current law's path after a freeze, so it fails the new 2034-35 checks: 13,630 where 12,830 is expected. That's correct, and once 2.0.0 is in, the qualification pipeline qualifies the newest release against it.

The call (cos d1344)

Max delegated the Budget CI plan's methodology calls to the workstream sessions on 2026-10-15 (d1344). Each needs an independent review to agree and its basis recorded. The call and its basis are in policyengine-uk#2423. In short:

  • Thresholds indexed from their own previous year (the personal allowance, the basic rate limit and the NICs thresholds aligned with them) resume indexation from the changed amount after a change ends.
    • ITA 2007 s57(3) Step 1 multiplies "the allowance … for the previous tax year".
    • s21(3) Step 1 increases "the basic rate limit for the previous tax year".
    • Finance Act 2021 s5 freezes by fixing the amount and disapplying the indexation for named years.
    • Contract 1.0.0's reading, returning to the path the threshold would have taken without the change, has no statutory basis.
  • Amounts uprated from an index (benefit rates) return to their uprated path, as before. Temporary changes to them are period-limited modifications (SI 2020/371 reg 3, the 2020 UC uplift).

What changes

  • CONTRACT_VERSION is 2.0.0 and PRIOR_LAW_OPTION is statutory. The module docs record the call and its basis.
  • extended_freeze: the projected 2034 check and the two pending d1344 checks (six rows across the country routes) are replaced by gating checks for 2034 and 2035. They cover the personal allowance, basic rate limit, LPL, UPL, PT and UEL, each indexed or aligned from the frozen amounts with current law's September CPI rise. Each year also gets an income tax change check, which runs on the wrapper routes too.
  • Sampled property: expected_annual gives the allowance the statutory oracle. Years a change covers take its value, years to 2030-31 take current law, and later years are s57 applied to the year before.
  • No check waits on d1344. A test enforces this. The only pending checks are main's CGT default-response checks, which wait on policyengine-uk#2396 (DEFAULT_RESPONSE_DECISION, from CGT-602).
  • Row fixture: tests/fixtures/uk_contract/evaluate_case_rows.json is recorded again from the merged runner. Against main's, only extended_freeze rows differ: 22 removed (among them the six pending d1344 checks on each country route) and 132 added, 40 of them unsupported rows on routes that can't read parameters. Against this branch before the merge, only main's CGT and blended-rate rows differ.
  • Full-run fixture for the qualification gate: full_released_uk_2.135.0.json replaces full_released_uk_2.130.1.json, the 1.1.0 run.
    • The run: contract 2.0.0 at f1f2431 on policyengine-uk 2.135.0 and core 3.33.0, every route, seed 0, max_examples=20, with population checks on the certified enhanced_frs_2024_25 (SHA-256 056e80fd…).
    • Result: it holds, with 881 pass, 0 fail, 0 error, 19 pending (#2396) and 119 unsupported. Both properties pass, and all 19 population rows pass.
    • Privacy: it has no count from 1 to 9 (the runner suppresses them since Apply the small-cell rule and flat findings to the Budget contract's population rows #643), and its population details are identical across the country routes. The dataset path is a placeholder, and the keys are sorted.
    • Later changes: Import the UK model module directly in the contract's household route #651 changed only how the household route imports the UK model, with the output identical row for row (its review), so the run stands for the merged head.
  • Gate tests:
    • RELEASED_COUNTS and the full-run summary assertion use the new counts.
    • Three tests relied on 1.1.0 listing the 2034 allowance check twice, once gating and once pending d1344. Two now swap 2.0.0's gating freeze check with a still-pending check, and replace one with a copy of the other.
    • That duplicate was also the only real data driving the gate's resolution of rows that share a label (by assertion id, else by oracle and declaration order). So 12 tests, written by the round-2 reviewer, declare a second, pending check on the 2034 allowance on top of the real runner and its real 2.0.0 run. They kill the three mutants of that branch that survived the fixture swap, and also pin a pending assertion reported as pass and an id with another oracle.
    • The gate rejects every swap and duplicate (probed: gating→pending, pending→pass, both, and each duplicate). The fixture README is updated.

Tests

Locally on the merged head: the contract, gate and qualification test files (test_uk_budget_reform_contract.py, test_uk_candidate_gates.py, test_uk_qualification_pipeline.py, test_qualification_contracts.py, test_uk_qualification_workflow.py) pass, 924 passed. ruff is clean. New contract tests:

  • worked examples for the statutory allowance oracle (15,000 → 15,300 → 15,610, and 12,570 → 12,830 after the frozen years);
  • the extended freeze's expected values (12,830 / 38,500 in 2034, 13,090 / 39,300 in 2035, PT 246.73, UPL 51,330);
  • no check waits on d1344, and only the default capital gains response waits at all.

Contract 2.0.0 against two models, run locally on this branch:

Model extended_freeze, sampled properties (10 examples) Result
policyengine-uk#2423 source (38288c1f6) every route, both properties holds: 248 pass, 0 fail, 0 error, 0 pending, 61 unsupported; both properties pass on 10 examples
policyengine-uk 2.130.1 (today's model) country routes, no properties fails: 42 rows, e.g. 2034 personal allowance 13,630 where 12,830 is expected, basic rate limit 41,000 where 38,500 is

So the new checks catch the old reading and pass the new one.

🤖 Generated with Claude Code

MaxGhenis and others added 3 commits October 15, 2026 06:42
…s d1344

Fixes #626. The six pending d1344 rows (the 2034-35 personal allowance and
basic rate limit after a freeze to 2033-34) become gating checks against
ITA 2007 s57(3) and s21(3) applied to the frozen amounts, with the aligned
NICs thresholds and the income tax change in 2034 and 2035. The sampled
property's oracle indexes the allowance from the year before after a
change (years to 2030-31 as Finance Act 2021 s5 states them). Uprated
amounts keep returning to their uprated path (SI 2020/371 reg 3).

The row fixture is recorded again; only the extended freeze's rows
changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The independent review of policyengine-uk#2423 found that freezes of
uprated amounts resumed from the frozen amount (WRWA 2016 s11), so the
contract no longer presents its unchanged reading for them as decided.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 4 commits October 16, 2026 19:53
The contract keeps 2.0.0's statutory prior law and gating extended-freeze
checks, and takes main's default capital gains response, whose checks
wait on policyengine-uk#2396. The evaluate_case fixture is recorded again
from the merged runner: against main it differs only in the extended
freeze's rows (132 gating rows for 18 pending ones), and against this
branch only in main's capital gains and blended-rate rows.

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

The gate tests read a real full run of the runner, and fail rather than
skip when the contract version moves past it. This one ran contract 2.0.0
on policyengine-uk 2.135.0 (with the d1344 statutory resumption) and the
certified enhanced_frs_2024_25: 881 pass, 19 pending policyengine-uk#2396,
119 unsupported, holds. It has no count from 1 to 9 and its population
details agree across routes. Two gate tests that relied on 1.1.0's
duplicated freeze check now swap the gating freeze check with a pending
one; the gate still rejects every such swap and duplicate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contract 1.1.0 read the 2034 allowance twice, so its full run drove the
gate's resolution of same-label rows (by assertion id, else by oracle and
order); 2.0.0 reads it once, and three mutants of that branch survived
the fixture swap. The tests now declare a second, pending check on the
2034 allowance on top of the real runner and its 2.0.0 run, and pin a
pending assertion reported pass and an id with another oracle. Tests
written by the round-2 reviewer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 17, 2026 14:44
@MaxGhenis
MaxGhenis merged commit cbd6c5f into main Oct 17, 2026
12 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merge audit (W1, session local_37646626): merged at d2af337, pinned with --match-head-commit. The merge commit is cbd6c5f.

  • CI: gh pr checks exited 0, with all 12 checks passing (Test 3.11–3.14, Lint, Mypy, smoke-import, changelog, release inputs). The PR was MERGEABLE and CLEAN, and not a draft.
  • Reviews: they are in ~/reviews/w1-budget-reform-contract-2026-10-11/.
    • GPT-6.1 Sol approved the contract change at e7babc3 (review-runner-d1344-out.md).
    • An independent Opus 5.5 review covered everything since (the Codex lanes were closed). Round 2 (review-runner-r2-out.md) re-ran the whole contract on policyengine-uk 2.135.0 with the certified dataset and matched the fixture. It asked only for the same-label gate tests, which are in. Round 3 (review-runner-r3-out.md) approved d2af337.
  • No CHANGES_REQUESTED review is outstanding.
  • Methodology: cos d1344, decided by W1 under Max's delegation of 2026-10-15, with independent agreement. The basis is in policyengine-uk#2423 and this PR's body.
  • Effect:
    • Contract 2.0.0's statutory freeze checks now gate.
    • policyengine-uk releases from 2.134.9, which resume indexation from the frozen amount, can qualify.
    • 2.130.1, still pinned, would fail them, as intended.
    • The qualification gate's fixture is the real 2.0.0 run on 2.135.0.

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.

Budget reform contract 2.0.0: resolve the six pending d1344 checks with statute

1 participant