Repository navigation
Count property income after finance costs in HBAI and market income - #2564
Conversation
hbai_household_net_income, market_income and household_market_income added property_income, the landlord's profit before the costs of dwelling-related loans. HBAI is built from the Family Resources Survey, which records rent from property after the mortgage payments and loan interest on show card K6, so the three now add property_income_after_finance_costs, as the legacy means tests do. Finance costs then lower HBAI income by the costs less the s. 274A tax reduction instead of raising it by the reduction. Income tax and the means tests are unchanged. Fixes #2390. 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
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; components the model counts twice; household income totals; population; poverty rates; people in poverty; inequality; mean household net income in each side's own deciles; standard reform costings (change in gov_balance); standard reforms: change in each reform's target. Checks failing on both base and head (1)
Counted-once checkEach of 84 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
Components the model counts twice: 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
|
Hand-off to the UK hub (job 20261022-001253-sprint-fix-2390)Head: Review: none run in the job, per adopt-common. The hub dispatches the GPT-6.1 Sol review at this head. Tests
Impact
Open items
|
|
Merged by the UK hub (session local_8e19f9d5, Opus 5.5) on its merge gates. One merge-queue enqueue, pinned to head
🤖 Generated with Claude Code |
Fixes #2390
What and why
hbai_household_net_income,market_incomeandhousehold_market_incomeaddedproperty_income. Since #2172 (2.123.0), that is the landlord's profit before the costs of dwelling-related loans. Income tax hasn't deducted those costs since 2020-21 (ITTOIA 2005 s. 272A(4): "no deduction is allowed for costs of a dwelling-related loan"). It relieves them with a tax reduction instead (s. 274A). The three income measures therefore counted mortgage interest as income. As a result, a landlord's finance costs raised their HBAI income by the tax reduction they earn.HBAI's basis is after interest. The DWP's HBAI methodology (FYE 2025) builds income from the Family Resources Survey and lists "investment income" without further detail. Its "mortgage interest payments" housing cost is the household's own home. The FRS question it rests on is PropRent: "How much rent have you received before tax from other property in the last 12 months, AFTER paying for any of the things on this card?" Show card K6 lists "1. Mortgage payments" and "3. Interest on a loan to purchase the property" (FRS 2023-24 question instructions, p. 302). The methodology itself doesn't say how landlords' mortgage interest is treated. The basis comes from the survey question.
Change. The three lists now add
property_income_after_finance_costs(property_incomelessproperty_finance_costs, nil where the costs exceed a positive profit). The legacy means tests already count property income this way.taxable_property_income, the s. 274A reduction,total_incomeand every means test are untouched.market_income,household_market_incomeincome_tax(s. 274A reduction of £800 included)hbai_household_net_incomeLosses. A positive profit with larger costs gives nil, not a loss:
property_income_after_finance_costsalready behaves this way. That matches how both data pipelines read the FRS: uk-datafrs.pyand Microcosmfrs_spine.pycount a RentProf loss as zero. A loss before interest (negativeproperty_income) is still counted as negative, as before.Readers checked (origin/main 9d81a5d)
No tax base or benefit means test reads the changed aggregates, so baseline tax, benefit and fiscal totals are unchanged. Some other readers can move results when switched on: private-school attendance imputation ranks households by market income (it changes VAT only when imputation is on and the private-school VAT lever is set; stored attendance bypasses it); the opt-in labour-supply dynamics use non-zero income elasticities; and the pre-Budget income deciles allocate education, NHS and other-spending changes across households (aggregate allocations are parameter-fixed, household incidence moves).
market_income: no reader inpolicyengine_uk/(docs only).household_market_income: read byhousehold_net_income,household_net_income_ahc,household_gross_incomeandpre_budget_change_household_net_income, which are outputs only.pre_budget_change_household_net_incomefeedspre_budget_change_ons_household_income_decile, which feeds thenhs/education/other_public_spending_budget_changecontrib levers. These are zero unless set.contrib/labour/attends_private_school.py:64ranks households on it to impute private-school pupils, which feedprivate_school_vatingov_tax/household_tax. On a dataset that storesattends_private_school, the formula doesn't run. The Microcosm Budget cuts store it (microcosm#1095, merged 2026-10-16; the 20261019T083323Z cut has the column), so private school VAT can't move there. On a dataset without the column, landlords with finance costs rank slightly lower. uk-data stores onlyattends_private_school_random_draw(frs.py:1850). It also fills noproperty_finance_costs, so nothing moves there (invariant 1).utils/aggregate_impact/measure.pyreports it and uses it in the net-income identity, which still holds.hbai_household_net_income(and the before-reset, AHC and equivalised variants) is read by:household_income_decile;dynamics/labour_supply.pyandprogression.pytargets;measure.py.The HBAI rebuild in
measure.pyusesHBAI_HOUSEHOLD_NET_INCOME_ADDS, so it follows the swap.household_net_incomeis read by:marginal_tax_rateandmarginal_tax_rate_wrt_employer_cost, which use differences and are unaffected;relative_income_change, which feedsincome_elasticity_lsr. The income elasticity is 0 by default, so nothing moves unless a run turns it on;dynamics/participation.py, which uses differences.total_income(income tax) addsproperty_incomedirectly and is unchanged. HB, IS, tax credits, CTR and PC already readproperty_income_after_finance_costs. UC counts no property income.Tests
household/income/hbai_property_income.yaml: four cases hand-computed from the 2026-27 rates.All four fail on origin/main (for example
market_income@2026: [50000.] differs from 46000.0) and pass here.test_hbai_property_income_properties.py: 30 Hypothesis examples × 21 landlords, each simulated without and with finance costs, at 2027 (property basic rate read from parameters), England and Scotland. It fails on origin/main at the first example (market income doesn't fall) and passes here.property_income,property_finance_costs,market_incomeorhbai_household_net_income, plus all oftests/policy/baseline/household.aggregate_impact/test_aggregate_impact_measure.py: 44 passed.code_health/test_aggregation_lists.py: 8 passed.code_health/test_household_income_lists.py: 2 passed.uvx ruff@latest format --check .(0.17.1) is clean.property_finance_costs, so the change is a no-op for them (see invariant 1). CI runs them.Invariants
property_finance_costs = 0, all three aggregates are unchanged to the penny.property_income_after_finance_costsequalsproperty_incomefor every profit, including losses.market_incomeandhousehold_market_incomeby exactly min(C, max(profit, 0)).Invariants 2 to 5 are executed by the property test. Invariant 1 holds by construction (
where(profit > 0, max_(profit - 0, 0), profit)).Impact
Microcosm Budget data. These are real microsim runs, aggregates only, at calibrated weights.
20261019T083323Z(HFpolicyengine/populace-uk-private, tagmicrocosm-uk-2024-25-national-20261019T083323Z-6cba5d71, revisionbb2258482ef8). This is the certified interim Budget data, built with pe-uk 2.132.6.property_income−property_income_after_finance_costs)hbai_household_net_income(and AHC)household_market_income,market_income,household_net_incomeincome_tax,gov_tax,household_tax,household_benefits,gov_balance, s. 274A reliefHow to read the table:
experiments/1106-uk-property-income-receipts.mdC11 item 1). That experiment reversed only the FRS channel's add-back in the data, which also cut income tax by £0.34bn. This change leaves data and tax alone and nets the costs on both the FRS and the SPI channels. The issue's £6.8bn SPI figure was not separately measured.Aggregate impact CI (comment, run): pass.
9d81a5dfa8against headc244eae09c, onenhanced_frs_2024_25.h5(policyengine-uk-data 1.58.1, sha256056e80fd8e91), 2025-26 to 2031-32.sign:vat, unrelated).property_finance_costscolumn, so invariant 1 makes the change a no-op there. It also has noattends_private_schoolcolumn. The Budget-relevant figures are the Microcosm ones above.Reproducer: policyengine_uk/tests/policy/baseline/household/income/hbai_property_income.yaml, policyengine_uk/tests/test_hbai_property_income_properties.py::test_finance_costs_lower_market_and_hbai_income
axiom: n/a: HBAI and market income are statistical income measures with no legal provision to encode, and the income tax and means-test rules are unchanged
🤖 Generated with Claude Code