Skip to content

Band savings and dividends above property income - #2352

Merged
MaxGhenis merged 4 commits into
mainfrom
property-income-band-base
Oct 12, 2026
Merged

MaxGhenis merged 4 commits into
mainfrom
property-income-band-base

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2351

axiom: ukpga/2007/3/16 encoded-correct (rulespec-uk c65fd7df: uk/statutes/ukpga/2007/3/16.yaml, and uk/statutes/income_tax/individual/savings_dividend_oracle_pipeline.yaml stacks savings and dividends on all non-savings income, with no separate property slice)

What changes

ITA 2007 s. 16 treats savings and dividend income as the highest part of total income, with dividends above savings. Property income is non-savings income, so it fills the bands below them, as pay does. That holds in 2026-27 and, with property income's own rates, from 2027-28.

Since #1408, earned_taxable_income subtracts taxable_property_income, because property_income_tax taxes property income separately. But these variables stack savings or dividends on earned_taxable_income:

  • basic_rate_savings_income_pre_starter, basic_rate_savings_income, higher_rate_savings_income, add_rate_savings_income;
  • the starting-rate taper in savings_starter_rate_income;
  • dividend_income_tax.

So savings and dividends were banded as if property income were not there.

  • New taxable_property_income_after_allowances: taxable property income less the allowances it absorbs. This is the slice property_income_tax already computed inline; it now reads this variable, with no change in behaviour.

  • New non_savings_taxable_income: earned_taxable_income plus property income after allowances. With no Marriage Allowance it equals non_savings_income_after_allowances (a property test checks this). earned_taxable_income also subtracts Marriage Allowance, which the law gives as a tax reduction (ITA 2007 s. 55B). That is a separate open defect (Marriage Allowance is booked on the recipient as the transferor's unused allowance, not the fixed s.55B transfer #1947, PR Model Marriage Allowance as the statutory s.55B transfer and Step 6 reduction #1963); YAML Case 7 pins the current behaviour.

  • The six variables above stack savings and dividends on non_savings_taxable_income.

  • taxed_income, which sets the marginal rate of the annual allowance charge (personal_pension_contributions_tax), adds non_savings_taxable_income too. On main, £10,000 of excess contributions with £60,000 of property income was charged at 20% instead of 40%.

  • New non_savings_income_after_allowances: adjusted net income less savings, dividends and allowances, floored at nil. Both taxable_property_income_after_allowances and property_income_tax read it, so there is one copy of the expression.

  • From 2027-28 the order is statutory:

    • s. 25(3A) sets allowances against income other than property, savings and dividends first;
    • s. 16A places property income immediately below savings.

    Both are cited.

  • Unchanged: earned_taxable_income and the earned-income bands, which property income must stay out of, because property_income_tax taxes it.

Worked example, 2026-27: £40,000 of property income and £20,000 of dividends. Non-savings taxable income is £27,430. The £500 dividend allowance and £9,770 fill the basic-rate band at 10.75% (£1,050.28), and £9,730 is at 35.75% (£3,478.48): £4,528.75. main charges all £19,500 at 10.75%: £2,096.25. The same income as pay gives £4,528.75 on main too.

Impact (real run)

Measured on enhanced_frs_2023_24.h5 (local policyengine-uk-data storage, 6 October build) for 2026. This branch at 2de2210 (whose model code is the head's, after a clean merge of main) and main's code (c6d15c8) each ran a full simulation of the same data (impact_compare.py).

main This PR Change
Income Tax £349,674.5m £349,705.3m +£30.7m
of which savings income tax £356.7m £382.6m +£25.9m
of which dividend income tax £1,613.7m £1,618.5m +£4.8m
Household net income £1,645,439.5m £1,645,408.7m −£30.7m

The £30.73m Income Tax change is £25.90m on savings plus £4.81m on dividends, plus about £0.02m from the annual allowance charge (taxed_income).

  • Who changes: 1,856 records (101k people weighted), all with property income.
  • Increases: 99k people pay more, by up to £9,873.52 a person.
  • Float noise, not decreases: 397 records (2k people weighted) show "decreases" of £0.0078 to £0.125. Each is one or two float32 steps at a tax level of £93k to £1.28m.
  • Not included: the starting rate for savings still tapers from the personal allowance plus £5,000 rather than from the start of taxable non-savings income (Starting rate for savings: band is not tapered until other income exceeds £30,140; should taper from the Personal Allowance (£12,570) #1799). Fixing that would raise tax further for landlords with £0-£17,570 of taxable non-savings income.

Tests

  • New YAML (gov/hmrc/income_tax/property_income_band_base.yaml), seven cases:

    • dividends above £40,000 of property income: £4,528.75;
    • savings above it: £5,846;
    • pay and property income together;
    • a Scottish taxpayer, whose dividends use UK bands;
    • 2027-28, with property income at the 22% property rate and dividends still above it;
    • the annual allowance charge at 40% with property income (Case 6);
    • Marriage Allowance pinned (Case 7).

    Cases 1-6 fail on main.

  • Changed YAML (integration/income.yaml, "Property income uses post-allowance rate bands"): it expected nil savings tax for two people with property income and savings interest, which encoded this bug. With savings above the property income:

    • person 1, a higher-rate taxpayer with a £500 allowance, pays (£2,900 − £500) × 40% = £960;
    • person 2, a basic-rate taxpayer with £1,000, pays (£1,525 − £1,000) × 20% = £105.
  • Property tests (test_property_income_band_base_properties.py, Hypothesis):

    • replacing property income with pay equal to its taxable amount leaves savings and dividend tax unchanged, in England and Scotland;
    • with no Marriage Allowance, non_savings_taxable_income = adjusted net income less savings, dividends and allowances, floored at nil;
    • more property income never lowers savings or dividend tax (a sanity check: main passes it too);
    • with £40,000 of property income, some of £20,000 of savings pays 40% (main charged £2,900, below the 20%-only £3,900).

    The first and last fail on main. The first moves the taxable amount, because the £1,000 property allowance relieves small property income in full; Hypothesis found that case (£312).

  • Run locally at 2de2210:

    • the full policy YAML suite, 3,015 passed;
    • the property tests, 4 passed.
  • Review: a GPT-6.1 Sol review approved 1a80b21. Its should-fix and nit findings are addressed in 2de2210:

Not changed

The savings starting rate still tapers from the personal allowance plus £5,000 rather than from the start of taxable non-savings income (#1799). This PR changes only the income that taper reads.

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 11, 2026 16:25
ITA 2007 s. 16 treats savings and dividend income as the highest part of
total income, so property income, which is non-savings income, fills the
bands below them. Since #1408, earned_taxable_income leaves property income
out (property_income_tax taxes it separately), and the savings bands, the
savings starting-rate taper and dividend_income_tax all stacked on
earned_taxable_income, so they were banded as if property income were not
there. £40,000 of property income and £20,000 of dividends paid £2,096.25 of
dividend tax instead of £4,528.75.

New non_savings_taxable_income (earned_taxable_income plus property income
after allowances, from the new taxable_property_income_after_allowances,
which property_income_tax now reads too) is the base for those variables.

Fixes #2351

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e bug

The case expected nil savings tax for two people with property income and
savings interest. With savings above the property income (ITA 2007 s. 16),
person 1 is a higher-rate taxpayer: (2,900 - 500) x 40% = 960; person 2 a
basic-rate one: (1,525 - 1,000) x 20% = 105.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 11, 2026 17:19
… variables

Review follow-ups for #2352:
- taxed_income, which sets the annual allowance charge's marginal rate,
  stacked on earned_taxable_income too and so left property income out;
  it now adds non_savings_taxable_income (Case 6: £10,000 of excess
  contributions with £60,000 of property income pay 40%, not 20%).
- One non_savings_income_after_allowances variable feeds both
  taxable_property_income_after_allowances and property_income_tax.
- Cite ss. 16A and 25(3A) for 2027-28; say the identity holds without
  Marriage Allowance and pin that case (#1947); point the starting-rate
  comment at #1799; replace the monotonic check, which main also passed,
  with a higher-rate check main fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 11, 2026 22:47
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

CI run cancelled to free runners (UK hub, 2026-10-11 23:30Z). The PolicyEngine org is at GitHub's limit of 60 concurrent jobs, with about 360 queued. Fleet ops asked the hub to let the Budget-critical #2305 take runners first. This PR's queued run had not started, so I cancelled it. Nothing is wrong with the PR.

Please don't re-run it or push just to retrigger CI. The hub re-runs this run itself once #2305 has runners. The record is ~/reviews/uk-hub/ci-yield-2026-10-11.json; see notice 17 in ~/reviews/uk-hub/notices.md.

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Hand-off to the UK hub (session local_66e4b1fd, PolicyBench UK round 2).

  • Head: c1067e325e10b8a1621cf7dddf6c9997ffa6dad0 (includes main at ed7b42f95).
  • Review: GPT-6.1 Sol, two rounds, then a delta review of the main merge; APPROVE at this head: ~/reviews/policybench-uk-round2/reviews/pe-uk-merge-delta-2352.md (round 2: pe-uk-2352-review-r2.md).
  • CI: not yet run at this head. The run was queued, and the hub cancelled it to free runners (notice 17, ~/reviews/uk-hub/ci-yield-2026-10-11.json); the hub re-runs it. No CI run has completed on this PR at any head: each was superseded by a push or cancelled while queued. Lint and Test are therefore the open gate.
  • Local tests (~/reviews/policybench-uk-round2/fixes/evidence/), at the approved head before the main merge, which changed none of this PR's files (pr2352_approved_net.diff and pr2352_merged_net.diff are identical): 3,015 YAML cases and 4 property tests (pr2352_r2_full_yaml.log, pr2352_r2_py.log).
  • PolicyBench check at this head: all 2,800 round 2 references recomputed on this head (audit/attribution/refs_prop_final.csv); 2 move, the same cells and values as at the reviewed head. With all five fix heads merged onto main ed7b42f95, 96 move, also unchanged.
  • Impact (enhanced FRS, 2026, in the PR body): Income Tax +£30.73m, 101k people, all with property income.
  • Depends on: nothing. It and Set the Personal Savings Allowance on rest-of-UK bands for Scottish taxpayers #2348 both touch savings tax, in different files; they merge cleanly in either order.
  • Decision: none. A bug fix to ITA 2007 s. 16.
  • Follow-ups: none owed. Axiom parity: encoded correctly already (uk/statutes/ukpga/2007/3/16.yaml).

@MaxGhenis
MaxGhenis merged commit c36829d into main Oct 12, 2026
4 of 12 checks passed
@MaxGhenis
MaxGhenis deleted the property-income-band-base branch October 12, 2026 03:07
MaxGhenis added a commit that referenced this pull request Oct 12, 2026
With #2352, savings and dividends sit above property income (ITA 2007
s. 16). Two YAML cases check that the s. 414(2)(b) extension applies on
that order: £40,000 of property income with £20,000 of dividends
(dividend tax £4,278.75 against £4,528.75) or £20,000 of savings
(savings tax £5,646 against £5,846).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 12, 2026
The frozen expectations predated #2352 (savings and dividends above
property income) and main's Scottish personal savings allowance on the
UK bands, so the mixed-income rows and one allowance changed on main.
Regenerated from main 3381500. With no gift, the branch matches main
byte for byte on all 21 variables and the tax band.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 12, 2026
Round-3 review nit. The design note listed two limitations the #2352
merge removed: savings and dividends now stack above property income,
and the Personal Savings Allowance tests net income against the UK
limits raised by the gift. It now describes that behaviour instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Savings and dividends are banded without the property income below them (ITA 2007 s. 16)

1 participant