Repository navigation
Fix statutory pension annual allowance taper income tests - #2441
Conversation
|
Hand-off for hub review at Validation: 385 pensions/income-tax YAML cases passed; 42 Python taper/charge/Gift Aid/Scottish-rate cases passed (exit zero). New regressions fail on the original base (34 YAML and 17 Python). Formatting, lint, committed-head fix evidence and bundle verification passed. Full repository suite and documentation build were not run. Impact, same certified cached uk-data 1.58.1 and locked dependencies: 2026 AA charge +£830.526112m; total income tax +£830.525920m. Four-year SB2023 AA-only cost falls £1.382156011bn to £11.513652540bn. 2024 modeled excess persons: 267,235 versus HMRC 30,440. Source hashes verified; sequential foreground simulations, four threads, aggregates only. Open items: independent hub review; Axiom s.228ZA computations/history/companion tests need signed encoding. The modeled excess tail still depends on cash-based DB inputs, carry-forward and sacrifice-date assumptions. Those limitations and the separate #2243 ANI scope are documented in the PR. The sandbox blocked shared Git metadata writes. Work was pushed to the requested feature branch and recovery evidence supplied to the hub. Caller metadata/history were untouched. The hub received handoff, commands and aggregate JSON. |
|
Addressed the review at
Validation commands and counts: uv run --frozen --no-sync policyengine-core test policyengine_uk/tests/policy/baseline/gov/hmrc/pensions policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax -c policyengine_uk
# 390 passed
uv run --frozen --no-sync pytest -n 4 -o usefixtures=cloned_uk_tax_benefit_system policyengine_uk/tests/test_pension_annual_allowance_taper.py policyengine_uk/tests/test_pension_annual_allowance_properties.py policyengine_uk/tests/test_gift_aid.py policyengine_uk/tests/test_scottish_income_tax_rates.py -q
# 48 passed
make format
uvx ruff format --check .Assertion-red evidence: historical 3; reviewed-head 2029 YAML 1 plus properties 6; relief/contributions mutation 1. The hub received the isolated diagnostic commands and complete logs. The final cap-property domain was also rerun at the reviewed head. Format/lint, diff checks, committed-head fix evidence and bundle verification pass. Full repository tests and docs build were not run. Impact: certified uk-data 1.58.1 SHA verified before each of three serial foreground aggregate-only microsimulations; four numerical threads; pre-run compressors 13.529/13.218/12.909GB. R2 changes neither 2026 aggregate; it adds £83.042990m AA charge in 2030. Full PR versus then-main: AA +£830.526112m in 2026 and +£909.155004m in 2030. The pre-2029 four-year SB2023 correction stays £1.382156011bn; it was not rerun because behavior in those years is unchanged. Final-head provenance: final head Reproducer: policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_annual_allowance.yaml::The 2029 NICs cap does not limit the salary sacrifice threshold income addback, policyengine_uk/tests/test_pension_annual_allowance_taper.py::test_nics_salary_sacrifice_cap_preserves_taper_and_charge The hub received handoff, recovery and aggregate evidence. Caller Git metadata was untouched. Open items: independent hub review, the post-#2440 merge round and Axiom signed encoding/companion tests. No self-review or PR merge performed. |
|
Addressed both findings from the review of
Validation: uv run --frozen --no-sync policyengine-core test policyengine_uk/tests/policy/baseline/gov/hmrc/pensions policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax -c policyengine_uk
# 392 passed (exit 0)
uv run --frozen --no-sync pytest -n 4 -o usefixtures=cloned_uk_tax_benefit_system policyengine_uk/tests/test_pension_annual_allowance_taper.py policyengine_uk/tests/test_pension_annual_allowance_properties.py policyengine_uk/tests/test_statutory_pension_edges.py policyengine_uk/tests/test_gift_aid.py policyengine_uk/tests/test_scottish_income_tax_rates.py -q
# 67 passed
# Isolated relief-versus-all-contributions mutation
# exactly 1 expected assertion failure; wrapper exit 0
make format
uvx ruff format --check .
# passedThe exact five review regressions fail at Impact: Fresh paired 2026/2030 runs use certified uk-data 1.58.1 (SHA verified before every process), then-main a94c65d, round 2 6fbf3e0, P1 c38168a and final ae2fe59. P1 moves neither metric/count in either year; P2 moves neither metric in 2026, and lowers 2030 AA charge £2.65 / income tax £3.74 with unchanged excess counts. Full PR versus main: AA charge +£830.526112m in 2026 and +£909.155001m in 2030; income tax +£830.525920m / +£909.154922m. Final excess people are 287,095.7 (340 records) / 311,044.8 (396 records). The pre-2028 reversal does move: the fresh four-year package cost falls £9.079549m to £11.504572991bn, so the full taper correction rises to £1.391235559bn. The body retains the #606 imputation/HMRC disclosure. Six serial foreground processes used four threads and pre-run compressors 18.111/12.261/12.027/11.920/11.830/11.486 GB; outputs are aggregates only. Historical round-3 coordination: #2440 was then open at The separate ordinary-tax defect is tracked in #2454, whose issue contains the runnable MOCK reproducer: the post-75 £160k witness gains £12,600 ordinary tax and the £100k PA witness £16,371 in each year. Reproducer: policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_annual_allowance.yaml::The 2029 NICs cap does not limit the salary sacrifice threshold income addback, policyengine_uk/tests/test_statutory_pension_edges.py::test_post75_dc_member_contributions_are_excluded_from_input_amount The hub received the handoff and aggregate evidence; caller metadata was untouched. |
Add the homogeneous loss property and assert default DC input paths. Clarify RAS and the 6 October age approximation.
|
Addressed the round 3 review at
Round 4 validation: 394 pensions/income-tax YAML cases and 71 Python cases passed, exit 0. Python used three workers; numerical workers used one thread. The unchanged review originals also pass: cap matrix 16 rows, basic RAS, 300/300 comparisons per year, age fixtures, 12 loss witnesses, all four homogeneous DC/DB loss-property nodes, and six #2454 boundary rows. The standalone gate-crossing age-80 charge is £41,062.50 at both caps. The six ordinary-tax/ANI/PA/reclassification rows match round 3 exactly; #2454 does not grow. The hub received the commands and complete logs. The CLI/pytest harnesses tune garbage collection and retain independent model clones; no calculated values are stubbed. The commands invoke the requested policyengine-core YAML suites, the five pension/property/Gift Aid/Scottish-rate Python files ( Historical round-4 2026/2030 impacts were blocked by host disk capacity. The required guard stopped before model loading at 44.036GB free; host activity then reduced available space to about 42.266GB. Own temporary fetch packs, duplicate snapshot trees and download/tool caches were removed. No new Microsimulation has run, and the 45GB free-disk requirement has not been relaxed. The fix and all tests were pushed first. The certified uk-data 1.58.1 file remains unchanged (128,409,762 bytes; SHA256 Round-4 then-main Reproducer: policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_annual_allowance_trading_losses.yaml::Trading loss limits for AA use actual income in 2029, policyengine_uk/tests/test_statutory_pension_edges.py::test_trade_losses_do_not_leak_nics_reclassification_into_aa, policyengine_uk/tests/test_statutory_pension_edges.py::test_post75_dc_member_contributions_are_excluded_from_input_amount The hub received handoff, recovery and aggregate evidence. All work stayed in the assigned workspace; caller Git metadata was untouched. |
|
Addressed the round-4 review at pushed head
Against the same-main merged pre-fix tree, the seeded 240-person MOCK population has 14 people with higher threshold and adjusted income in every 2016–2030 year (10 default DC, four supplied DB). Pre-2029 increases range from £600 to £32,754. One DC person crosses threshold income £110,000 → £120,000 in 2016–19: AA falls £40,000 → £10,000 and the charge rises £13,500 each year. This population has no allowance/charge change in 2020–30; the separate 2026 fixture above demonstrates a later gate crossing. Returned pay, raw net income, raw trading-loss relief and pension input arrays are byte-identical. All eight same-main cap/year/scheme ordinary-tax arrays are also byte-identical (960 stored person-world values). These comparisons isolate round 5 from main integration.
The basic-RAS £900 charge difference is a historical pre-#2440 result: merging #2440 removes that charge and personal-allowance difference (the capped-minus-uncapped ANI difference is now £1,600). Both post-75 ordinary-tax differences remain. Across all six NICs boundary witnesses, all 252 recorded variable cells are identical between the same-main merged pre-fix tree and this final tree, so round 5 does not expand that boundary. Fresh validation:
Portable equivalents of the actual foreground suite commands: uv run --frozen --no-sync policyengine-core test policyengine_uk/tests/policy/baseline/gov/hmrc/pensions policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax -c policyengine_uk
uv run --frozen --no-sync pytest -n 3 -o usefixtures=cloned_uk_tax_benefit_system policyengine_uk/tests/test_pension_annual_allowance_taper.py policyengine_uk/tests/test_pension_annual_allowance_properties.py policyengine_uk/tests/test_statutory_pension_edges.py policyengine_uk/tests/test_adjusted_net_income_pension_relief.py policyengine_uk/tests/test_gift_aid.py policyengine_uk/tests/test_scottish_income_tax_rates.py -q
make format
uvx ruff format --check .The actual harnesses tune garbage collection and reuse independent parsed-model clones; they do not stub calculated values. Numerical workers use one thread, Python uses three workers, and unchanged reviewer scripts run serially. Original script bytes and source import paths are verified. The full repository suite and documentation build were not run locally; GitHub CI documentation and full YAML checks have passed, with remaining merged-head CI status reported above. These diagnostics replay existing evidence and do not constitute an independent review. Impact: Three sequential foreground microsimulations completed on the certified uk-data 1.58.1 enhanced FRS 2024–25: current main The table measures the entire PR against current main, including corrections completed before round 5. Monetary figures are pounds rounded to pennies; weighted counts are rounded to one decimal, with totals and deltas rounded independently.
The round-5 corrections alone, measured as final minus the same-main merged pre-fix tree, give exactly £0 change in AA charge, income tax and chargeable amount, and zero change in weighted excess people or survey records in both 2026 and 2030, without a zero tolerance. This does not negate the statutory witness changes: the 2026 gate-crossing and supplied-ANI cases exercise inputs the certified population does not necessarily contain. For each of 2024, 2025, 2026 and 2027, the final microsimulation's aggregate-only diagnostic found zero supplied-ANI records and zero people with both relievable net-pay contributions and a trading loss. No person can enter finding 3's changed loss-limit path in those years, so its annual-allowance base, allowance and chargeable excess are unchanged under both current and reversed-SB2023 AA parameters. This is a zero-candidate proof using model inputs, not a new four-year fiscal replay. The historical SB2023 AA-only figure therefore remains £11,504,572,991.14, with the historical £1,391,235,559.17 reduction against its original main baseline. No new current-main four-year cost estimate is claimed. The correction still changes pre-2029 outputs for qualifying calculator inputs, as the 2026 regression demonstrates. From 2029, the code removes NICs-only returned pay and reconstructs dependent relief for the AA income tests, while the supplied-ANI path restores only actual relief. The cap properties and unchanged review witnesses test the resulting income/input/allowance invariance. The measured post-cap year here is 2030; no 2029 aggregate fiscal total was measured, and the 2029 behavior is established by the code and statutory/property tests. Code and tests were pushed before these runs. One microsimulation ran at a time in the foreground, numerical thread caps were all four, Hugging Face was offline, and only aggregates were saved. Recorded pre-run/year guards had compressor 7.563–7.574 GB and free disk 99.414–100.126 GB, satisfying the limits of below 30 GB and above 45 GB. All worlds used policyengine-core 3.33.2, numpy 2.5.4 and pandas 3.0.6. The final pension-helper SHA256 is Reproducer: policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_annual_allowance_trading_losses.yaml::Net-pay relief limits the loss before the threshold gate in 2026, policyengine_uk/tests/test_statutory_pension_edges.py::test_nics_cap_preserves_aa_inputs_and_charge_with_fixed_ordinary_tax, policyengine_uk/tests/test_statutory_pension_edges.py::test_trade_losses_do_not_leak_nics_reclassification_into_aa, policyengine_uk/tests/test_statutory_pension_edges.py::test_post75_dc_member_contributions_are_excluded_from_input_amount |
|
Implemented the round-5 P2 in The supplied isolated patch is applied unchanged: the rebuilt s.24A cap now calls the existing RAS-aware Validation:
Impact method: certified-input proof; no new microsimulation. Rechecked 1.58.1's actual SHA256, absent trading-loss/ANI inputs, zero loss default and the exact changed path. Zero loss makes the changed cap irrelevant. R6 minus R5 is exactly zero in 2026/2030 AA charge, income tax and excess counts; R5 provenance was revalidated. The retained PR-versus-main AA-charge deltas remain +£830,526,111.98 and +£909,155,001.43. Pre-2029 calculator scope remains disclosed. The separate ordinary-ATI formula is unchanged. Its standalone MOCK issue draft is ready for the hub to file (ATI £248,400 versus £250,000; cap £62,100 versus £62,500), as requested. The PR body is updated. Fresh CI is pending; hub independent review and signed Axiom encoding remain open. Handoff/proof logs and a verified recovery bundle are retained in the workspace job folder; Hypothesis storage is removed and no foreground test/model process remains. No self-review or merge performed. Reproducer: policyengine_uk/tests/test_statutory_pension_edges.py::test_basic_ras_uplift_does_not_relieve_net_pay_in_aa_loss_cap |
|
Landed by the UK hub through the merge queue, pinned to head
|
Fixes #2244
The annual allowance taper now applies both statutory income tests, counts employer pension provision and supplied statutory DB input in adjusted income, and rounds its reduction down to whole pounds. The taper starts in 2016–17. Main
1bdc7a0abhas been merged in9a146999c, including #2440, #2089, #2061 and #2423. Current head is39f5fa85c2e3ed365dc788ad2e9f6355a2c3dd5e. This draft retains the reviewed round-5 corrections and restricts the basic pension-relief uplift to relief at source in the rebuilt trading-loss cap.Statutory income tests
FA 2004 s. 228ZA defines adjusted income in (4), threshold income in (5), relevant sacrifice arrangements made on or after 9 July 2015 in (6), and whole-pound rounding in (2). Both income limits must be exceeded. The threshold-income limit is the adjusted-income limit less the standard allowance, including under reforms.
References: F(No. 2)A 2015 Sch. 4 para. 10, FA 2020 s. 22, and F(No. 2)A 2023 ss. 20 and 22. For 2016–19 the multiplier is
(standard − minimum) / £60,000; from 2020 it is one half. Parameters retain statutory 6 April dates; formula years use the model's calendar-year proxy.The model's
net_incomeprecedes pension relief, which is deducted separately throughallowances. Both tests useannual_allowance_net_incomeinpolicyengine_uk/utils/pensions.py. Adjusted income adds total pension input and subtracts all actual own member contributions, including unrelievable post-75 payments. Threshold income deducts actual relievable member contributions and adds full relevant salary sacrifice. Both exclude taxable pension death benefits supplied separately. The shared pension input feeds taper and charge and accepts statutory DB accrual; its DC default uses actual contributions. Gross Gift Aid does not reduce either taper income. Durable conventions are indocs/engineering/pension-annual-allowance.md.Basic pension relief in the rebuilt loss cap
The rebuilt ITA 2007 s.24A cap now reuses
pension_contributions_relief_amount. FA 2004 s.190(3) and s.191(7) reserve the basic £3,600 uplift above earnings to RAS; HMRC PTM044100 confirms this distinction. Pure net pay receives relief up to earnings, mixed payments receive only the RAS portion of the uplift, and member relief stops at age 75.For age 45, £2,000 cash pay, £3,600 gross net pay, no RAS, £250,000 dividends, £200,000 current trading loss, £100,000 employer contributions and £12,500 sacrifice, only £2,000 net pay is relievable. ATI is £250,000, the loss cap £62,500 and post-relief statutory net income £187,500. Threshold income is £200,000, adjusted income £302,000, AA £60,000 and charge £25,245. The reviewed head instead gave £200,400 / £302,400 / £38,800 / £34,785. Equality at the threshold prevents tapering.
The regression covers 2026, 2029 and 2030, each at the £2,000 NICs cap and uncapped, plus the £2,000-payment control: six failing worlds at
b6e819662become green; all six controls already passed and remain green. The control retains the same statutory incomes/allowance and a £24,525 charge on its smaller pension input. This correction also applies to qualifying pre-2029 calculator inputs. The related ordinaryadjusted_total_incomeloss-cap error is deliberately outside this PR; a standalone MOCK issue reproducer is ready for the hub to file. #2454's existing boundary is checked separately below.Round 5 corrections
Supplied ANI remains authoritative. With #2440 merged, supplied
adjusted_net_incomealready excludes synthetic NICs-returned pay. Its annual-allowance base now restores gross Gift Aid and pension relief recomputed on actual contributions and earnings, without applying pay removal or trading-loss reconstruction to that supplied income. The age-45 2030 case with £2,000 cash pay, £201,000 sacrifice, £100,000 employer contributions and supplied ANI £150,000 has threshold income £351,000 and AA £10,000 at either NICs cap. At the reviewed unmerged head the capped result was £201,000 / £39,500; on the #2440 merge the age-80 and age-45 loss variants still leaked. The cap property covers supplied ANI at ages 45 and 80, with and without trading losses, in separate simulations because ANI is a partial-input override.Net-pay contributions precede the income limit on trading-loss relief. FA 2004 s. 193(2) deducts net-pay contributions from employment income itself; only the s. 193(4)/(6) excess is a Step 2 deduction. ITA 2007 s. 25(4) restricts Step 2 relief to sufficient income. Annual-allowance construction now limits current-year trading-loss relief to actual income after relievable net-pay contributions, applying the age and earnings relief limits. This applies to every person, including those with no NICs-returned amount.
The corrected age-45 fixture, with £2,000 pay, £201,000 sacrifice, £100,000 employer contributions, £600 net pay and £10,000 loss, has threshold income £201,000, adjusted income £301,600 and AA £39,200 in both 2029 and 2030. The 2026 gate-crossing witness with £200,500 sacrifice and £1,000 net pay has threshold £200,500, adjusted income £301,500 and AA £39,250, replacing the erroneous £60,000 allowance. This changes pre-2029 behavior for the narrow group whose trading-loss relief is income-limited and who make relievable net-pay contributions. The earlier claim that every pre-2029 output is unchanged no longer applies to this correction. Ordinary income-tax formulas remain unchanged; the separate NICs interaction is tracked in #2454.
Against the same-main merged pre-fix tree, the seeded 240-person MOCK population has 14 people with higher threshold and adjusted income in every 2016–2030 year (10 default DC, four supplied DB). Pre-2029 increases range from £600 to £32,754. One DC person crosses threshold income £110,000 → £120,000 in 2016–19: AA falls £40,000 → £10,000 and the charge rises £13,500 each year. This population has no allowance/charge change in 2020–30; the separate 2026 fixture above demonstrates a later gate crossing. Returned pay, raw net income, raw trading-loss relief and pension input arrays are byte-identical. All eight same-main cap/year/scheme ordinary-tax arrays are also byte-identical (960 stored person-world values). These comparisons isolate round 5 from main integration.
#2440 integration. #2440 merged as
df61251c6and is included here. The agreed fixture “ANI pension deduction does not feed back into annual allowance taper or charge” now expects threshold income £330,000, adjusted income £370,000, AA £10,000 and charge £13,500 (£30,000 excess × 45%). Both explanatory comments are retained. Fresh merged-head validation is reported below; round-4 CI predates #2440.Retained corrections and verified evidence
The earlier helper correction reconstructs trading-loss relief from actual earnings and contributions, rebuilding the ITA 2007 s. 24A cap and s. 64 income limit, including the add-back for brought-forward trading losses. It avoids retaining relief computed on synthetic pay. The no-net-pay age-45 witness (£2,000 pay, £201,000 sacrifice, £100,000 employer contributions, £10,000 loss) remains threshold £201,000 and AA £39,500 in 2029 and 2030. Default-DC and supplied-DB people remain in separate simulations with their input paths asserted.
The round-4 review at
998f3c5b6confirmed all round-3 witnesses give identical annual-allowance incomes, pension input and allowance at both caps; all four homogeneous DC/DB loss-property nodes pass; and a 240-person loss-rich population has zero cap mismatches, against 32 at round 3. Its 2016–2028 outputs were byte-identical to round 3. That historical pre-2029 result does not cover the new net-pay loss-limit correction.Earlier statutory witnesses remain:
Age is read on 6 October. Payments in the year of a 75th birthday are treated all-or-none according to that date, without splitting at the birthday. Relievable pre-75 RAS payments cancel from adjusted income; unrelievable payments need not.
Cap invariance covers threshold income, adjusted income, pension input and allowance. Charge comparisons hold ordinary income-tax inputs fixed. The original 300-person check had a £3,242.83 charge difference through ANI and the personal-allowance interaction despite invariant taper accounting. #2454 tracks this separate ordinary-tax defect: the reviewed post-75 ordinary-tax increases were £12,600 and £16,371, with a £1,885.50 charge change in the latter witness; the basic-RAS witness had a £900 charge change through ordinary-tax inputs. No unrestricted charge-invariance claim is made.
The basic-RAS £900 charge difference is a historical pre-#2440 result: merging #2440 removes that charge and personal-allowance difference (the capped-minus-uncapped ANI difference is now £1,600). Both post-75 ordinary-tax differences remain. Across all six NICs boundary witnesses, all 252 recorded variable cells are identical between the same-main merged pre-fix tree and this final tree, so round 5 does not expand that boundary.
Validation
Validation at
39f5fa85c2e3ed365dc788ad2e9f6355a2c3dd5e:b6e819662production gave 6 assertion failures and 6 passing controls. The failing cases all reported threshold £200,400 instead of £200,000.-n 3and numerical thread limits of one.b6e819662and this head.make formatand lint passed;uvx ruff format --check .passed for 1,748 files. One pre-existing anyio assertion-rewrite warning remains in the YAML harness.b6e819662had 16 successful checks; that result is historical.Foreground suite commands (the local harness only tunes GC and uses independent parsed-system clones):
The requested local suites ran with MOCK and offline data access. The unchanged review scripts were SHA256-verified, run serially in the foreground, and their model-source imports checked. No full repository suite or documentation build was run locally: the requested paths cover this helper correction and the engineering documentation is standalone Markdown. No new independent review or merge was performed; the hub dispatches the review at this head.
Impact and interpretation
Round 6: unchanged from round 5, confirmed by an input proof rather than a new microsimulation. Certified 1.58.1 bytes and SHA256 were rechecked. Its 113,589-person table has neither trading-loss nor supplied-ANI input; trading loss has no formula and defaults to zero. The sole changed production path is
relieved_contributions → adjusted_total → loss_cap → actual_loss_relief, and zero loss makes the final deduction identically zero under either cap calculation. The saved R5 aggregate/source provenance (666 source hashes plus 113 diagnostic hashes) was verified against the original commits. Thus 2026 and 2030 AA charge, income tax, chargeable excess and weighted/unweighted excess counts have exactly zero R6-minus-R5 change. The table below retains the R5 measurements and their original baseline. No fresh fiscal replay is claimed.Three sequential foreground microsimulations completed on the certified uk-data 1.58.1 enhanced FRS 2024–25: current main
1bdc7a0ab269be750f8b6f57bd0bdb3a09b26517, the same-main merged pre-fix tree9a146999c73f83be8cb11d03ad0cdede016c6ba6, and finalb6e81966284d4f4d9ff4236dbb3460427e86024a. The artifact is 128,409,762 bytes, SHA256056e80fd8e9151d78f432a25cde863340baee81304c6216a37fb575ce8563784, with 113,589 person records. Source hashes were verified against each full commit, including 107 pension/income-tax source files for main and 113 for each PR tree.The table measures the entire PR against current main, including corrections completed before round 5. Monetary figures are pounds rounded to pennies; weighted counts are rounded to one decimal, with totals and deltas rounded independently.
The round-5 corrections alone, measured as final minus the same-main merged pre-fix tree, give exactly £0 change in AA charge, income tax and chargeable amount, and zero change in weighted excess people or survey records in both 2026 and 2030, without a zero tolerance. This does not negate the statutory witness changes: the 2026 gate-crossing and supplied-ANI cases exercise inputs the certified population does not necessarily contain.
For each of 2024, 2025, 2026 and 2027, the final microsimulation's aggregate-only diagnostic found zero supplied-ANI records and zero people with both relievable net-pay contributions and a trading loss. No person can enter finding 3's changed loss-limit path in those years, so its annual-allowance base, allowance and chargeable excess are unchanged under both current and reversed-SB2023 AA parameters. This is a zero-candidate proof using model inputs, not a new four-year fiscal replay. The historical SB2023 AA-only figure therefore remains £11,504,572,991.14, with the historical £1,391,235,559.17 reduction against its original main baseline. No new current-main four-year cost estimate is claimed. The correction still changes pre-2029 outputs for qualifying calculator inputs, as the 2026 regression demonstrates.
From 2029, the code removes NICs-only returned pay and reconstructs dependent relief for the AA income tests, while the supplied-ANI path restores only actual relief. The cap properties and unchanged review witnesses test the resulting income/input/allowance invariance. The measured post-cap year here is 2030; no 2029 aggregate fiscal total was measured, and the 2029 behavior is established by the code and statutory/property tests.
Code and tests were pushed before these runs. One microsimulation ran at a time in the foreground, numerical thread caps were all four, Hugging Face was offline, and only aggregates were saved. Recorded pre-run/year guards had compressor 7.563–7.574 GB and free disk 99.414–100.126 GB, satisfying the limits of below 30 GB and above 45 GB. All worlds used policyengine-core 3.33.2, numpy 2.5.4 and pandas 3.0.6. The round-5 pension-helper SHA256 was
b35d32a7975bad8e95ef4db69ebf95dd3b7b8d8a883aadc78cc4c91bfd3145f0; the aggregate wrapper SHA256 wasfef8712a422cdd93df851625559dda0e8888e5ed7ae811645bd39b38e1eb1c64.Round 4 did not produce fresh impact totals: its guard stopped before model loading at 44.036 GB free, and space then fell to about 42.266 GB. Historical figures below remain identified with their original baselines.
Historical round-3 impact
The following measurements predate round 4 and must not be read as fresh current-main or round-4 results. Round-3 paired runs used then-main
a94c65df96691eeffa5935f4797735e245439999, round-26fbf3e07e7f2f08e3eebaaeff3d33787f4844f98, fix-1-onlyc38168a3f46016224e2eb11bbe46b46f941d77c4, and round-3 finalae2fe59e033699b3e042b2b2dfdacacbe52b4495. Fix 1 was isolated by fix-1-only minus round 2; fix 2 by final minus fix-1-only.Totals and differences are rounded independently; raw aggregates are preserved in the evidence.
Both historical tables report AA charge, income tax including that charge, and people with a positive chargeable excess; counts include weighted people and unweighted survey records. Round-3 fix 1 changed none of these aggregates. Its pre-existing DC-default correction had zero measured effect in 2026 and lowered 2030 AA charge by £2.65 and income tax by £3.74; excess counts were unchanged in both years. These figures are pounds, not millions of pounds. The exact post-75 charge residue was −£2.6527891159057617; its income-tax residue was −£3.7371826171875.
The original paired 2026 taper correction raised AA revenue by £830.526112 million. That increase came from counting employer contributions and salary sacrifice in adjusted income under s. 228ZA(4); the threshold gate and rounding can only reduce the taper. Its positive-excess tail was 320 → 340 survey records. The round-3 corrections' separate effects are reported above.
policyengine-uk-data#606 tracks employer contributions imputed as 3 × employee contributions in frs.py. The original statutory correction moved AA charges further from HMRC statistics: its previously measured 2024 charge rose from £2.699 billion to £3.513 billion. HMRC's provisional 2024–25 Table 6 estimates £0.3 billion of AA charge, rounded to £0.1 billion; Table 7 reports 30,440 people declaring excess contributions through Self Assessment. The round-3 final 2024 current-law model AA charge was £3,513,221,874.7659545 (£3.513221875 billion), with 267,235.3 weighted people and 276 survey records with chargeable excess. That matched-year model count is 8.779 times HMRC's 30,440; the model remains conditional on imputed contributions and its DB/carry-forward defaults. HMRC's charge estimate models marginal tax on SA breaches and excludes AfT-only cases; reporting lags and the public-service pensions remedy also limit comparison (methodology).
The SB2023 AA-only replay previously moved closer to the OBR comparison: a £1.382156011 billion correction reduced the modelled four-year cost from £12.895808550 billion to £11.513652540 billion. The hub's tax comparator is £1.551794599 billion, with different scope from the net Budget scorecard. The round-3 replay lowered the four-year AA-only package cost by £9,079,548.52, from £11,513,652,539.66 to £11,504,572,991.14 (£11.504572991 billion). Against the unchanged historical main baseline, the round-3 full taper correction was £1,391,235,559.17 (£1.391235559 billion). The change occurs in the lower-AA counterfactual in 2026 and 2027: income tax falls £4,395,220.86 and £4,684,327.66 respectively; current-law 2024–27 aggregates are unchanged. Cost is the negative of current-law minus reversal income tax plus NI. The replay changes only AA, its floor and adjusted-income limit; MPAA/LTA remain. The original unrounded main baseline was £12,895,808,550.316437. These estimates do not validate the imputed pension tail.
The round-3 runs used the read-only certified uk-data 1.58.1 enhanced FRS 2024–25: 128,409,762 bytes, SHA256
056e80fd8e9151d78f432a25cde863340baee81304c6216a37fb575ce8563784, 113,589 people. Hashes were checked from bytes and model sources verified against their commits. Each process used one Microsimulation in the foreground, sequentially, with five numerical thread caps at four and Hugging Face offline. Only aggregates were saved. The six canonical foreground processes used numpy 2.5.4, pandas 3.0.6, policyengine-core 3.33.2. Pre-run compressor values were main 18.111004672 GB, round2 12.261343232 GB, fix1 12.026724352 GB, final 11.920375808 GB, sb-round2 11.830099968 GB, sb-final 11.486035968 GB, each below 30 GB. The five thread caps (MKL_NUM_THREADS, NUMEXPR_NUM_THREADS, OMP_NUM_THREADS, OPENBLAS_NUM_THREADS, VECLIB_MAXIMUM_THREADS) were all four. The diagnostic main-initial files are excluded from these canonical results.Scope and remaining limitations
The relief inventory covers current-year general-income trading losses and the separately modeled pension deduction. Brought-forward trading losses, capital allowances and trading allowance depend on profits; employment/property expenses remain confined to source income; property finance-cost relief is a downstream reducer. Charitable gifts of shares and land and
other_deductionsremain inallowances, although ITA 2007 s. 24(1)(a) places charitable investment-gift relief at Step 2, leaving a disclosed gap shared with ANI. The survey input defaults to zero.Sacrifice dates and taxable death benefits are unobserved; their inputs default to zero. DB accrual remains a cash proxy unless statutory pension input is supplied; carry-forward history defaults to zero. The 2015 parameters read back an unused £150,000 taper, but no taper applies before 2016–17. The 2016–19 multiplier reads
minimumfor the statute's literal £10,000, differing only under a reform of that historical minimum. Overseas/anti-avoidance adjustments, contribution-imputation repair, MPAA/LTA changes, new behavioral assumptions and the wider NICs income-tax defect are outside this PR. The paired-model estimates remain conditional on the pension-data and valuation defaults.axiom: needed — s.228ZA's RuleSpec module defers the income/taper computations and its companion tests are empty; its parameters contain only current values dated 0001-01-01. The signed encoder is unavailable. Hub follow-up must encode computation, dates and same-case tests, including the s.188/s.233 post-75 boundary, s.193/s.25 loss ordering and s.190(3)/s.191(7) RAS-only basic uplift.
Reproducer: policyengine_uk/tests/test_statutory_pension_edges.py::test_basic_ras_uplift_does_not_relieve_net_pay_in_aa_loss_cap, policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_annual_allowance_trading_losses.yaml::Net-pay relief limits the loss before the threshold gate in 2026, policyengine_uk/tests/test_statutory_pension_edges.py::test_nics_cap_preserves_aa_inputs_and_charge_with_fixed_ordinary_tax, policyengine_uk/tests/test_statutory_pension_edges.py::test_trade_losses_do_not_leak_nics_reclassification_into_aa, policyengine_uk/tests/test_statutory_pension_edges.py::test_post75_dc_member_contributions_are_excluded_from_input_amount