Repository navigation
Count the 2022 Energy Bills Rebate in HBAI income, and apply the trading allowance to Chapter 8 miscellaneous income - #2726
Conversation
…on Chapter 8 income - HBAI household net income adds energy_bills_rebate as miscellaneous income (DWP HBAI QMI FYE 2023); the Council Tax Rebate is paid in 2022-23 only (payments by 30 September 2022). - The trading allowance relieves income not otherwise charged (ITTOIA 2005 s. 783AB), sharing one allowance with trade receipts. New optional input income_not_otherwise_charged (default 0), deduction miscellaneous_income_trading_allowance_deduction, flag uses_trading_allowance for the loss opt-out, and miscellaneous_income_before_trading_allowance for means tests. Fixes #2724, fixes #2725. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… income YAML cases for miscellaneous_income_trading_allowance_deduction worked from ITTOIA 2005 Part 6A, Hypothesis properties for both fixes (a statutory differential, one allowance, bounds, monotonicity, trade parity, the loss election), and the Energy Bills Rebate docs: the monthly EBSS, the one-off Council Tax Rebate and its HBAI treatment as miscellaneous income. 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
|
It declares the GDP-per-capita index, so dataset projection needs it in uprating_indices.yaml (test_uprating_declarations), in the block that grows miscellaneous_income, which it is part of. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The trades-first split of the allowance charges the least income tax only without trade losses brought forward. With them, a smaller trade share can charge less now but uses up a loss that otherwise carries forward (ITA 2007 ss. 83-84) and raises Class 4 profits. The helper now says so instead of claiming every split is tax-neutral, and YAML Case 14 pins the split. The property tests draw losses brought forward and negative profits. The statutory reference returns the trades-first figure, which the model must match, and the lowest figure any split under s. 783AK allows, which it must never undercut and must equal without losses brought forward. The docs state the zero-receipts reading for a loss-making trade, and that ordinary treatment is an election out of full relief (s. 783AL) or no election for partial relief (s. 783AM). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n relief - HBAI counts the Energy Bills Rebate by financial year, as DWP does: hbai_energy_bills_rebate sums the monthly credit from April to the next March, so the whole £400 (Northern Ireland's January 2023 payment too) counts in 2022-23 and nothing in 2023-24. energy_bills_rebate keeps the calendar-year sum for household net income and government spending. - The Welsh childcare offer's reviewed source set now names miscellaneous_income_before_trading_allowance (CI's only failure). - The trading allowance docstring no longer claims every split charges the same income tax without losses brought forward: pension relief reads the trade's share too. YAML Case 15 pins the trades-first result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ction - hbai_energy_bills_rebate now picks the scheme by the household's nation in the financial year, reading eligibility and the schedule month by month. Before, January to March read the next model year's country, so a move (or a country set for one year only) mixed the two schemes: £599 or £201 where 2022-23 should hold £400. The monthly credit's scheme choice moves into ebss_credit, shared by both. YAML Cases 8-10 and the financial-year property test (now with households that move) pin it. - The aggregate-impact report counts the financial-year rebate's own records and suppresses it like a head (measure.HBAI_ONLY_COMPONENTS): HBAI income, its deciles, poverty and inequality leave it out in a year it is suppressed. HBAI no longer holds the calendar-year head by name, so suppressing that head left the payment in. New measure tests, including a differential over awards, pin it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r4 showed that a second, financial-year figure for the 2022 Energy Bills Rebate lets published calendar-year and financial-year totals, or a reform change, give back a suppressed small-cell award. Withdraw that copy instead of adding cross-window suppression: - Delete hbai_energy_bills_rebate and the ebss_credit helper; restore monthly_ebr_energy_bills_credit, the aggregate-impact measure, privacy notes, README and measure tests to main. - HBAI income adds energy_bills_rebate itself, which the report already protects as a fiscal-partition head. - Restore the r1 rebate YAML and property tests, and note the calendar-year sum (GBP 349 in 2022 and GBP 201 in 2023 against HBAI's GBP 550 in 2022-23) in the docs, the HBAI list and the YAML header. The docs also state how a one-year country input selects the scheme. Whether to sum the EBSS and EPG by financial year is a methodology choice across household net income, gov spending and HBAI, outside this PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
epg_subsidy counts in household net income and government spending but not in HBAI income, so only the Energy Bills Support Scheme's timing would move all three measures. Correct the docs page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Hand-off to the UK hub (session local_961f6e31-704b-49fe-a0fe-473ce5c08062, started by the Autumn Budget coordinator)
|
Fixes #2724
Fixes #2725
What and why
The review of #2719 (Autumn Budget 2026 baseline) found two pre-existing bugs. This PR fixes them outside #2719 and together, so one merge-queue pass covers both. It is not for merging during the Budget-week hold.
A third item from that review, Carer's Allowance penny rounding at the earnings limit, already has a more thorough fix in open draft #2543 (issue #2541). #2543 stores the limit in pence and applies reg. 5 per step, while the review's patch used a float tolerance, so this PR does not repeat it.
1. The 2022 Energy Bills Rebate in HBAI income (#2724)
Bug.
energy_bills_rebate(the Energy Bills Support Scheme credit plus the £150 Council Tax Rebate) counted inhousehold_net_incomeandgov_spending, but not inhbai_household_net_income, the income behind the poverty statistics. HBAI counts both. The HBAI quality and methodology report for FYE 2023 puts the EBSS (£400, or £600 in Northern Ireland) and the £150 Council Tax Rebate under miscellaneous income, not state support, and DWP imputes receipt because the FRS did not ask about them.No double counting. The FRS fields behind
miscellaneous_incomein policyengine-uk-data (frs.py: current odd-job incomeoddjob.ojamt, plusallpay2,royyr2–royyr4,chamternandchamttst) hold no rebate, so adding the rebate counts it once. (allpay2reaching bothmiscellaneous_incomeandprivate_transfer_incomeis a separate, known overlap, policyengine-uk-data#627.) It stays out ofhbai_benefits, which HBAI keeps for state support.A second bug: the model paid the Council Tax Rebate again in 2023-24.
council_tax_rebate/amount.yamlset £150 from 1 January 2022 to 1 October 2023. The model reads fiscal-year parameters at 30 April, so it paid £150 in 2022-23 and again in 2023-24. The existing test case expected £150 in 2023. Counting the rebate in HBAI income would have counted that second payment too. The billing authority guidance makes it a one-off: households qualified on their band on 1 April 2022, and billing authorities made every payment by 30 September 2022 (paragraphs 7, 14 and 19). The parameter is now £150 from 2022-04-01 to 2022-09-30 and zero otherwise.Timing: the model keeps the calendar-year sum. HBAI is a financial-year statistic and counts the whole EBSS in FYE 2023. The model sums the monthly credit by calendar year (#2103's convention): £199 in 2022 and £201 in 2023 for a Great Britain household on the scheme throughout. The model reads fiscal-year parameters at 30 April, so model year 2022 is 2022-23, and HBAI income holds £349 there (with the Council Tax Rebate) and £201 in 2023-24, where DWP counts £550 in 2022-23.
household_net_income,gov_spendingand HBAI income all use this one figure. Moving the credit to financial years would change all three together.epg_subsidysums the Energy Price Guarantee by calendar year the same way, and counts in household net income and government spending but not in HBAI income. This PR leaves the timing of both alone; it is a separate methodology question (see Follow-ups). The docs page states the difference.The aggregate-impact report protects it as a head.
energy_bills_rebateis a head of the fiscal partition. When it comes from fewer than 10 records, the report suppresses it and rebuilds HBAI income without it (hbai_holds_anyand_hbai_withoutinmeasure.pyread the HBAI component list), so HBAI income, its deciles, poverty and inequality never include it. Because HBAI adds the head itself, the report publishes no second figure for the same payments.Changes.
energy_bills_rebateadded toHBAI_HOUSEHOLD_NET_INCOME_ADDS, next to the Warm Home Discount.council_tax_rebate/amount.yamlnow covers 2022-23 only.hbai_benefits.cost-of-living-payments.mdnow describes the monthly EBSS, the 2022-23-only CTR, HBAI's treatment and the calendar-year timing. It previously described a flat £200 credit.2. The trading allowance on Chapter 8 miscellaneous income (#2725)
Bug. The trading allowance covers "relevant income": trade receipts plus "miscellaneous income" (ITTOIA 2005 s. 783AC). The model applied it to trades only.
Law. These are from ITTOIA 2005 Part 6A Chapter 1.
Royalties, other Part 5 chapters, and the SPI's benefits and termination payments are in
miscellaneous_incomebut are not Chapter 8 income, so they get no allowance.Design.
income_not_otherwise_charged(person, year): the Chapter 8 part ofmiscellaneous_income. It is optional and defaults to zero, because no dataset separates it yet (see Follow-ups). The model caps it atmiscellaneous_income, and it never adds to it.utils/trading_allowance.py::trading_allowance_reliefsmakes one decision for the whole relevant income and returns(trade_relief, miscellaneous_relief).trading_allowance_deductionlogic, unchanged when there is no Chapter 8 income.loss_relief, ITA 2007 s. 83) absorb the trade profit a smaller share leaves, but that uses up loss which would otherwise carry forward against later profits of the trade (s. 84). YAML Case 14 pins this: £3,606 against £3,486 under the £200/£800 split, which would use £600 of the loss.miscellaneous_income_trading_allowance_deduction;miscellaneous_income_before_trading_allowance(the oldtaxable_miscellaneous_incomeformula,max_(0, miscellaneous_income));uses_trading_allowance, true when either relief applies.taxable_miscellaneous_incomeis now the before-allowance figure less the deduction.Means tests read income before the allowance. Benefits read raw
self_employment_income, not profit after the trading allowance. To match, every means-test and gross-income reader of miscellaneous income now usesmiscellaneous_income_before_trading_allowance:uc_individual_earned_income_before_mif);gross_taxable_inputs;Tax-side readers stay on
taxable_miscellaneous_income: adjusted net income, the UC income tax deduction, the CPS marriage tax reform and the property allowance check."Allowance chosen" now means either relief. Three places treated
trading_allowance_deduction > 0as "the individual used the allowance": the trading loss inannual_allowance_net_income(utils/pensions.py),trade_loss_relief_against_general_income, andni_class_4_trading_loss. With relief on Chapter 8 income alone, that would let the individual claim the s. 783AF nil trade loss as well. All three now readuses_trading_allowance. YAML Cases 10 and 11 cover both directions: the model claims a £5,000 loss and taxes the casual income, while a £500 loss gives way to full relief on £800 of casual income.Not modelled (stated in the helper's docstring):
Assumption with unknown receipts. Without
self_employment_gross_receipts, the model takes a trade's receipts as the lowest its profit allows: the profit when that is within the allowance, and nil when the trade made a loss or no profit. This is the reading the trade-side logic already uses, and it is the generous one. The helper and theincome_not_otherwise_chargeddocs both state it. So a loss-making trade with unknown receipts leaves the whole allowance to Chapter 8 income. Where actual receipts would push relevant income above the allowance, the model can over-relieve. With receipts supplied, the statutory differential test covers it exactly.Invariants
Each one holds for every input. Hypothesis tests each over many generated cases in one reusable simulation.
Energy Bills Rebate (
tests/test_energy_bills_rebate_hbai_properties.py, 16 households across bands, nations, pay, UC claims and EBSS months, 2021–2024):energy_bills_rebate, in every year, nation and band. (test_hbai_income_rises_by_exactly_the_rebate)hbai_benefitsdoes not change with the rebate, because it is miscellaneous income. (same test)test_the_council_tax_rebate_is_paid_once)energy_bills_rebateonce, and not its parts as well, and neither it nor the Warm Home Discount is inhbai_benefits. (test_the_rebate_is_counted_once_and_not_as_state_support)Trading allowance (
tests/test_trading_allowance_miscellaneous_income_properties.py, 24 drawn cases × 3 copies: drawn Chapter 8 share, none, all; each with and without the trade; the allowance is read from parameters, so the tests carry over to #2719's £3,000):test_taxable_income_matches_statutory_reference)test_one_allowance_covers_both)test_deduction_and_taxable_income_are_bounded)test_trade_relief_does_not_depend_on_chapter_8_income)test_no_chapter_8_income_changes_nothing)test_means_tests_read_income_before_the_allowance)test_income_tax_never_rises_with_more_chapter_8_income)test_chapter_8_income_is_taxed_like_trade_receipts)uses_trading_allowancematches the deductions, which only restates its formula. (test_a_current_loss_is_never_both_claimed_and_given_up)Mutation check. I applied each mutant to the helper or flag, then ran the property tests and YAML.
uses_trading_allowancereads the trade relief onlyM3 at first got past every property test, because the loss test read the flag it was meant to check. The test now works out "allowance used" from the two deductions.
Independent review
Round 1 ran through
subfleet run --task review --tier hard, at bd9cca3. With no Codex lane open, so Subfleet served it on Opus 5.5. Verdict: CHANGES REQUESTED, with 1 major, 2 minor and 2 nit findings. The report is in~/reviews/pe-uk-2726/review-r1.md. 729062e addresses each finding:income_not_otherwise_chargednow document it, and Case 11's comment states it.loss_reliefand negative profits. The reference minimises over the feasible splits, and M5 shows it pins the documented split.Round 2 ran on GPT-6.1 Sol (pinned to a Codex lane) at 729062e. Verdict: CHANGES REQUESTED, with 1 major and 2 minor findings; report in
~/reviews/pe-uk-2726/review-r2.md. It recommended keeping trade-first as the documented convention. It confirmed the statutory reference's piecewise argument and found it non-vacuous: 31 strict gaps between the lowest split and trade-first among 1,050 applicable cases. It also found no change against main with Chapter 8 income at zero, over 40,000 formula cases. 1077aa2 addresses each finding:taxable_miscellaneous_income. It now namesmiscellaneous_income_before_trading_allowance. This was CI's only failure on 729062e.Round 3 ran on GPT-6.1 Sol at 1077aa2. Verdict: CHANGES REQUESTED, with 2 major findings, both on the financial-year copy; report in
~/reviews/pe-uk-2726/review-r3.md. January to March read the next model year's country (England then Northern Ireland gave £599 for 2022-23), and the report's small-cell protection missed the copy (one recipient, the calendar head suppressed, HBAI kept the £400). cc7002d fixed both.Round 4 ran on GPT-6.1 Sol at cc7002d. Verdict: CHANGES REQUESTED, with 2 major and 1 minor findings; report in
~/reviews/pe-uk-2726/review-r4.md. It confirmed both round 3 fixes, then found:All three come from publishing a second figure for the same payments. Patching each overlap would add suppression logic across calendar and financial years for one historical payment, so 0deb0bb withdraws the financial-year copy instead (
hbai_energy_bills_rebate, its helper, the report'sHBAI_ONLY_COMPONENTSand their tests). HBAI countsenergy_bills_rebate, which the report already protects as a head; that code matches main. The timing question goes to Follow-ups. The Welsh source set and pension fixes from round 2 stay. The docs page now records how the calendar convention treats movers, the behaviour behind finding 3.Round 5 ran on GPT-6.1 Sol at 0deb0bb. Verdict: CHANGES REQUESTED, with 1 minor finding; report in
~/reviews/pe-uk-2726/review-r5.md. It confirmed the revert is complete and executed the protections: one recipient among twelve suppresses the head, rebuilds HBAI income without it and withholds deciles, poverty and inequality; reform withholding triggers on the head; round 4's overlapping-window pattern publishes no second figure. It also confirmed the calendar-year figures in the docs and found nothing new in the trading allowance.epg_subsidycounts in household net income and government spending only (executed: a £123 EPG left HBAI income at £349). 9d4f759 corrects the docs page and this body.Round 5 delta ran on GPT-6.1 Sol at 9d4f759. Verdict: APPROVE, no findings; report in
~/reviews/pe-uk-2726/review-r5-delta.md. It confirmed the docs correction againsthousehold_benefits,gov_spendingand the HBAI component list, and that 9d4f759 changes only the docs page.Test plan
miscellaneous_income_trading_allowance_deduction.yaml: 15 cases, with tax worked from s. 783AD's £1,000, the £12,570 personal allowance, the 20% basic rate and the 6% Class 4 main rate.energy_bills_rebate.yaml: Cases 3–6.council_tax_rebate.yaml: 2021, 2022 and 2023.pytest -n 4.tests/code_health,test_uprating_inputs_reach_data.pyandtest_projection_horizon.pywith-n 2: 3,027 passed.-n 4: the rebate and trading-allowance YAML (6 and 15 cases), and the rebate and trading-allowance property tests,tests/aggregate_impact/,tests/code_health,test_variable_code_sharing.pyand the Welsh source test: 3,407 passed.make formatchangelog.d/2724.fixed.mdandchangelog.d/2725.fixed.mdAggregate impact
CI's job on 729062e passed: no household's net income changed in any year from 2025-26 to 2031-32, and no change to receipts, the government balance, poverty, inequality or decile incomes; one check (VAT sign) fails on both sides. The new head has the same rebate and HBAI code as 729062e, so the expected result is the same: the rebates are nil after 2023-24, and
income_not_otherwise_chargeddefaults to zero, sotaxable_miscellaneous_income, every means-test reader and the loss sites compute what they did before.Overlaps with open PRs
household_energy_paymentto the same HBAI list, right afterwarm_home_discount, and inserts a docs section after the CTR parameter line this PR rewrites. Both are textual conflicts that keep both sides.trading_allowance.yamlsays the s. 783AD amount "also relieves miscellaneous income (s. 783B); the model applies it to trading income". Once this PR lands, the model applies it to both. The section is s. 783AB; s. 783B starts Chapter 2, the property allowance. Whichever lands second should fix that comment.utils/pensions.pyandtrade_loss_relief_against_general_income.py, where this PR changes one line each (trading_allowance_deduction > 0becomesuses_trading_allowance). Any new "allowance chosen" test there should read the flag.Follow-ups (not in this PR)
income_not_otherwise_chargedfrom the FRS odd-jobs and casual-income fields, and keep it at zero for SPI income that is already net of the allowance. Until then the relief has no aggregate effect.gov_spendingand HBAI income; the EPG in the first two. Whether to sum April to March instead spans both schemes, so it is a methodology decision of its own.Reproducer: policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/energy_bills_rebate.yaml; policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml; policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/miscellaneous_income_trading_allowance_deduction.yaml; policyengine_uk/tests/test_trading_allowance_miscellaneous_income_properties.py::test_taxable_income_matches_statutory_reference; policyengine_uk/tests/test_energy_bills_rebate_hbai_properties.py::test_hbai_income_rises_by_exactly_the_rebate
axiom: TheAxiomFoundation/rulespec-uk#348 queued
The axiom line covers the trading allowance. The spec for its miscellaneous-income half is in this comment, and the encoder waits on the corpus, which lacks ss. 783AA–783AR. The Energy Bills Rebate half is n/a: HBAI income is DWP's statistical definition (microsimulation-only), and the 2022-23 Council Tax Rebate was a grant scheme set by billing-authority guidance, with no rulespec-uk module.
🤖 Generated with Claude Code