Skip to content

Model Marriage Allowance as the statutory s.55B transfer and Step 6 reduction - #1963

Draft
MaxGhenis wants to merge 12 commits into
mainfrom
marriage-allowance-election
Draft

MaxGhenis wants to merge 12 commits into
mainfrom
marriage-allowance-election

Conversation

@MaxGhenis

Copy link
Copy Markdown
Collaborator

Fixes #1947.

Stacks on #1949 (the #1942 fix, which stacks on #1943). The base is main so CI runs, and the diff includes #1943 and #1949 until they merge.

What the law says and what changes

ITA 2007 ss. 55A-55E (legislation.gov.uk, read 2026-09-30; verbatim text in the issue):

Before After (= law)
Transferable amount min(partner's unused allowance, 10% of PA), rounded up to £10 the fixed 10% of the s. 35(1) allowance, rounded up to £10 (s. 55B(4)-(5)); £1,260 in 2026-27, £1,060 in 2015-16
Transferor allowance unchanged allowance cut by the transferable amount (s. 55B(6))
Recipient taxable non-savings income cut by the amount Step 6 tax reduction of the basic rate, or Scottish basic rate, × the amount (s. 55A(2), s. 55B(1), (3)), capped at the Step 5 tax left after other reductions (s. 29(2)-(3), s. 27(2))
Eligibility tax band of the recipient (NONE/STARTER/BASIC/INTERMEDIATE) recipient not liable above the listed basic rates (s. 55B(2)(b), (ba)); transferor the same once their allowance is cut (s. 55C(1)(c), (ca)) and entitled to an allowance (s. 55C(1)(b)); no married couple's allowance claimed by either (s. 55B(2)(d)); at most one election (s. 55E)
Who claims anyone married with a partner who has unused allowance, both partners if both are below the allowance the couple elects only if it lowers their combined income tax, in whichever direction lowers it more
Take-up the recipient's would_claim_marriage_allowance the couple's election uses the elder spouse's would_claim_marriage_allowance, so each couple has one draw (the dataset draws it per person at 50%, so take-up stays at 50%)

The rate test reads the model's own liabilities. Two points follow from the statute's wording:

  • Dividends: the dividend nil rate does not help. s. 55B(2)(ba) tests the dividend upper rate "if section 13A (dividend nil rate) were omitted".
  • Savings: the savings nil rate does help. s. 55B(2)(b) lists it, and nothing like (ba) applies to savings. (Compare s. 12B(8)(b)(ii), which does look through s. 12A.)

Scottish savings and dividends are banded on UK rates, so an intermediate-rate Scottish taxpayer with savings stays eligible. The old band test made them ineligible.

Variables

New, all Person, YEAR:

  • marriage_allowance_transferable_amount: s. 55B(4)-(5).
  • is_marriage_allowance_spouse: the two eldest married members of a benefit unit that has exactly two. This also works before Replace generic child and adult flags with each programme's legal definitions #1896 lands, while marital_status still marks children in a married benefit unit as married.
  • makes_marriage_allowance_election: the couple's choice; users can set it as an input.
  • marriage_allowance_relinquished: s. 55B(6).
  • marriage_allowance_appropriate_percentage: s. 55B(3).
  • marriage_allowance_tax_reduction_limit: s. 29(2)-(3).
  • marriage_allowance_tax_reduction: s. 55B(1). Added to income_tax_subtractions.

Changed:

  • marriage_allowance is now the amount received from the spouse's election, and only the gaining spouse has it. It no longer comes off taxable income: it was removed from earned_taxable_income_exclusions.
  • personal_allowance subtracts marriage_allowance_relinquished.
  • meets_marriage_allowance_income_conditions is the rate test above.

Removed:

  • partners_unused_personal_allowance: it is not part of the law and nothing else used it.
  • the eligible_bands parameter.

The CPS expanded-MA contrib reform now overrides meets_marriage_allowance_income_conditions and marriage_allowance_transferable_amount. Its mechanics follow the statute, so a higher-rate recipient saves the basic rate × the amount, not their marginal rate.

How the election is computed

The election depends on the couple's tax with and without it, and the tax depends on the election. So makes_marriage_allowance_election runs two policyengine-core branches, the pattern PE-US uses for itemisation:

  1. No election in force.
  2. Every spouse's own allowance cut by the transferable amount, with no reductions granted.

For each spouse, the saving from electing is the partner's reduction (capped at their Step 5 tax left) minus the elector's extra tax. It is rounded to pennies. The couple elects if the saving is positive and the conditions hold. The spouse with the larger saving elects; on a tie, the elder. Branches are dropped after use.

Overhead: ~20% on small household simulations (noisy, on a loaded machine). Enhanced FRS: see below.

Universal Credit

uc_income_tax_on_earnings (from #1949) takes the recipient's reduction off the tax on their earnings first. That is how HMRC delivers it: gov.uk's tax code letters say code M means "you've received a transfer of 10% of your partner's Personal Allowance". So a pensioner's State Pension no longer changes the earning partner's UC earned income once the couple has elected. The strict xfail test_state_pension_does_not_change_partners_marriage_allowance now passes.

Other Step 6 reductions (married couple's allowance, other_tax_credits) keep #1949's min(tax, income_tax), which sets them against other income first. That is the opposite order, and a comment says so. Married couple's allowance needs a birth before 6 April 1935, so it almost never reaches UC.

Known interaction (intended): the election weighs the couple's income tax, not their UC. At the point where electing stops saving tax, the couple stops electing. The earner's tax then rises by up to £252, and their UC rises by up to 55% of that. test_couple_stops_electing_when_it_no_longer_saves_tax pins an example: 2026, State Pension £12,500 → £12,600, UC £5,509.26 → £5,547.86. A choice rule that also weighed UC would behave differently; that is a separate modelling decision.

Departures in the issue, each now a YAML test

Issue item Test (marriage_allowance.yaml) Old model Law = new model
Worked example (30,000 / 12,000) "Issue example" 3,372 / 0 3,234 / 138
1. Transferor with £15,000 / £12,000 of interest "Issue departure 1" (×2) recipient 3,486 / 3,372 3,234
2. Recipient with £12,570 earnings, £5,000 dividends "Issue departure 2" 483.75 231.75
3. Scottish intermediate-rate recipient "Issue departure 3" saves 264.60 saves 252 (3,199.07)
4. Rounding of the partial unused amount every case: the amount is always 1,260
5. Double counting when both are below the allowance "Issue departure 5" 1,260 each 0
6. Married couple's allowance not checked "Issue departure 6" MA given no election

Also covered:

  • the transferor just under / at the allowance (elect / not);
  • a higher-rate recipient;
  • take-up follows the elder spouse;
  • direction regardless of age order;
  • the cap at Step 5 tax (86);
  • other tax reductions first (186);
  • a tie;
  • children in the unit;
  • the dividend nil-rate vs savings nil-rate straddles;
  • Scottish savings banded on UK rates;
  • the pensioner case from the UC test;
  • 2015-16 (£1,060) and 2019-20 (£1,250).

meets_marriage_allowance_income_conditions.yaml is rewritten on incomes, not tax-band inputs. It includes s. 55C(1)(c) with the cut allowance (50,000 earnings: eligible with the full allowance, ineligible once it falls to 11,310).

Invariants and property tests

test_marriage_allowance_properties.py (Hypothesis). It generates couples and singles with every taxable income type, in England, Wales and Scotland, with children and occasional married couple's allowance claims, for 2019, 2026 and 2027:

  1. The couple's income tax is never higher with the model's election than with none. When the couple elects, it is at least a penny lower.
  2. Differential against brute force: the model's couple tax equals the minimum over {no election, first spouse elects, second spouse elects}, each run with the election fixed and filtered by the statutory conditions computed from those runs.
  3. With the election fixed, the gaining partner's Marriage Allowance, reduction, allowance and income tax do not change when the elector's income of any type rises. The elector's allowance is exactly the uncut allowance less the transferable amount.
  4. Accounting:
    • only spouses elect, at most one per couple;
    • the amount given up equals the amount received in each couple, and is 0 or the transferable amount;
    • the reduction is at most the appropriate percentage × the amount and the Step 5 limit;
    • the gainer's tax falls by exactly the reduction;
    • the elector never pays less.
  5. The couple's income tax, with the model's election, never falls when either spouse gains income.
  6. No one outside a married couple elects, gives up or receives anything.

UC properties now run with Marriage Allowance claimed. test_uc_state_pension_properties.py covers pound-for-pound, non-increasing, and the private-pension and property-income equivalences. test_uc_earnings_deductions_properties.py covers invariants 1-3; the old docstrings said these "switch Marriage Allowance off until this is fixed". Where a property compares two runs, each couple's election is held at its first-run choice, because the election legitimately responds to income.

Mutation testing of these tests is running; results will be added here before the PR leaves draft.

Enhanced FRS impact

Real Microsimulation runs on a private copy of the Enhanced FRS 2024-25 (enhanced_frs_2024_25.h5, sha256 e433e532…). Base is #1949's head d0fc22f and head is this branch (a1a4822); both trees were clean. There are 4 runs per year: base, head, and each with no one claiming (would_claim_marriage_allowance false for all). £m, head minus base:

Year Income tax Household net income UC Pension Credit MA cost, old model MA cost, law Couples electing Reductions
2025 −44.5 +44.5 +0.18 −0.17 293.2 337.6 1.70m 420.0
2026 −50.3 +50.3 +0.20 −0.19 277.7 328.0 1.51m 370.4
2027 −44.1 +44.2 +0.19 −0.15 265.7 309.9 1.44m 356.2
2028 −33.7 +33.9 +0.18 −0.01 262.2 296.0 1.36m 336.8
2029 −30.1 +29.9 −0.04 −0.12 252.0 282.1 1.33m 330.4
2030 −22.4 +22.1 −0.11 −0.22 243.9 266.3 1.31m 327.0

"MA cost" is income tax with no one claiming minus income tax as modelled. Housing Benefit and CTR move by less than £0.01m. Poverty rates (BHC and AHC; all, children, pensioners, working age) are unchanged to 0.001pp in 2026 and 2027, and move by at most 0.011pp in other years.

Differential check: with no one claiming, base and head agree exactly on all 32 recorded person, benefit-unit and household arrays in every year. So this changes nothing but Marriage Allowance.

2026 decomposition (aggregates only):

  • Electing couples. 1.51m couples elect. For 96% of recipients the reduction is the full 20% × 1,260 = 252; for the rest it is capped at their tax. Against the old model, electors' own tax is £42.4m higher and recipients' £95.8m lower.
  • Couples that newly elect (0.29m): they pay £46.4m less. In every one the transferor's adjusted net income is at least the £12,570 allowance, so the old model saw no unused allowance to transfer. 0.25m of these transferors have savings or dividends. In 0.13m of these couples the recipient has dividends.
  • Couples the old model gave MA but that do not elect now (0.61m): their tax rises only £3.1m. Only 0.015m of them saved more than £1 from the old Marriage Allowance. 0.14m had it on both partners (the double counting).
  • Tax moved between partners with no change for the couple: 0.04m people. This is the issue's worked example.
  • Scottish recipients (0.16m) pay £13.7m less.
  • UC changes for 8.1k benefit units, net +£0.2m. In every benefit unit whose UC rises, the tax UC deducts from earnings rose.
  • Household net income rises £50.3m, mostly in deciles 7 (£9.6m) and 9 (£30.1m). 0.39m households gain and 0.10m lose.

Take-up: the dataset draws would_claim_marriage_allowance per person at 50%. The couple's election uses the gaining spouse's draw, the same draw that decided take-up before. A first version used the elder spouse's draw. That reshuffled take-up across ~0.65m couples for no legal reason, so it was dropped; those runs are kept in the review folder.

Runtime: the election's branches add about 0.4–1 s per year to a full Enhanced FRS run, on a heavily loaded machine.

Not modelled

  • residence (s. 55B(2)(c), s. 55C(1)(d), (2)-(4)): the model assumes UK residents;
  • death during the year (s. 55B(7));
  • backdating and continuity of elections (s. 55D);
  • marriages for part of the year.

The rate test inherits the model's own income tax stacking. Chips filed for pre-existing bugs found on the way:

  • savings are not stacked above property income, and the starting-rate taper double-counts the allowance;
  • the dividend upper-rate threshold in 2015-2025;
  • the missing 2016-17 £11,000 allowance, which also makes 2016's transferable amount £1,060, not £1,100;
  • the Scottish PSA is banded on Scottish rates (s. 12B(8)(b)(iv)).

Axiom

axiom: TheAxiomFoundation/rulespec-uk#362 queued (s.55C, extended for this PR with s.55C(1)(ca) and s.55B(2)(ba) and seven more companion cases) + the s.55B re-encode queued in rulespec-uk bulk/worklist.yaml (batch PE-UK-CHILD-DEFS, pending), which already requires the fixed transferable amount, the s.55B(6) cut and the s.55B(1) reduction.

rulespec-uk's s.55B module still caps the transfer at the partner's unused allowance: it encoded the same departure as PolicyEngine. The worklist entry and #362 both called the PolicyEngine side "a separate follow-up"; this is it.

Review

Independent verification (hand computation from the statute, adversarial law and robustness reviews) is running; results will be added before this leaves draft.

🤖 Generated with Claude Code

MaxGhenis and others added 11 commits September 30, 2026 13:26
UC Regs 2013 reg 66(1)(a) counts retirement pension income as unearned
income, and reg 67(1) gives it the State Pension Credit Act 2002 s.16
meaning, which includes the new State Pension (s.16(1)(za)) and the
Category A/B retirement pension (s.16(1)(a)). UC unearned income counted
state_pension from the first calculated UC (0e2d8be, 2020) until
055dce8 (2021-10-27) dropped it in a UC restructure; since then the
list has had private pension income but not State Pension, so mixed-age
couples on UC had their State Pension ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hypothesis properties: UC is non-increasing in State Pension; with no
earnings it falls pound for pound (reg 22(1)(a)); State Pension counts
exactly like private pension income, and like property income when the
family has no earnings. A strict xfail pins #1942, where the benefit
unit's tax on State Pension is deducted from a partner's earnings.

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

uc_earned_income subtracted benunit_tax, the whole benefit unit's income
tax and NI on all income, from the unit's gross earnings. UC Regs 2013
reg. 55(5)(b) and reg. 57(2) step 3 deduct only tax and NI paid by the
person in respect of their employment or trade.

- uc_income_tax_on_earnings: income tax on the person's earnings, taken
  as the lowest slice of their non-savings income after their allowances
  (savings and dividends sit above it under ITA 2007 s. 16, property
  income above it in the engine and under s. 16A from 2027-28).
- uc_national_insurance_on_earnings: Class 1 employee, Class 2, Class 4.
- uc_individual_earned_income: gross earnings less the person's own
  pension contributions, tax and NI, floored at nil.
- uc_earned_income: sum over the unit, less the work allowance.

Fixes #1942.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- test_uc_earnings_deductions_properties.py: unearned income never
  changes earned income; UC is non-increasing in every kind of unearned
  income; the tax deducted equals the tax on earnings alone; earned
  income is never lower, and UC never higher, than under the pre-fix
  formula.
- test_uc_state_pension_properties.py: the #1942 strict xfail now passes
  and loses its marker; pound-for-pound and the property-income
  equivalence cover families with earnings; a new strict xfail pins the
  Marriage Allowance transfer, which the model books on the recipient as
  the transferor's unused allowance (ITA 2007 s. 55B gives a fixed
  reduction).
- Document the earnings deductions in the UC docs page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The transferor's election cuts their own personal allowance by the fixed
transferable amount (s.55B(4)-(6)); the gaining party gets a Step 6 tax
reduction at the basic or Scottish basic rate, capped at their Step 5 tax
(s.55A(2), s.55B(1), (3), s.29(2)). The couple elects only when the
conditions in s.55B(2) and s.55C(1)(b)-(c) hold, no married couple's
allowance is claimed, it lowers their combined income tax, and the elder
spouse's take-up draw is true.

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

YAML cases from ITA 2007 ss.55A-55E, hand-computed, including the issue's
worked example and each departure it lists. The State Pension and
earnings-deduction UC properties now run with Marriage Allowance claimed,
holding each couple's election at its first-run choice; the strict xfail on
the partner's Marriage Allowance now passes, and a new case pins the point
where the couple stops electing.

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

The couple's tax never rises with the model's election, which matches the
cheapest allowed option found by running each election fixed; the gaining
partner's reduction does not depend on the elector's income; transfers
balance and reductions stay within s.55B(1)/(3) and s.29(2); couple tax never
falls with more income.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dataset draws would_claim_marriage_allowance independently per person at
50%. Reading the elder spouse's draw reshuffled take-up across about 0.65m
couples on the Enhanced FRS for no legal reason. The gaining spouse's draw is
the one that decided take-up before, so the same couples claim. Also add the
changelog fragment.

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

s.55B(2)(ba) asks whether dividends would reach the dividend upper rate,
which starts at the basic rate limit (s.13); the dividends scale's own
threshold lags it before 2026-27. State the married premise in the UC
property tests, and correct the comments on why the couples do not elect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tie case no longer asserts income tax, which depended on the model's
fixed allowance order rather than s.25(2). The married couple's allowance
case uses spouses old enough to claim it. The ordering case cites s.27(2)
and s.29(2)-(3); the limit notes s.27(6) for double taxation relief; the
single election per couple is described as a modelling choice, since s.55E
does not bar elections both ways.

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

s.16 puts dividends above property income as well as earnings, so a landlord
whose dividends cross the basic rate limit is liable at the dividend upper
rate (s.55B(2)(ba)). Note that a spouse outside the benefit unit is not
modelled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve the election-independent income tax inputs before branching, so a
reform that branches inside adjusted_net_income gives the same result
whichever variable is asked for first, and free the branch arrays
afterwards. Only a spouse can give allowance up, and spouses must be old
enough to marry (16, the Scottish minimum). On a tie the lower-income spouse
elects. The CPS expanded reform lifts the income condition only when
remove_income_condition is set. Refresh stale comments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit to PolicyEngine/policyengine-uk-data that referenced this pull request Oct 1, 2026
…riage Allowance

The locked policyengine-uk predates PolicyEngine/policyengine-uk#1963. A lock
bump changes the dataset build, so it belongs in its own release. The test
runs as soon as the installed model defines marriage_allowance_relinquished.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Heads-up from #1949, which this stacks on: its head moved from d0fc22f to 514132f with one added commit and no history rewrite. The commit changes two lines in policyengine_uk/tests/test_uc_state_pension_properties.py (#MA_ISSUE → #1947 in the docstring and in the strict xfail's reason) and one sentence in the UC docs page. No formula changed. A rebase onto 514132f should conflict only where this PR removes that xfail marker. Further review fixes to #1949, if any, will also arrive as added commits.

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Update from #1949: its head is now c98c53c, a merge of #1943's new head ce85220, which has main 7b9fc37 merged in. No history rewrite and no formula change. Rebasing or merging onto c98c53c brings in current main, so this PR's impact base moves too. The one conflict #1949 had was the UC docs means-test sentence.

This branch has not been deployed

No deployments
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.

Marriage Allowance is booked on the recipient as the transferor's unused allowance, not the fixed s.55B transfer

1 participant