Repository navigation
Conversation
…into fix/2541-ca-earnings-pence
is_gainfully_employed_for_carers_allowance floored the weekly pence in float32, where the 1e-6 tolerance does nothing near 20,000 pence, so float32 rounding decided cases within about 0.002 pence of a boundary. Earnings of 52 x L + 0.52 a year (a penny a week over) counted as within the 2020-21 to 2024-25 limits of 128, 132, 139 and 151. The formula now takes the stored annual earnings to the nearest penny in float64 (an exact half penny disregarded, reg. 5), spreads them over 52 weeks in whole pence with the fraction disregarded (reg. 5), and compares with the limit in pence (reg. 8(1)). Tests: every limit in earnings_limit.yaml in every year it applies, entered as earnings and as pay; a pounds-and-pence reformed limit; property tests for exact whole-pence judgement, agreement with exact rational arithmetic and monotonicity; YAML cases for 2024-25. The property-test helpers now restate the new rule in Fraction arithmetic. Fixes #2541 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aggregate impact on certified data: passBase Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 0 (thresholds in Notes
Moves flagged for reviewNone. Spending by benefit and service
Caseloads
Standard reform costings (change in gov_balance)
Standard reforms: change in each reform's target
Household net income by decileNo household's net income changes in any year. No change in any year: receipts by tax head; government balance, each component counted once; model totals; household income totals; population; poverty rates; people in poverty; inequality; mean household net income in each side's own deciles. Checks failing on both base and head (1)
Counted-once checkEach of 91 components was raised by £1 per unit in 2026-27, and every head of its totals was read household by household: its own head must rise by exactly £1, no other tax head may move, no other benefit may rise, and the model's own total must move by what its heads moved. A head that breaks a rule is measured again twice: with every other head held at its baseline value, and with every other head held at its value after the first £1 while the component rises again. It fails where either still shows the response. 0 failed; 0 were skipped.
Provenance
Dataset: Receipts by tax head: head levels
Spending by benefit and service: head levels
Caseloads: head levels
Government balance, each component counted once: head levels
Model totals: head levels
Household income totals: head levels
Population: head levels
Poverty rates: head levels
People in poverty: head levels
Inequality: head levels
Mean household net income in each side's own deciles: head levels
Standard reform costings (change in gov_balance): head levels
Standard reforms: change in each reform's target: head levels
|
The #2543 review found that taking stored earnings to the nearest penny misjudges whole-pence pay less half of an odd-pence pension contribution. Net earnings of 52 x L + 0.515 are 52 x L + 0.51 in law, because reg. 5 counts the half penny of the reg. 10(4)(b) deduction as a penny. Float32 holds that value just above the half penny for most limits, so nearest penny counted it up and over the limit, at all ten limits. The formula now takes the nearest half penny (an exact quarter penny down), disregards a half penny, then divides by 52 in whole pence (1996 reg. 8(1)(b)(iii) with reg. 5). np.floor(x / n) replaces // so that infinite earnings stay over the limit. Every whole-pence and half-penny amount below 65,536 pounds is recovered exactly. Tests: odd-pence contributions at every limit in every set year, a Hypothesis property checking pay less half a contribution against the law in integer arithmetic, YAML Cases 23 and 24, float32 values either side of 52L + 0.515 and 52L + 0.5175 as explicit examples, and boundary examples for every #2541 limit. The Fraction references follow the new rule. changelog.d/2532.fixed.md (from #2534) no longer describes this head, so it is removed; the wording fixes the review asked for are included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…into fix/2541-ca-earnings-pence
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
juaristi22
left a comment
There was a problem hiding this comment.
Review status: COMPLETE
Review severity: REQUEST_CHANGES
Reviewed head: a67d545
C1 — Nearest-half-penny rounding can remove the entire allowance for valid self-employed earnings. In is_gainfully_employed_for_carers_allowance.py:61–63, the new step can round computed net earnings upward even when the supplied income and pension inputs are whole-pence amounts.
Executed case: an otherwise eligible 45-year-old carer in England in 2026, providing 40 qualifying care hours weekly, with £14,000.01 self-employment profit, £6,039.38 personal pension premiums, no employed income and no overlapping benefit. No eligibility or intermediate amount is overridden.
Both the current calculation and a prior-formula-only control produce stored net earnings £10,608.517578125. The new formula promotes this to £10,608.52 and pays £0 Carer’s Allowance; reverting only that formula pays £4,495.40.
Computation of Earnings regulation 5 requires fractional pennies to favour the claimant. With regulations 13 and 14, claimant-favourable deductions are £286.01 tax, £85.81 Class 4 and £3,019.69 pension. Annual earnings are £10,608.50, giving £204.00 weekly after disregarding the fraction. This is within the strict 2026 earnings limit, so the £4,495.40 award remains due. Rounding a combined deduction instead leaves £10,608.51 and the same eligibility; even the existing unrounded approximation is below £204.01 a week.
Preserve the whole-pence and odd-pension fixes while ensuring computed off-grid earnings receive claimant-favourable rounding. Add this actual-input regression and update the corresponding bridge/case in queued Axiom issue #482. The disclosed generic approximation does not cover this demonstrated full-award regression, and the prior-formula control isolates this PR's change.
Validation: 66 Python tests and 24 changed YAML cases pass, with no failures or skips. The original interrupted run was recovered with native exit 0; it was not repeated. The additional current/prior diagnostic separately exited 0. Twenty source originals and extracts were checked. Review scope is GitHub's five actual PR files, with the comparison base qualified independently of the shallow local history. No local population run, full suite or proposed repair is claimed.
|
Heads-up on a semantic interaction with #2699 and #2700. There's no file overlap.
Suggested change: take years after the last YAML date from the model, which keeps the "every limit in every year" coverage: def _limits_by_year(last_year):
limits = []
for year in range(LIMIT_VALUES[0][0].year, last_year + 1):
if year <= LIMIT_VALUES[-1][0].year:
limit = [v for date, v in LIMIT_VALUES if date <= datetime.date(year, 4, 30)][-1]
else:
limit = system.parameters(f"{year}-01-01").gov.dwp.carers_allowance.earnings_limit
limits.append((year, limit))
return limitsRestrict the set-equality assertion to 🤖 Generated with Claude Code |
juaristi22's review of #2543 found a trader within the limit whom the nearest-half-penny rule put over it: £14,000.01 of profit and a £6,039.38 premium leave £10,608.5174 unrounded, which the half-penny step took to £10,608.52 (£204.01 a week). Reg. 5 counts a fraction of a penny in each deduction as a penny, giving £10,608.50. carers_allowance_earnings now works in float64 pence from the whole pence each amount was entered as (utils.pence.stored_pence), taking pay and profit down to a whole penny and each deduction (PAYE, Class 1, notional tax, Class 4, Class 2, half of pension contributions) up to one. Net earnings are whole pence, which is_gainfully_employed_for_carers_allowance reads back exactly before dividing by 52. Tests: stored_pence round-trips every whole-pence amount below £131,072 and moves an amount at most half a float32 step; a through-the-model test checks trading and employee net earnings against the law, deduction by deduction, in exact arithmetic, with the review case; YAML Case 25 pins it. The limits test now reads projected limits from the model after the last legislated one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pence # Conflicts: # policyengine_uk/variables/gov/dwp/carers_allowance_earnings.py
|
@juaristi22, thanks. C1 was right, and it went deeper than the half-penny step. Rounding the stored total can't separate whole-pence earnings from genuine fractions of a penny: float32 holds a £14k–£20k profit only to within about a tenth of a penny before tax comes off, so the two overlap. Even a two-step tolerance misjudged 39 of 1,779 traders within 5p of the 2026-27 boundary. So 32f1639 applies reg 5 where the calculation happens, at each step:
Your case is £14,000.01 of profit and a £6,039.38 premium in 2026-27. The deductions are notional tax £286.002, rounded up to £286.01; Class 4 £85.8006, rounded up to £85.81; and half the premium, £3,019.69. That leaves £10,608.50, or £204.0096 a week, which is not over £204, so CA is £4,495.40. It is now covered in three places:
The PR body has the full rule, the sweeps and the wrong-rule checks. rulespec-uk#482's bridge and companion row are updated to match. |
|
Checked: at 32f1639 this merges cleanly onto #2699 (3c19621) and onto #2700 (21f0fa85f). Its CA tests pass on both:
That includes #2700, where the limit rises to £212 from 2027-28. The |
Review of #2543 at 32f1639 (GPT-6.1 Sol lanes closed; Opus reviewer): - Class 1: the model sums twelve float32 months, which can hold a whole-penny total (£175.56) further out than stored_pence recovers, so rounding up deducted a penny too much and put employees exactly a penny a week over the limit within it. carers_allowance_earnings now works the model's Class 1 formula exactly on the year's NI income in whole pence, where it agrees with the stored total to within float32 error, and otherwise reads the stored total. - Pension: read pension_contributions, summing its programmes again in float64 only where the stored total is their float32 sum (stored_sum_pence), so a total entered directly still comes off. - Docs: PAYE and Class 1 rounding is the claimant-favourable convention, reg. 5 governs the calculated deductions; the self-employed weekly amount cites reg. 11(1)(a); CSP reads these earnings too. - Tests: employee-route Class 1 expectation worked exactly, with the review's rows; invariant 3 restated (2p rises never lower net earnings, a 1p rise can, as reg. 5 intends) and checked over every penny across each threshold; entered pension totals; stored_sum_pence; deadline=None on the stored_pence property tests; YAML Cases 26-31 and two CSP cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A float32 sum of the two programmes can lie more than half a step from its pence; read alone, half of it would round up a penny too far. This case fails if stored_sum_pence reads a sum as stored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes the three findings of the review of 8f1df68, and a fourth of the same kind found while fixing them: - Class 1 entered as an input (nil, or any amount near the formula's) was replaced by the formula worked exactly whenever the two lay within float32 error. Class 1 is now worked out again only where the model calculated it with its own formula: no reform changed how it or its parts are calculated, and no month was supplied or stored by a scenario. Otherwise the stored amount is the one deducted (reg. 10(4)(a)). - Sums nested in sums (employee_pension_contributions inside pension_contributions, and employment_income itself) kept float32 noise. amount_pence now recurses through adds/subtracts of amounts the simulation derived, reading each as stored_pence does, and takes their exact sum where the float32 total lies within the rounding of the additions that formed it. Pay is read this way too: 10,276.42 + 1,415.69 is stored as 11,692.109375 and was floored to 11,692.10. - A formula in place of a sum (adds=None) crashed the reader; a variable with a formula, defined_for, another period or another entity's part is now read as stored. YAML Cases 33-36 pin the four executed cases, each a penny a week over the 2026-27 limit; model-level tests pin entered and reformed Class 1, a parameter reform, a formula reform and 1,203 sums the model forms (600 with Class 1, 603 without NI), and the every-year test checks Class 1 against an independent Fraction restatement from 2015 to the horizon. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three of the 22 wrong rules swapped in at 6e8a53f failed no test: - Employee pension contributions read as stored for PAYE. test_sums_the_model_forms_are_read_in_whole_pence gains a PAYE regime: 600 sets of inputs with pay less member contributions over the personal allowance, mostly by a multiple of 5p, so that 20% of it is whole pence and contributions misread by a fraction of a penny change the tax. - The reader's input check removed. A pension total entered as £3,242.6401 is the very float32 that programmes of £1,807.49 and £1,435.15 sum to; only the input check tells them apart, and the entered total is read as entered (£10,608.51, within) where the programmes alone give £10,608.52 (over, CA Case 32). - The reader's formula check removed. policyengine-core refuses a variable with both a formula and adds, so the check could never be true; it is dropped, and a test pins the core behaviour it relied on. The fourth survivor, the Class 1 tolerance backstop, is intended: the exact path restates the model's own formula, so the two can only disagree if one is edited without the other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Heads-up from #2719 (Budget 2026 measures, draft until Budget week ends): its Carer's Allowance taper commit (b5d2d77) moves the weekly-pence step out of 🤖 Generated with Claude Code |
Fixes the r7 review's findings on PR #2543 (refs #2541): - Class 1 entered for the year (which core divides among the months in float32) or month by month was read from the float32 annual sum, so £1.20 (or 12 x 10p) was deducted as £1.21. amount_pence now sums a monthly flow's months exactly (months_summed), recovering a year's whole pence within the rounding of the division; the Class 1 fallback and backstop read it that way. - The exact Class 1 path accepted a reform that ended the primary formula or dated it from 2027, since it compared formula code alone. It now compares, month by month, the formula core runs (code, the globals it reads, defaults, closure), the variables' other calculation metadata against the model's own classes, abolition by gov.abolitions, and how the formulas read NI income, liability and directorship. - A sum, or Class 1, that the cache policy declines to keep counted as supplied (is_derived is false for an unstored value). Inputs are now told by the holder's input periods. Tests: the reviewer's reproducers, 400-carer sampled property tests of Class 1 entered in whole pence (year and months), reforms that end, re-date, abolish or hold in whole pounds the primary part, run its code with another global value, or change how it reads liability or NI income, cache-policy invariance, and months_summed invariants (exhaustive recovery of a year's whole pence below £32,768). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The r7 review's reproducer: £1.20 entered with £10,609.72 of pay leaves £10,608.52, a penny a week over, not £10,608.51. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tment The r7 review noted that _natural_rows called its reference legal net earnings, though the model counts statutory sick pay in NI income only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #2541
What and why
is_gainfully_employed_for_carers_allowancedecides whether a carer's earnings exceed the Carer's Allowance earnings limit: SSCBA 1992 s.70(1)(b), and ICA Regulations 1976 reg 8(1), "have exceeded £204" from 6 April 2026. In the Computation of Earnings Regulations 1996:The formula floored the weekly pence in float32, the dtype of
carers_allowance_earnings:np.floor(weekly * 100 + 1e-6) / 100 > limit. At these magnitudes the+ 1e-6does nothing, because float32 spacing near 20,400 is 0.00195. So float32 rounding, not the law, decided cases within about 0.002 pence a week of a boundary. Earnings of 52 × L + £0.52 a year (L + £0.01 a week, a penny over) counted as within the limit for L = £128, £132, £139 and £151. A carer a penny a week over the 2020-21 to 2024-25 limits got the full allowance.The rule
Reg 5 is applied where the calculation happens, so net earnings are whole pence, which float32 can hold recoverably:
carers_allowance_earningsapplies reg 5 to each step. It works in float64 pence from the whole pence each input was entered as (policyengine_uk/utils/pence.py:stored_pence).ni_class_1_employee's formula worked exactly on the year's NI income in whole pence. The model works out each month's Class 1 in float32 and sums the twelve. That can hold a whole-penny total further out thanstored_pencerecovers: £175.56 (8% of £14,764.46 less £12,569.96) is stored as 175.5600128, and rounding that up deducted a penny too much. The exact figure is used where it agrees with the stored total to within float32 error (one float32 step of the NI income plus 64 of the contribution). Otherwise, as under a reform that replaces the formula, the stored total is used.pension_contributions, whether entered as a total or summed from its programmes. A float32 sum is redone in float64 pence (stored_sum_pence) where the stored total is within float32 rounding of its programmes' sum; otherwise it is read as entered. The model holds each programme as one annual amount, not the payments reg 10(4)(b) halves one by one, so the half is of the year's total, rounded up once.is_gainfully_employed_for_carers_allowancereads the whole pence back exactly, divides by 52 with the fraction disregarded (reg 8(1)(b)(iii) for pay; reg 11(1)(a), average weekly earnings over a year, for profit; with reg 5), and tests whether that exceeds the limit (reg 8(1), strict). An amount entered directly with a fraction of a penny has the fraction disregarded. The limit is compared in pence, rounded to a millionth of a penny, so a reformed limit of £204.10 isn't read as 20,409.999… pence.stored_pence(x)returns the whole pence a float32 lies within half a float32 step of, and otherwise its exact value in pence. An amount entered in whole pence is stored within half a step of them; below £131,072 a step is under a penny, so no other whole number of pence is that close. Every step is exact in float64 (a float32 has 24 significant bits, so × 100 is exact).Why not round the stored total. This PR's first version took the nearest penny of the total and its second the nearest half penny. GPT-6.1 Sol's review found that the first counted 52L + £0.515 (pay less half an odd-pence contribution) up. juaristi22's review found that the second counted genuine fractions up: £14,000.01 of profit and a £6,039.38 premium leave £10,608.5174 unrounded, which it took to £10,608.52 (£204.01 a week), removing the full £4,495.40. A tolerance below the total can't fix this. Float32 holds a £14k–£20k profit only to within about a tenth of a penny before tax is taken off, so whole-pence and fractional totals overlap. A two-float32-step tolerance still misjudged 39 of 1,779 such traders within 5p of the 2026-27 boundary. Applying reg 5 to each step, before storage, decides them all exactly (below).
Known limits:
r5/class1_tolerance_study.py. It covers about 54,000 pays a year to £250,000, for every year from 2015 to 2031, plus 2022 full-year category A directors and statutory sick pay. The largest error is 0.42p, 0.18 of the tolerance.Effect (
~/reviews/uk-2541-ca-pence/probe_years.py; carer in England, aged 45, caring 40 hours, earnings = pay)52 × L and 52 × L + £0.51 stay within the limit in every year, before and after.
carers_allowance_earningsitself moves by at most a few pence a year (each deduction's fraction of a penny).Employees whose Class 1 is a whole number of pence that the float32 sum holds out are now judged as the law says. An example is £14,764.46 of pay with a £7,960.76 contribution in 2026-27 (YAML Cases 26–28,
probe_rows.pyin the review's salvage). They are exactly a penny a week over:Pension contributions entered as a total (
pension_contributions: 1000) come off earnings as on main (YAML Case 29). 32f1639 had dropped them.Two variables read
carers_allowance_earnings:is_gainfully_employed_for_carers_allowance;carer_support_payment_pre_couple_limit. Its own test,earnings < (limit + £0.01) × 52in float32, is exact on whole pence.CSP's SSI 2023/302 Schedule 2 has reg 5's rounding (para 4) and the same net earnings and profit (paras 9 and 12), so its boundary is now exact too. In Scotland in 2026-27, £12,576.76 of profit with a £3,932.96 premium has earnings of £10,608.51 (£204.00 a week) and CSP of £4,495.40; main had £10,608.5225 and CSP nil (
r5/probe_csp.py). A penny more profit is over the limit on both.Exhaustive and through-the-model checks (
~/reviews/uk-2541-ca-pence/, scripts with logs)sweep_exhaustive.pyruns the limit test's real formula on numpy arrays for every distinct limit, against exact integer references. Main's and the second version's (a67d545) formulas run on the same inputs:A // 52 > 100 × LA // 52 > 100 × Lsweep_offgrid.pyruns net earnings with fractions of a penny through the full model, for 2024-25 to 2026-27, against the law in exact arithmetic, deduction by deduction: P less each deduction rounded up, over exactly when that reaches 52 × (100L + 1) pence. Each tree runs its own model:About 140 trading and 31 employee rows a year fall on different sides of the boundary when only the total is rounded. Main and a67d545 never rounded each deduction, so most of their misses are these. This head's stored earnings are within half a float32 step of the legal whole pence in every row. The employee reference used to be the model's stored Class 1, which hid the Class 1 noise; with the exact Class 1, main's count is 124 rather than 115, and a67d545's 214 rather than 219.
sweep_class1_exact.py(written by the review of 32f1639) takes the untaxed employee route above, widens it to 5,248 rows a year (every 997p of contribution) and judges it against the law with Class 1 worked exactly. This head is wrong on 0 rows; 32f1639 on 6 (2 a year, the £175.56 and £235.38 rows); main on 580.sweep_pension_pairs.pyruns 59,532 whole-pence pairs of pay and pension contribution through the full model (every contribution from 0 to 40p, net earnings within 60p a year of the boundary, 2015 to 2026), against(P − ceil(C/2)) // 52 > 100 × L: 0 wrong.Invariants
Stated in the test module docstrings, and executed:
Whole pence are judged exactly: annual earnings of A pence are over the limit L exactly when A // 52 > 100 × L, in every year from 2015 to the parameter horizon. Tested by
test_whole_pence_are_judged_exactly(Hypothesis, with boundary examples for every Carer's Allowance: a penny a week over the 2020-21 to 2024-25 earnings limits counts as within the limit #2541 limit), the per-limit tests and sweep B.Pay less half a pension contribution is judged as the law says: pay of P pence with a contribution of C pence is over the limit exactly when (P − ceil(C/2)) // 52 > 100 × L. Tested by
test_pay_less_half_a_pension_contribution_is_judged_as_the_law_says(Hypothesis),test_half_an_odd_pence_pension_contribution_counts_as_a_penny_off(which also checks earnings are exactly P − ceil(C/2)), YAML Cases 23 and 24, andsweep_pension_pairs.py.Each deduction counts a fraction of a penny as a penny: with tax and Class 1 or Class 4 to pay, net earnings are P less each deduction rounded up, exactly, and the limit test follows them. Class 1 is 8% of P less 52 × £241.73, worked exactly in the test, not read from the model. Tested by
test_each_deduction_counts_a_fraction_of_a_penny_as_a_penny(trading and employee, 2024-25 and 2026-27, with the review cases), YAML Cases 25–28,sweep_offgrid.pyandsweep_class1_exact.py.Exact arithmetic (differential): for any stored amount, the float64 formula agrees with
_over_limit, which restates it infractions.Fraction. Tested bytest_the_formula_matches_exact_arithmetic_and_rises_with_earnings, with the float32 values either side of 52L + £0.52 and the second version's review-case value as explicit examples, and throughtest_bounds_and_differentialand the pension-share property test.Monotonic in earnings: more earnings never take a person from over the limit to within it.
Net earnings are monotonic in steps of 2p: raising pay or profit by 2p or more never lowers them.
test_net_earnings_never_fall_for_a_rise_of_two_pence_or_more, which runs every penny across £12,570, £50,270 and £125,140 (pay) and £12,570 and £50,270 (profit) and finds no fall at 2p or more. It also checks that each 1p fall is exactly 1p. Pinned bytest_a_penny_more_profit_can_lower_net_earnings_by_a_pennyand YAML Cases 30–31.Entered pension totals:
pension_contributionsentered as a total comes off earnings exactly as the same amount entered as a programme. Tested bytest_a_pension_total_entered_directly_counts_like_a_programmeand YAML Case 29.stored_pencehas four properties, tested intest_stored_pence.py:stored_sum_pencerecovers every float32 sum of up to five whole-pence amounts below £131,072, added one at a time asaddsdoes (2 million sums, some of whichstored_pencealone misses). It reads a total that is not such a sum as entered. Also YAML Case 32.Strict at the limit: earnings of exactly 52 × L a year are within it, in every year.
The existing invariants (bounds, unearned income is not earnings, the pension-share exactness, within a penny of reg 5 rounding) still hold.
Tests
test_a_penny_a_week_over_each_limit_is_over_it_in_every_yearenterscarers_allowance_earningsat 52L, 52L + £0.51 and 52L + £0.52. After the last legislated limit (2026-27) it takes the limit from the model, so a projection of the limit (as Project the Carer's Allowance earnings limit as 16 hours at the national living wage #2699 proposes) is covered rather than breaking the test, as MaxGhenis's heads-up on this PR suggested.test_pay_a_penny_a_week_over_each_limit_ends_entitlemententers pay, from 2015 to 2026; it stops at 2026 because from 2029employment_incomesubtractssalary_sacrifice_broad_base_haircut.test_each_deduction_counts_a_fraction_of_a_penny_as_a_penny, as above: 1,210 trading and employee pairs in 2024-25 and 2026-27 whose net earnings, deductions unrounded, lie from 4p below to 2p above the threshold. It adds C1 and the seven employee rows the review of 32f1639 found, each asserted to be exactly a penny a week over.test_a_limit_in_pounds_and_pence_is_read_exactly: a reformed limit of £204.10.Each wrong rule fails at least one test. For each, the formula files were swapped with everything else at this head (
r5/swap_checks.sh,r5/yaml_swaps.sh). The tests are the two CA property files andtest_stored_pence.py, 37 tests in all.stored_pencereturns the exact value)>=)test_bounds_and_differentialand the every-limit testsstored_sum_pencenever sums the parts)stored_sum_pencetestsstored_sum_pencealways sums the parts)stored_sum_pencetestLogs:
r5/swaps.log(property tests and YAML at d4b8cb2) andr5/yaml_swaps.log(YAML case names at 8f1df68, which adds Case 32).Review
~/reviews/uk-2541-ca-pence/review-sol.md,rereview-sol.md). Its nit, that the aggregate-impact sentence was stale, is answered below. Its one disputed claim, whole-pence recovery below £131,072 under the half-penny rule, was settled: that rule failed at £65,536.05. Under this head's rule whole pence are recovered below £131,072, checked exhaustively intest_stored_pence.py.subfleet run --task review --tier hard; no Codex lane admitted it, so Opus 5.5 served it. It was stopped at its six-hour limit before it finished. Its draft (REQUEST_CHANGES) and scripts are in~/reviews/uk-2541-ca-pence/rereview2b-salvage/. Each finding was checked here, and all are addressed at this head:sweep_class1_exact, against 6 for 32f1639. The known-limits text is corrected.pension_contributionswas ignored: the total is now read (stored_sum_pence), YAML Case 29.test_stored_penceproperties lackeddeadline=None: added.subfleet run --task review --tier hard) is pending.Local runs. They use this worktree's own venv (
uv sync --frozen --extra devfrom the mergeduv.lock; Python 3.13.9, policyengine-core 3.33.12, numpy 2.5.4, Hypothesis 6.170.11), with-n 4and-o xfail_strict=true.test_stored_pence.py(11 files): 105 passed (6 min). 8f1df68 adds only YAML Case 32.policyengine-core teston every YAML file underpolicyengine_uk/tests/policythat mentions carers or care hours (66 files): 1,205 passed.r5/, on trees extracted at each commit):sweep_offgrid.pyandsweep_class1_exact.pyas above.sweep_pension_pairs.py: 0 wrong of 59,532.sweep_exhaustive.py: identical to the earlier head (this head 0 in sets A–C).probe_years.py: this head misjudges no year from 2015 to 2028; main misjudges 2020 to 2024.uvx ruff@0.17.1anduvx ruff@latest(0.17.3),format --check .andcheck .: clean.Aggregate impact
At 8f1df68: pending (CI is running; this section is updated when it reports).
CI's Aggregate impact report at 32f1639 (run 40589857208): base
6030cbc0ba, which is main and the first parent of the merge commitc95ea031b0(its second parent is this head). Both sides ran onenhanced_frs_2024_25.h5(policyengine-uk-data 1.58.1), fiscal years 2025-26 to 2031-32, with a full microsimulation each year on each side. No household's net income changed in any year. No receipts, spending, caseload, poverty, inequality or decile figure moved. Checks: 0 broken, 0 fixed, 1 failing on both sides (VAT sign, unrelated). No record in the survey data lies close enough to a boundary to change; the fix matters for individual carers a penny a week over the limit.Reproducer:
policyengine_uk/tests/test_carers_allowance_earnings_limit_properties.py::test_a_penny_a_week_over_each_limit_is_over_it_in_every_year,policyengine_uk/tests/test_carers_allowance_earnings_limit_properties.py::test_pay_a_penny_a_week_over_each_limit_ends_entitlement,policyengine_uk/tests/test_carers_allowance_earnings_limit_properties.py::test_each_deduction_counts_a_fraction_of_a_penny_as_a_penny,policyengine_uk/tests/test_carers_allowance_earnings_limit_properties.py::test_a_pension_total_entered_directly_counts_like_a_programme,policyengine_uk/tests/policy/baseline/gov/dwp/carers_allowance_earnings_limit.yaml,policyengine_uk/tests/policy/baseline/gov/social_security_scotland/carer_support_payment_earnings_limit.yamlaxiom: TheAxiomFoundation/rulespec-uk#482 queued
🤖 Generated with Claude Code