Repository navigation
Apply the small-cell rule and flat findings to the Budget contract's population rows - #643
Merged
Merged
Conversation
…population rows No population row now reports a count of survey records from 1 to 9 (it reads "fewer than 10") or a total over fewer than 10 changed records, and each row states every condition it tests as a top-level true/false finding, so a failed check can be diagnosed from the published findings. Fixes #642. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, and test the findings on random runs The April total is withheld by the records whose tax moved at all, not only those past the counting threshold. publishable_detail raises on a type it cannot check. The informational finding is named no_payment_lower_informational. The docstring says the rule covers counts and totals, not error text or cross-row differences, so the raw report is not for publication; the ledger is the publishing control. The UC differential now draws holding verdicts, from lawful pairs, and a property runs the population checks on random stubbed arrays, lawful responses included, checking every row's findings decide it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… row whose detail cannot be checked A few large changes among negligible ones are still a few records, so the April total is withheld when the changes past the threshold number 1 to 9 as well as when all changes do. A detail publication cannot check makes its row an error instead of raising out of the run. New tests pin routes that disagree only in 2026 and a State Pension that falls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An unreformed rebuild unlike the first fails isolation, and outputs that depend on the order they are asked for fail the query-order check; each verdict forced to pass is now caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as ready for review
October 16, 2026 22:21
Contributor
Author
|
Merge audit (W1, session local_37646626): merged at b02bc59, pinned with
|
MaxGhenis
added a commit
that referenced
this pull request
Oct 17, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #642
Independent review: the third round (Opus 5.5; the Codex lanes were closed) approved ca1345e, in
review-r3-out.md. b02bc59 adds only the two tests that round suggested (below).Reproducer: tests/test_uk_budget_reform_contract.py::test_population_rows_state_each_condition_as_a_flat_finding
Reproducer: tests/test_uk_budget_reform_contract.py::test_publication_removes_every_small_count_and_nothing_else
Reproducer: tests/test_uk_budget_reform_contract.py::test_every_population_row_publishes_the_findings_that_decide_it
Reproducer: tests/test_uk_budget_reform_contract.py::test_a_total_moved_only_by_tiny_changes_in_few_records_is_withheld
Why
The UK Budget reform contract's population checks run on a 1,000-household subsample of a certified survey dataset. Their rows reported counts of records, and totals over them, in
detail. The qualification ledger publishes from these reports, and raw reports are committed as test fixtures. So the rows now follow the small-cell rule the Budget tooling uses elsewhere: never publish a count from 1 to 9, as in W3'ssmall(count) = 0 < count < 10.The qualification ledger (#574) is the publishing control. It publishes only the fixed row fields and the top-level true/false values in
detail. The raw report is not for publication: the rule here covers counts and totals, not an error's message, and not the difference between two rows' figures (two routes' rows share a subsample).This PR does two things:
full_released_uk_2.130.1.jsonand Check statutory resumption after a freeze: Budget reform contract 2.0.0 (cos d1344) #627's refresh, and local runs;W4 asked for both.
What changes
src/policyengine/tax_benefit_models/uk/budget_reform_population.py:publishable_detailreplaces every count from 1 to 9 in a row'sdetail, at any depth, with"fewer than 10". Python and NumPy integers are both covered, and booleans are left alone.TypeErroron any type it cannot check, such as an array, a set or a non-text key, rather than passing it through.run_population_checks, such a row becomes anerrorrow with its detail dropped, so the report does not hold and the run isn't lost.run_population_checksapplies it to every row it returns.2027_total_changereads"withheld: fewer than 10 records"when 1 to 9 people's tax changed at all, or 1 to 9 changed by more than the 1e-6 threshold the published counts use (total_over_records).detailnow states every condition it tests as a top-level boolean:<output>:<year>_matchesper compared output (it was the list of differing names, ornull)income_tax:2026_matches,income_tax:2027_matches(it had no detail)2026_unchanged,2027_total_risesincome_tax:2028_matches(it had no detail)standard_allowance_scaled_10_percent,no_award_lower,payments_are_award_less_deductions,no_payment_below_the_payable_floor,some_payment_higher,no_non_finite_units; plusno_payment_lower_informational, which is not a condition because payments can lawfully fallbasic_and_new_scaled_10_percent,no_pension_lower,some_pension_higherThe counts stay, subject to the small-cell rule, for local reruns with data access.
uc_allowance_verdictstill returns raw counts, and its verdict is nowall(findings).reason. The ledger publishesreason; the message stays indetail.No check, verdict or coverage changes, so
CONTRACT_VERSIONstays 1.1.0. Only the diagnosticdetailchanges, and no gate rule reads it (W4). Contract 2.0.0 (#627) will carry this shape when its full-run fixture is refreshed.Invariants (tested)
test_publication_removes_every_small_count_and_nothing_else), on every row of the stubbed run, and on the two tiny-dataset runs._informationalare excluded.test_every_population_row_publishes_the_findings_that_decide_it). The runs use 1 to 12 units, with and without NaN, and some of them have lawful Universal Credit and State Pension responses, so every country check both passes and fails across the run (asserted).no_award_lowerbeingawards_lower == 0.Mutants, each run against the population tests:
no_payment_lowera condition: caught by the lawful-pair tests;2027_total_risesfrom the April verdict: caught by the random-run property.Tests
tests/test_uk_budget_reform_contract.py:reason.Locally,
test_uk_budget_reform_contract.py,test_uk_candidate_gates.py,test_uk_qualification_pipeline.py,test_qualification_contracts.pyandtest_uk_qualification_workflow.pypass on the head: 700 passed.ruff format --check .andruff check .are clean.Review findings and responses
detailfor diagnosis; the ledger withholds it.publishable_detailnow fails closed.no_payment_lower_informational.test_a_few_large_changes_among_tiny_ones_withhold_the_total).lower == 0:test_a_state_pension_that_falls_fails_the_pension_check.test_routes_that_differ_only_in_2026_disagree.test_a_detail_that_cannot_be_checked_turns_its_row_into_an_error).test_an_unreformed_rebuild_that_differs_fails_isolationandtest_outputs_that_depend_on_query_order_fail_the_order_checknow cover them. Forcing either verdict to pass is caught.🤖 Generated with Claude Code