Skip to content

Fix Scottish tax bands and test Marriage Allowance rates directly - #2828

Open
MaxGhenis wants to merge 36 commits into
mainfrom
fix-2350-scottish-tax-band
Open

MaxGhenis wants to merge 36 commits into
mainfrom
fix-2350-scottish-tax-band

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2350

Reproducer: policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/marriage_allowance_tax_reduction.yaml::A Scottish intermediate-rate recipient with dividends gets 20% of the transferable amount; policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/meets_marriage_allowance_income_conditions.yaml::Under a raised Scottish higher rate, nil-rate savings meet the conditions; policyengine_uk/tests/test_tax_band_scottish_properties.py::test_marriage_allowance_follows_the_liability_with_nil_rates

axiom: TheAxiomFoundation/rulespec-uk#523 queued, with TheAxiomFoundation/rulespec-uk#536 queued for the s. 55B(1) and (3) reduction at Step 6

What and why

tax_band compared a Scottish taxpayer's total taxable income, savings and dividends included, with the Scottish limits. Parliament applies Scottish rates to income other than savings and dividends under ITA 2007 ss. 11A and 13. The Scottish Parliament's 2025-26 resolution (S6M-16531) calls this "non-savings and non-dividend income". Parliament puts savings and dividends at the top of income (s. 16) and charges them at the rates they would bear outside Scotland (ss. 11D(6) and 13(5)). The model already calculated non-savings, savings and dividend liabilities separately.

For a Scottish taxpayer, tax_band now takes the higher of two bands:

  1. the Scottish band of non_savings_income_after_allowances, their income other than savings and dividends after allowances, which go to it first, as in earned_income_tax;
  2. where the person has taxable savings or dividends, the rest-of-UK band of all taxable income (net_income - allowances), since Parliament puts savings and dividends at its top (s. 16).

The model keeps income up to a limit in the lower band. Parliament charges income "up to" a limit at the lower rate (s. 10(2) to (3A)), and the Scottish Parliament charges each Scottish rate "on income above" one limit "and up to" the next. As before, the model raises the Scottish limits from the basic rate's upper limit, and the basic and higher rate limits, by the grossed-up Gift Aid gift, as Parliament requires (s. 414(2)(b)). The model retains nil-rate savings and dividends in their underlying bands. Parliament sets separate rate conditions for the Marriage Allowance (s. 55B).

Marriage Allowance rate conditions

meets_marriage_allowance_income_conditions no longer reads tax_band. It calls liable_only_at_marriage_allowance_rates, which applies s. 55B(2)(b) and (ba) to the person's income. A person fails it when any of these holds:

  • their income other than savings and dividends, after allowances, exceeds the basic rate limit, or for a Scottish taxpayer the start of the Scottish higher rate;
  • some savings above the basic rate limit lie outside the savings nil-rate slice. Savings up to the limit bear a basic rate or the starting rate for savings, both permitted, since Parliament charges the starting rate only on savings that would otherwise bear a basic rate (s. 12(1)). It charges the savings nil rate on the lowest savings above the starting rate limit for savings, up to the savings allowance (s. 12A(1) to (4)). Dividends sit above savings (s. 16) and don't move that slice;
  • their dividends, counted as if the dividend nil rate did not exist (s. 55B(2)(ba) omits s. 13A), take their income past the basic rate limit, where the dividend upper rate starts (ss. 10(3) and 13(2)).

Under s. 414(2)(b), the model raises each limit by the grossed-up gift. Parliament and the Treasury set the permitted rates year by year:

  • 2015-16: the basic rate, the dividend ordinary rate and the starting rate for savings. The Scottish rates of s. 11A start in 2016-17, the year the Treasury appointed (FA 2014 Sch. 38 para. 12, SI 2015/2000 art. 3), so the test holds a Scottish taxpayer to the basic rate limit. Parliament gave the savings nil rate effect from 2016-17 (FA 2016 s. 4(17)), so the test counts no savings nil rate in 2015-16;
  • 2016-17: the Scottish basic rate (the Treasury's SI 2015/1810 art. 14(3)), and the savings and dividend nil rates with s. 55B(2)(ba) (FA 2016 ss. 4(8) and 5(6)). Parliament then charged the Scottish basic rate on the non-savings income that would otherwise bear the basic rate (s. 11A(1) as it stood), so the test again uses the basic rate limit;
  • 2017-18: the Scottish basic rate only, among the Scottish rates, so the test uses the start of the Scottish higher rate, £31,500 of taxable income;
  • from 2018-19: the Scottish starter and intermediate rates too (the Treasury's SI 2018/459 art. 6(2)), so the test uses the start of the Scottish higher rate.

The model's Scottish rate schedule starts in April 2017, and the model reads its first values in earlier years too, so the test sets a Scottish taxpayer's limit by the year, not from that schedule. The test also departs from three historical or reformed parameters that the liability reads. It starts the dividend upper rate at the basic rate limit, where the model's 2015-16 dividend scale starts it at £37,500. It counts no savings nil rate in 2015-16, where the model's Personal Savings Allowance starts in 2005. And it places the savings nil rate above the starting rate limit, where the liability starts it after the income charged at the starting rate. The two agree unless a reform raises that limit above the basic rate limit or changes the starting rate's phase-out, which the test no longer reads.

Parliament charges tax at each rate at Step 4 and takes tax reductions off at Step 6 (s. 23), and it gives the Marriage Allowance as a tax reduction at Step 6 (ss. 55A(2) and 55B(1)). So the allowance never changes the income each rate applies to, and the test never reads it. The test takes non_savings_income_after_allowances, taxable_savings_interest_income, received_allowances_savings_income, savings_allowance (from 2016-17), the starting rate limit for savings, taxable_dividend_income, received_allowances_dividend_income and gift_aid_grossed_up.

The direct test admits people at a permitted rate limit and people whose savings bear permitted nil rates:

  • taxable income exactly at the basic rate limit (or the Scottish higher rate's start, or a limit Gift Aid raised). Parliament charges it at the basic rate (s. 10(2)). tax_band outside Scotland still calls it HIGHER;
  • from 2016-17, people whose income passes the basic rate limit only by savings the savings nil rate covers. Parliament charges those savings at the savings nil rate (s. 12A(3)) and allows that rate for the Marriage Allowance (s. 55B(2)(b)). Under current limits no Scottish taxpayer reaches this case from 2017-18. The nil-rate slice starts at their non-savings income, so it reaches past the basic rate limit only when that income comes within a savings allowance of the limit, above the start of the Scottish higher rate.

Dividends the dividend allowance covers still fail when, without it, they would bear the dividend upper rate. tax_band stays the same for everyone outside Scotland, but the Marriage Allowance conditions move there too. We ran a grid of 4,816 single adults (3,596 of them outside Scotland) on origin/main and on this branch for each year from 2015-16 to 2028-29. Outside Scotland 91 person-years move, all to meeting the conditions:

  • 90 have taxable income exactly at the basic rate limit, or at a limit Gift Aid raised, from 2019-20 on;
  • 1 has savings above the limit that the savings nil rate covers, in 2016-17.

In Scotland 841 person-years move: 833 to meeting the conditions, and 8 in 2017-18 to failing them. Every adult's income_tax and savings_allowance, and every band outside Scotland, match origin/main; Scottish bands change in 3,339 person-years. These synthetic households give no population estimate, and the years after 2026-27 use the model's projections.

The create_expanded_ma_reform CPS reform calls the same helper. It keeps its rule: people meet its conditions when they meet the statutory ones or the reform's expansion conditions. We ran 400 generated married couples, 187 of them with a child, in 2017-18, 2018-19, 2021-22, 2025-26 and 2026-27. The rule holds for every person-year, under this branch's direct test and under conditions read off this branch's tax_band. The statutory conditions move for 21 person-years, the reform's for 20, and the reform's conditions and allowance move for no one whose statutory conditions stay the same.

This PR deletes gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bands, which nothing else read. A reform or saved policy that names it now fails with directions to the rate limits (REMOVED_PARAMETERS).

Marriage Allowance tax reduction

The model used to take the Marriage Allowance off earned_taxable_income (gov.hmrc.income_tax.earned_taxable_income_exclusions). That saved the recipient tax at the rate on their top £1,260 of income other than savings and dividends, and it lowered the base under their savings and dividends. Parliament gives the recipient "a tax reduction for a tax year of the appropriate percentage of the transferable amount" (ITA 2007 s. 55B(1)) at Step 6 (s. 55A(2)). The appropriate percentage is "the basic rate or default basic rate or, in the case of a Scottish taxpayer or Welsh taxpayer, the Scottish basic rate or Welsh basic rate" (s. 55B(3)). The Scottish Parliament set the Scottish basic rate at 20% for 2025-26 (S6M-16531). A reduction comes off "only so far as there is sufficient tax calculated at Step 5", counting "tax reductions already deducted at Step 6" (s. 29(2) and (3)).

This PR gives every recipient that reduction:

  • gov.hmrc.income_tax.earned_taxable_income_exclusions no longer lists marriage_allowance, so the allowance no longer changes earned_taxable_income, non_savings_taxable_income, the savings rate bands or the dividend base.
  • marriage_allowance_appropriate_percentage (new) gives the basic rate, or for a Scottish taxpayer from 2016-17 the Scottish basic rate. It reads the Scottish scale's basic rate band itself (brackets[1]), the way pension_credit_self_employment_deductions reads it. The model has no Welsh rates, so a Welsh taxpayer takes the basic rate.
  • marriage_allowance_tax_reduction (new) gives the appropriate percentage times marriage_allowance and limits it to the Step 5 tax that the reductions listed before it leave (earlier_tax_reductions). gov.hmrc.income_tax.step_6_tax_reductions lists it last. Section 27(5) does not list Chapter 3A, so s. 27(2) sets its place: "the order which will result in the greatest reduction". Each listed reduction has an amount fixed before Step 6, so every order deducts the same total; listing this one last leaves the other reductions' amounts as they were.
  • marriage_allowance keeps the amount the model books today: the transferor's unused personal allowance, up to 10% of the personal allowance, rounded up to £10.

This fixes items 2 and 3 of #1947 for the recipient: a recipient taxed mostly on dividends or savings now gets the reduction in full, and a Scottish recipient gets 20%, not their marginal rate. We ran each case on this branch and at e5b16d14b (the branch before this change), for a married earner whose spouse earns £5,000:

2025-26 unless stated e5b16d14b This branch Law
Scotland: £40,000 pay, £5,000 dividends £5,711.97 £5,724.57 £5,976.57 - 20% x £1,260 = £5,724.57
Scotland: £40,000 pay, £5,000 savings £6,118.22 £6,130.82 £6,382.82 - £252 = £6,130.82
Scotland: £40,000 pay £5,318.22 £5,330.82 £5,582.82 - £252 = £5,330.82
Scotland: £14,000 pay £32.30 £19.70 £1,430 x 19% - £252 = £19.70
England: £17,570 pay, £3,000 savings £896.00 £1,148.00 £1,000 + £400 - £252 = £1,148
England, 2026-27: £12,570 pay, £5,000 dividends £483.75 £231.75 £4,500 x 10.75% - £252 = £231.75
England: £30,000 pay £3,234.00 £3,234.00 £3,486 - £252 = £3,234
England: £13,500 pay £0.00 £0.00 £186 - min(£252, £186) = £0

In the first row household net income falls from £41,919.12 to £41,906.53. In the fifth, the old deduction cut the earner's taxable pay below the £5,000 starting rate limit for savings, so £1,260 of interest bore the 0% starting rate as well. The old model saved them £504 rather than £252. uc_income_tax_on_earnings takes the Step 6 reductions off the tax on earnings, so Universal Credit's deduction for income tax follows the change. The Scottish £40,000 earner's deduction rises by £12.60, from £5,318.22 to £5,330.82, and the English £30,000 earner's stays at £3,234.

Readers of the old deduction

  • uc_income_tax_on_earnings and uc_income_tax_on_trade read both lists, so they follow the change with no code change (above).
  • pension_credit_self_employment_deductions takes marriage_allowance off the profit at a single notional rate, the basic rate or the Scottish basic rate. At one rate, with both floored at zero, rate x max(0, profit - reliefs - amount) equals max(0, rate x max(0, profit - reliefs) - rate x amount), and the married couple's allowance comes off after either. A million random draws of profit, reliefs, allowance, married couple's allowance and rate give the same notional tax both ways to within £0.000000000004. Its comment now says this; the code stays the same.
  • uc_earnings_deductions.yaml's case that sets its own exclusions list no longer lists marriage_allowance.
  • The CPS reform (create_expanded_ma_reform) redefines marriage_allowance; marriage_allowance_tax_reduction reads the reform's allowance, and a property test checks that under the reform a higher- or additional-rate recipient's tax falls by 20% of the allowance (£252 in 2025-26), not 40% or 45%.
  • non_savings_taxable_income, higher_rate_savings_income, add_rate_savings_income, basic_rate_savings_income, savings_starter_rate_income and dividend_income_tax read marriage_allowance through earned_taxable_income at e5b16d14b. They no longer do. property_income_band_base.yaml's Case 7 pinned the old base for Marriage Allowance is booked on the recipient as the transferor's unused allowance, not the fixed s.55B transfer #1947; it now gives £17,430, not £16,170, and income tax of £3,234.
  • Give Scotland and Wales working-age CTR their own rules #1966's devolved route reads the tax on a person's pensions and benefits as earned_income_tax, which comes before Step 6, less uc_income_tax_on_earnings. With the reduction at Step 6, that difference keeps tax the reduction has cancelled: for a Welsh earner with £13,000 of pay, a £3,000 pension and a partner's £1,260, the route would disregard £686 on the pension, £252 more than they pay. working_age_unearned_income_tax now takes the reductions off through earnings_tax_reductions, which uc_income_tax_on_earnings_slice shares, so the route disregards £434. A new case in council_tax_reduction_devolved_working_age.yaml takes that through to an award of £460.12.
  • The docstrings of liable_only_at_marriage_allowance_rates and non_savings_taxable_income, invariant 2's note in test_property_income_band_base_properties.py, docs/engineering/gift-aid.md and marriage_allowance/max.yaml now describe the reduction. The rate test computes the same thing as before.

The rest-of-UK band needs savings or dividends

The issue proposes the higher of the Scottish band of non-savings income and the rest-of-UK band of total taxable income. That second band measures the savings and dividends only when the person has some. Without them it lifts a Scottish starter-rate taxpayer to BASIC: in 2018-19, £12,570 of pay leaves £720 of taxable income, all at the 19% starter rate, and the proposal gives BASIC. The existing case Scottish intermediate rate recognised (2022-23, £14,650 of income, STARTER) fails under the proposal. This PR applies the rest-of-UK band only when the person has taxable savings or dividends.

Other years

The same band formula now runs from 2017-18. The model dispatches annual formulas at 1 January, so before this PR:

  • In 2017-18 the model ran the formula for earlier years and banded Scottish taxpayers on the rest-of-UK limits. The model labelled £44,000 of pay, £1,000 of it at the 40% Scottish higher rate, BASIC, and the earner met the Marriage Allowance conditions, though in 2017-18 Parliament allowed only the Scottish basic rate (s. 55B(2)(b)).
  • In 2018-19 it ran the 2017-18 formula, which read the first three of the five Scottish limits as the basic, higher and additional limits. So the model labelled every Scottish taxpayer with more than £12,150 of taxable income ADDITIONAL.

Labels

TaxBand has no advanced or top label, so ADDITIONAL covers the Scottish advanced and top rates and the savings and dividend additional rates. HIGHER covers the Scottish higher rate and the savings higher and dividend upper rates. STARTER and INTERMEDIATE come from the Scottish band only.

What reads tax_band, and what moves

  • meets_marriage_allowance_income_conditions and the CPS reform no longer read it.

  • marriage_allowance and income_tax move for married couples whose earner now meets, or no longer meets, the conditions. We ran an earner whose spouse earns £5,000 on origin/main and on this branch:

    Year and earner's income Earner's band Marriage Allowance Earner's income tax
    2025-26, Scotland: £40,000 pay, £5,000 dividends HIGHER → INTERMEDIATE £0 → £1,260 £5,976.57 → £5,724.57
    2025-26, Scotland: £40,000 pay, £5,000 savings HIGHER → INTERMEDIATE £0 → £1,260 £6,382.82 → £6,130.82
    2018-19, Scotland: £40,000 pay, £5,000 dividends ADDITIONAL → INTERMEDIATE £0 → £1,190 £5,995.00 → £5,757.00
    2017-18, Scotland: £44,000 pay BASIC → HIGHER £1,150 → £0 £6,270.00 → £6,700.00
    2025-26, England: £50,270 pay HIGHER £0 → £1,260 £7,540.00 → £7,288.00
    2025-26, England: £50,070 pay, £500 savings HIGHER £0 → £1,260 £7,500.00 → £7,248.00
    2025-26, England: £50,070 pay, £500 dividends HIGHER £0 £7,500.00
    2025-26, England: £40,000 pay, £5,000 dividends BASIC £1,260 £5,627.75

    The spouse pays no income tax in any row. Where the earner has the allowance, it now saves them the appropriate percentage of it: 20% x £1,260 = £252 in 2025-26 and 20% x £1,190 = £238 in 2018-19. origin/main deducted it from earned income, so in the 2017-18 row it saved £430, taking £1,000 out of the 40% band and £150 out of the 20% band; under this branch that earner fails the conditions. These synthetic households give no population estimate.

  • Counts of taxpayers by marginal rate move, since Scottish taxpayers move to the band their income reaches (One consistent UK target surface: enforced cross-grain reconciliation, declared uprating holds, nation household controls and the 942a1fa re-pin (#1123 PR A) microcosm#1198 binds HMRC's Scottish higher and additional rate counts on tax_band). In the 4,816-adult grid, 3,129 of the 3,339 Scottish band changes move down; the grid gives no population shares. The other 210 move up: 8 Scottish taxpayers in 2017-18 above the Scottish higher-rate limit, and 202 starter-rate taxpayers with some savings or dividends, whom the model now bands BASIC. The model charges savings that low at the 0% starting rate for savings and such dividends at the nil or ordinary rate, and the band counts nil-rate income where it sits.

  • savings_allowance does not read tax_band. Since the fix for Personal Savings Allowance uses the Scottish bands for Scottish taxpayers (ITA 2007 s. 12B(8)) #2347 it sets the Personal Savings Allowance on the rest-of-UK bands itself (s. 12B(8)), and its documentation now says so. This PR does not move it: test_savings_allowance_does_not_read_the_band forces every band as an input and the allowance stays the same, and the 4,816-adult differential above finds no change in it.

Microcosm's engine test test_scottish_savings_and_dividends_count_against_the_scottish_thresholds pins the issue's first case (Scotland, £40,000 of pay and £5,000 of dividends, HIGHER). With this change the model gives INTERMEDIATE, so that test fails until Microcosm updates it.

Existing tests changed

  • The eleventh row (index 10) of the test_gift_aid.py bit-for-bit snapshot, a Scottish taxpayer in 2026-27 with no pay, £10,000 of property income, £20,000 of savings and £10,000 of dividends, moves from INTERMEDIATE to BASIC. The model sets the allowance against all the property income, so no income bears a Scottish rate (s. 11A), and the remaining £27,430 of savings and dividends falls below the £37,700 UK basic rate limit (ss. 11D(6) and 13(5)). Its other eleven rows and every other snapshot value stay the same.

  • On origin/main, the six cases in meets_marriage_allowance_income_conditions.yaml set tax_band as an input. They now set the income that puts a person in each band; every expected value stays the same.

  • test_marriage_allowance_cps_switch.py's invariant 5 pinned the CPS reform's values from before the reduction: with the reform on, the £60,000 earner saved 40% of the allowance. Its expected tax now comes from s. 55B(1) and (3): £11,432 - 20% x £1,260 = £11,180 at the reform's 10% rate, and £11,432 - 20% x £2,520 = £10,928 at 20%, in place of £10,928 and £10,424.

  • property_income_band_base.yaml's Case 7 pinned the old Marriage Allowance base for Marriage Allowance is booked on the recipient as the transferor's unused allowance, not the fixed s.55B transfer #1947; it now gives £17,430 and income tax of £3,234 (above).

  • pension_credit_earnings_disregard.yaml's two Scottish couple cases for 2025-26 pinned the old deduction. In both, the claimant has £12,000 of State Pension and £16,000 of private pension, and the partner has no taxable income. The first case adds £1,040 of pay. The claimant's taxable income exceeds £14,921, where the Scottish intermediate rate starts, both with pay (£16,470) and without (£15,430), so all of the pay bears 21%. Before the Marriage Allowance, tax comes to £2,827 x 19% + £12,094 x 20% + £1,549 x 21% = £3,281.22 with pay and £3,062.82 without. Parliament takes 20% x £1,260 = £252 off each at Step 6 (s. 55B), and four outputs change:

    Output Old New
    income_tax, with pay £3,016.62 £3,029.22
    income_tax, without pay £2,805.73 £2,810.82
    pension_credit_earnings_disregard, with pay £829.11 £821.60
    pension_credit_income, both cases £25,194.27 £25,189.18

    The pay adds £3,029.22 - £2,810.82 = £218.40 of tax (all £1,040 at 21%), and the claimant pays no Class 1 contributions above State Pension age. Net earnings come to £821.60, and the £20-a-week disregard, up to £1,040 a year, covers them in full. Pension Credit income stays the same with and without pay: £29,040 - £3,029.22 - £821.60 = £28,000 - £2,810.82 = £25,189.18. Main deducts the £1,260 from the claimant's taxable income instead, which leaves £14,170 without pay, below where the intermediate rate starts. So £751 of the pay bears 20% and £289 bears 21%, adding £210.89 of tax.

  • Main added test_step_6_puts_the_pension_tax_allowance_after_every_other_reduction after this branch's base. This branch lists the Marriage Allowance after the Pension Tax Allowance, so the test becomes test_step_6_lists_the_pension_and_marriage_allowances_last. Both reductions have amounts fixed before Step 6, so the order leaves the total as it was.

  • Main also added test_council_tax_reduction_pensioner_children_tariff_properties.py, which pins a Scottish couple on £25,000 of pay in 2019-20 at £24,674.64 of Council Tax Reduction income and a £460.78 award. Taxable income now stays £12,500, so its last £350 reach the 21% band: £380 + £2,030 + £73.50 - £250 = £2,233.50 of tax, against £2,230 with the allowance off taxable income. Income falls to £24,671.14, and the award rises by 20% of £3.50 to £461.48.

  • test_marriage_allowance_cps_switch.py's invariant 3 read eligible_bands. It now checks that no one with taxable income above the basic rate limit, or above £31,092 (the start of the Scottish higher rate) for a Scottish taxpayer, meets the conditions or has the allowance, and that everyone else meets them.

Known limits, unchanged here

Overlap

#1963 (draft, marriage-allowance-election at 69c919f) models the Marriage Allowance as the statutory transfer and Step 6 reduction. Both branches define liable_only_at_marriage_allowance_rates in the same file, and this branch now adds marriage_allowance_appropriate_percentage and marriage_allowance_tax_reduction under #1963's names. This branch deducts the reduction after the reductions listed before it in step_6_tax_reductions, through earlier_tax_reductions, and has no marriage_allowance_tax_reduction_limit. #1963 conflicts with this branch's head, which merges main at a866277, in 21 files: marriage_allowance/max.yaml, income_tax_subtractions.yaml, the CPS reform, pension_credit_earnings_disregard.yaml, meets_marriage_allowance_income_conditions.yaml, property_income_band_base.yaml, test_marriage_allowance_cps_switch.py, test_aggregate_impact_measure.py, test_property_income_properties.py, test_state_pension_components.py, measure.py, basic_state_pension.py, new_state_pension.py, pension_credit_self_employment_deductions.py, marriage_allowance.py, marriage_allowance_appropriate_percentage.py, marriage_allowance_tax_reduction.py, meets_marriage_allowance_income_conditions.py, uses_property_allowance.py, non_savings_taxable_income.py and property_finance_cost_relief.py. Nine of those (income_tax_subtractions.yaml, test_aggregate_impact_measure.py, test_property_income_properties.py, test_state_pension_components.py, measure.py, basic_state_pension.py, new_state_pension.py, uses_property_allowance.py and property_finance_cost_relief.py) conflict with main at a866277 itself.

#2830 (fix-2106-allowance-order at 6602ccc) conflicts with this branch in non_savings_income_after_allowances.py and in test_property_income_band_base_properties.py, whose invariant 2 note both branches rewrite. #2841 (fix-2782-tax-band-boundaries at a15905c) conflicts in tax_band.py, which both branches change. #2830 and #2841 merge cleanly with main at a866277, and #1963 conflicts with it as above.

#2670 also edits create_expanded_ma_reform (its child condition). No other open PR touches these files.

We ran 1,000 generated households in all four nations (607 married couples and 393 single adults) for each year from 2015-16 to 2028-29. This branch's rate test and #1963's at 69c919f agree in 22,497 of 22,498 person-years, couples included. In the one difference, in 2016-17, a single Scottish taxpayer with £20,519 of pay, £22,267 of property income and £1 of interest has £31,786 of taxable income other than savings and dividends. This branch holds them to the £32,000 basic rate limit and finds the conditions met, where #1963 uses the £31,500 that the model's Scottish schedule shows in that year.

Merge notes

Invariants

The property tests assert these on generated cases:

  1. With the starting rate for savings, the Personal Savings Allowance and the dividend allowance set to zero, every single Scottish taxpayer pays tax at their band's rates on some income and at no higher band's rates; with no band they pay no tax.
  2. With the baseline nil-rate amounts, no single Scottish taxpayer pays tax at the higher or additional rates above their band.
  3. With the nil-rate amounts set to zero, the Marriage Allowance income conditions hold for a single Scottish taxpayer exactly when they pay nothing at the higher or additional rates.
  4. With the baseline nil-rate amounts and with reformed limits and amounts, the conditions hold for every single person in England, and in Scotland from 2017-18, exactly when the liability charges no income at a rate s. 55B(2)(b) forbids and, without the dividend allowance, no dividends at the dividend upper or additional rate. The reforms change the start of the Scottish higher rate, the basic rate limit (with the dividend upper rate moved to it, where Parliament starts it (s. 13(2))), the starting rate limit for savings up to the basic rate limit, the Personal Savings Allowance or the dividend allowance. So savings at a nil rate never stop the allowance.
  5. From 2019-20, the band never rises against the formula before this PR, except from STARTER to BASIC where savings or dividends sit below the Scottish starter limit: they sit in the rest-of-UK basic band.
  6. With the CPS expanded reform on, its conditions equal the statutory conditions or its expansion conditions.

test_marriage_allowance_tax_reduction_properties.py asserts these on generated married couples in England, Scotland, Wales and Northern Ireland, with pay, private pensions, savings and dividends drawn freely, in 2016-17, 2017-18, 2018-19, 2021-22, 2025-26 and 2026-27:

  1. For every person, income_tax equals the income tax with would_claim_marriage_allowance false, less the smaller of the appropriate percentage of marriage_allowance and the Step 5 tax that the earlier reductions leave.
  2. The reduction does not depend on the recipient's marginal rate. Under the CPS expanded reform, which gives the allowance to recipients in every band, a recipient with enough tax gets the appropriate percentage of the allowance, 20% in each year drawn, and their income tax falls by that amount. A fixed case checks £252 for 2025-26 recipients with £60,000 and £150,000 of pay in England and £60,000 in Scotland.
  3. The election does not move the rate test: meets_marriage_allowance_income_conditions gives the same result with would_claim_marriage_allowance true and false.
  4. The reduction lies between zero and the appropriate percentage of the allowance, the Step 6 reductions together never exceed the Step 5 tax, and the allowance never changes the Step 5 tax.

We ran a grid of 896 married couples in each year from 2015-16 to 2028-29 (25,088 person-years) at e5b16d14b and on this branch. The earner has £0 to £130,000 of pay (14 levels) and no other income, £3,000 of interest, £5,000 of dividends or £10,000 of private pension; the spouse earns £0, £5,000, £11,000 or £20,000; the couple lives in England, Scotland, Wales or Northern Ireland. Across the grid, two invariants hold:

  1. meets_marriage_allowance_income_conditions gives the same result in all 25,088 person-years, and marriage_allowance stays the same in every one.
  2. Everyone without the allowance pays the same income_tax: every person-year whose income_tax moves has the allowance.

test_council_tax_reduction_devolved_working_age_properties.py adds one on #1966's route:

  1. For a family whose taxed income is pay and a private pension, uc_income_tax_on_earnings and council_tax_reduction_working_age_unearned_income_tax add to the family's income tax, so a Step 6 reduction neither disappears nor counts twice.

For everyone outside Scotland, tax_band stays the same. For single people anywhere, income_tax and savings_allowance stay the same.

On the same grid, against e5b16d14b, the reduction moves income_tax in these person-years, all of them Marriage Allowance recipients (6,272 person-years in each nation):

Nation Recipients Tax rises Tax falls
England 1,708 34 33
Wales 1,708 34 33
Northern Ireland 1,708 34 33
Scotland 1,522 316 141

household_net_income moves in the same couples, the other way: 33 households rise and 34 fall in each of England, Wales and Northern Ireland, and 141 rise and 316 fall in Scotland (3,136 household-years in each nation). Outside Scotland, tax rises only for earners with £14,000 or £18,000 of pay and £3,000 of interest, whose deduction used to open the 0% starting rate band for savings (up to £199.20). It falls only for earners with £12,570 of pay and £5,000 of dividends, whose tax the deduction could not reach (from 2018-19, by £26 to £252). In Scotland tax rises by up to £12.60 for earners whose top £1,260 of non-savings income bore the 21% intermediate rate (with pay only, dividends or a pension). With savings it rises by up to £199.20 (2027-28: £18,000 of pay and £3,000 of interest, £1,073.77 to £1,272.97). It falls by up to £12.60 where that slice bore the 19% starter rate, and by up to £252 for earners whose tax comes mostly from dividends. The largest falls, £252, come in 2022-23 and later for earners with £12,570 of pay and £5,000 of dividends (2022-23: £262.50 to £10.50). Universal Credit's uc_income_tax_on_earnings rises in 234 person-years and falls in 144. These synthetic households give no population estimate, and the years after 2026-27 use the model's projections.

Invariant 4 compares the test with the model's liability, so its reforms hold the starting rate limit at or below the basic rate limit, the range in which the model's liability places the savings nil rate where Parliament does (s. 12A). It also leaves out Scottish taxpayers before 2017-18, and its years start in 2016-17. YAML cases worked from the statute cover those: the 2015-16 dividend and savings cases at the model's £32,000 limit and at the statutory £31,785, and the two cases under a raised starting rate limit.

Test plan

  • YAML tests whose expected values come from an external source: new cases in scottish_rates.yaml and meets_marriage_allowance_income_conditions.yaml, which we worked by hand from ITA 2007, FA 2016, SI 2015/1810, SI 2018/459 and the Scottish rate resolutions. Both files pass: 36 and 31 cases.
  • marriage_allowance_tax_reduction.yaml: 16 cases worked by hand from ss. 55B(1) and (3) and 29(2) and (3), S6M-16531 and the parameter files, with the arithmetic in each comment. All pass.
  • Scoped Ruff format and lint checks, the repository F811/F821 check, and git diff --check.
  • Changelog fragment changelog.d/2350.fixed.md.

We ran these locally with no survey data:

  • scottish_rates.yaml: 36 passed.
  • meets_marriage_allowance_income_conditions.yaml: 31 passed.
  • We ran liable_only_at_marriage_allowance_rates on 200,000 generated sets of non-savings, savings and dividend income, basic rate limits, starting rate limits, savings allowances, Gift Aid, years and nations. It agrees in every case with a hand-worked oracle of ss. 10, 12, 12A and 13 and FA 2016 s. 4(17).
  • HMRC income tax YAML directory (policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/): 570 passed.
  • At 2ca7c5ff7, which merges main at 9dd44e1: pension_credit_earnings_disregard.yaml, 34 passed; the whole policyengine_uk/tests/policy/baseline YAML tree, 5,589 passed and none failed; scottish_rates.yaml, meets_marriage_allowance_income_conditions.yaml, marriage_allowance_tax_reduction.yaml, marriage_allowance_statutory_rate.yaml and marriage_allowance.yaml together, 96 passed. When we put marriage_allowance back on the exclusions list and took the reduction off the Step 6 list, the two Scottish Pension Credit cases failed on income_tax (£3,016.62 and £2,805.73) and the file's other 32 passed. With -n 4, the eleven property and snapshot files above together with test_marriage_allowance_cps_switch.py: 245 passed and 1 xfailed (the same strict xfail). code_health: 3,150 passed. Ruff 0.17.2 format and lint, the F811/F821 check and git diff --check: clean. The head, e511964cb, changes only a comment in pension_credit_earnings_disregard.yaml after 2ca7c5ff7.
  • Every other YAML file that names marriage_allowance: marriage_allowance.yaml 7, marriage_allowance_statutory_rate.yaml 6, marriage_allowance_tax_reduction.yaml 16, property_income_band_base.yaml 7, property_finance_cost_relief.yaml 21, gift_aid.yaml 23, tax_band_historical.yaml 16, uc_earnings_deductions.yaml 15, uc_mif_earned_income.yaml 29, uc_is_responsible_carer.yaml 8 and pension_credit_statutory_pay_earnings.yaml 12, all passed.
  • marriage_tax_reforms.yaml: 10 passed.
  • integration/income.yaml: 8 passed.
  • test_tax_band_scottish_properties.py: 5 passed.
  • test_marriage_allowance_cps_switch.py: 45 passed.
  • With -n 4: test_marriage_allowance_tax_reduction_properties.py, test_tax_band_scottish_properties.py, test_gift_aid.py, test_income_tax_step_6_step_7_properties.py, test_property_income_band_base_properties.py, test_pension_credit_earnings_disregard_properties.py, test_uc_state_pension_properties.py, test_uc_income_from_capital_properties.py, test_uc_unearned_benefits_properties.py, test_deterministic_variables.py and test_dated_reform_routes.py together: 200 passed and 1 xfailed. The strict xfail test_state_pension_does_not_change_partners_marriage_allowance still fails: the recipient's allowance still reads the transferor's unused personal allowance (Marriage Allowance is booked on the recipient as the transferor's unused allowance, not the fixed s.55B transfer #1947, Model Marriage Allowance as the statutory s.55B transfer and Step 6 reduction #1963).
  • code_health: 3,095 passed.
  • Ruff 0.17.2 format and lint, the F811/F821 check and git diff --check: clean.

We ran each mutation of the reduction on a copy of the branch, against marriage_allowance_tax_reduction.yaml (16 cases), marriage_allowance_statutory_rate.yaml (6), property_income_band_base.yaml (7), uc_earnings_deductions.yaml (15), meets_marriage_allowance_income_conditions.yaml (31), marriage_tax_reforms.yaml (10) and the three property tests:

Mutation Reduction YAML Other YAML Property tests
Revert: marriage_allowance back on the exclusions list, the reduction off the Step 6 list 8 fail Case 7 of property_income_band_base.yaml fails 3 fail
Keep marriage_allowance on the exclusions list as well as the reduction 8 fail 2 statutory-rate cases, Case 7 and the UC Marriage Allowance case fail 3 fail
Take the reduction at the recipient's top non-savings rate the 4 Scottish cases fail all pass 3 fail
Drop the Step 5 limit the 2 limit cases fail all pass the test of invariants 7, 9 and 10 fails (at 7); the other 2 pass

No mutation changes the rate test's 31 cases or the CPS reform's 10.

We ran one-line mutations of the Marriage Allowance test and of tax_band against both YAML files:

Mutation Marriage Allowance YAML (31 cases) scottish_rates.yaml (36 cases) Cases that fail
Dividend upper rate read from the model's dividend scale 2 fail all pass the two 2015-16 dividend cases
Savings nil rate counted in 2015-16 2 fail all pass the two 2015-16 savings cases
Savings nil-rate slice starts at non-savings income, not at the starting rate limit 1 fails all pass the £37,500 starting rate limit case
Scottish limit before 2017-18 read off the 2017-18 schedule 2 fail all pass the 2015-16 and 2016-17 Scottish cases
Savings test on all taxable income instead of non-savings income and savings all pass all pass none (see below)
tax_band without the Gift Aid rise in the UK limits all pass 1 fails Scottish 2025 dividends at the Gift Aid limit
tax_band puts income at the UK additional limit above it all pass 1 fails Scottish 2025 savings at the higher rate limit
tax_band reads earned_taxable_income all pass 2 fail both property-income cases at the higher rate limit

Under the £5,000 starting rate limit, a slice that starts at non-savings income and one that starts at the larger of it and the limit give the same answer: where they differ, both end below the basic rate limit. So only a raised starting rate limit separates the slice mutation, and the YAML case under a £37,500 limit does. The savings-test mutation changes the savings result only where dividends sit above the savings and take income past the basic rate limit. There the dividend test already fails the person. So no input whose net income equals the sum of its non-savings, savings and dividend income separates the mutation at the helper's output, and the 200,000-case differential above finds no difference with it either. A supplied adjusted_net_income below the income components breaks that equality and separates them.

🤖 Generated with Claude Code

MaxGhenis and others added 28 commits October 31, 2026 18:42
tax_band compared a Scottish taxpayer's total taxable income, savings and
dividends included, with the Scottish limits. The Scottish rates charge
only income that is neither savings nor dividend income (ITA 2007 s. 11A),
and savings and dividends take the rest-of-UK bands (ss. 11D(6), 13(5)).
The band is now the higher of the Scottish band of non-savings income and,
where any taxable income is savings or dividends, the rest-of-UK band of
all taxable income. Income at a limit stays in the lower band.

The same formula now runs from 2017-18: before, 2017-18 used the
rest-of-UK limits for Scottish taxpayers and 2018-19 read the five-rate
Scottish schedule as the three-rate one. Other taxpayers are unchanged.

Fixes #2350

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cases with hand-worked arithmetic for the issue's Scottish incomes with
dividends and with savings, both limits at once, one pound above the basic
rate limit, Gift Aid, allowances beyond pay, starter-rate pay, 2017-18 and
2018-19, with rest-of-UK controls. Eleven fail on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For Scottish taxpayers the tests raise one band's rates at a time and
check that a person in a band pays tax at that band's rates and at no
higher band's, that the Marriage Allowance conditions match, and that
against the formula before #2350 the band rises only from starter to
basic. They also show savings_allowance does not read tax_band.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tenth snapshot row is a Scottish taxpayer with no pay and 10,000 of
property income, 20,000 of savings and 10,000 of dividends. The allowance
takes all the property income, so nothing is charged at a Scottish rate
(ITA 2007 s. 11A), and the 27,430 of savings and dividends left sit below
the basic rate limit (ss. 11D(6) and 13(5)). The band is basic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
meets_marriage_allowance_income_conditions stops reading tax_band. It ports
liable_only_at_marriage_allowance_rates from #1963 and computes it from
income before the Marriage Allowance, since this head still takes the
allowance off earned_taxable_income: non-savings income up to the start of
the Scottish higher rate or the basic rate limit, savings above the limit
only where the savings nil rate and the starting rate for savings cover
them, and dividends counted without the dividend allowance (s. 55B(2)(ba)).
The CPS expanded reform reads the same helper, and the eligible_bands
parameter, which nothing else read, goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The model's Scottish scale carries its 2017-18 values back to 2015-16 and
2016-17, so the rate test's empty-scale branch never ran and it read the
31,500 Scottish higher-rate start for those years. In 2016-17 s. 11A(1)
charged the Scottish basic rate on income that would otherwise bear the
basic rate, and 2015-16 had no Scottish rate, so the test now uses the basic
rate limit before 2017-18. The property test leaves Scottish taxpayers out
before 2017-18, where the model's liability uses the carried-back scale, and
Ruff formats its limits table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
property_income is profit, and with no receipts given the model applies no
property allowance to a profit above 1,000, so the two cases now give
31,092 and 31,093 of profit directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scenario's parameter_changes takes numbers only, so a list of bands failed
validation before the removal check. The test now passes the saved list
through Reform.from_dict and Scenario.from_reform, which check the path
first, and checks the alias stays in the parameter tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FA 2014 Sch. 38 para. 12 gives s. 11A effect from the year the Treasury
appointed under s. 25(5) of the Scotland Act 2012, and SI 2015/2000 art. 3
appoints 2016-17.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Under a starting rate limit raised to 40,000, the model charges 37,700 of
38,000 of interest at the starting rate for savings and the rest at the
savings nil rate, both of which s. 55B(2)(b) allows. Baseline limits never
separate the starting rate from the savings nil rate in this test.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comments only: the Treasury adds the Scottish basic rate, a reform raises
the starting rate limit, and the model reads its 2017-18 Scottish scale in
earlier years.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Section 13(2) charges the dividend upper rate on dividends that would
otherwise bear the higher rate, which s. 10(3) starts at the basic rate
limit. The model's dividend scale holds 37,500 in 2015-16, against a
32,000 basic rate limit, so the test read it there and admitted dividends
the statute charges at the upper rate. The property ties the dividend
scale to a reformed basic rate limit instead of drawing it on its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FA 2016 s. 4 inserted the savings nil rate (ss. 12A and 12B) and added it
to s. 55B(2)(b), with effect for 2016-17 and later years (s. 4(17)). The
model's Personal Savings Allowance amounts start in 2005, so the test
counted a nil rate in 2015-16 that the law didn't have.

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

Section 12(1) charges the starting rate for savings only on savings that
would otherwise bear a basic rate, so it never reaches past the basic rate
limit. Section 12A(1) to (4) charges the savings nil rate on the lowest
savings above the starting rate limit, up to the savings allowance. The
test now fails a person when any savings above the basic rate limit lie
outside that slice, instead of starting the slice where the starting rate
ends.

Under a starting rate limit of 40,000, 12,570 of pay and 38,000 of
interest leave 300 above the basic rate limit at the savings higher rate,
so that case now fails the conditions. A new case under a 37,500 limit
meets them: s. 12 charges 37,500 at the starting rate and s. 12A the 500
above it at the savings nil rate. The property keeps a reformed starting
rate limit at or below the basic rate limit, where the model's savings
liability places the nil rate as s. 12A does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rate test's notes now say which rates s. 55B(2)(b) permits each year
and where the test follows the statute against the model's liability.
tax_band, savings_allowance, non_savings_income_after_allowances and the
CPS reform's conditions variable describe what each now does, and the
Scottish rates cases name the band each reaches. The changelog fragment
names the income conditions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comments and one case name only: the 2015-16 cases say which rates
s. 55B(2)(b) permits, and the property's Marriage Allowance section names
its nil-rate amounts and reforms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Documentation only: the rate test's docstring and
non_savings_income_after_allowances name s. 414(2)(b) as what raises the
rate limits, and the docstring drops a passive phrase.

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

With pay of 50,070 the least-tax allocation of the personal allowance
(ITA 2007 s. 25(2)) can move a pound of allowance onto the savings and
take the last pound of interest into the savings nil rate. Pay at the
basic rate limit leaves no allocation that lowers the tax, so the case
gives 40p of savings tax and fails the conditions either way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6GDsfRzbSb9XEm12wG
Rewrite the rate-test, tax_band and test notes so that the body that
makes each rule acts, with the section in brackets, and keep statutory
quotations as they are. Rename the two pre-2017-18 Scottish cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6GDsfRzbSb9XEm12wG
The tax_band docstring names each Scottish rate resolution as the source of
"on income above" one limit "and up to" the next, and the Scottish rates
YAML comment cites ITA 2007 s. 11A(1A), (4) and (5) and s. 13, since
s. 11A itself excludes only savings income. Text only.

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

Copy link
Copy Markdown
Collaborator Author

Thanks for the review (review). We moved the branch to 89f2f9f34.

  • C1: every recipient now gets the s. 55B(1) reduction at Step 6, in place of the deduction from earned income. marriage_allowance_appropriate_percentage gives the basic rate, or from 2016-17 the Scottish basic rate for a Scottish taxpayer (s. 55B(3)). marriage_allowance_tax_reduction takes that percentage of marriage_allowance off the Step 5 tax that the reductions listed before it leave (s. 29(2) and (3)), and step_6_tax_reductions lists it last. Your case now gives income tax of £5,724.57 and household net income of £41,906.53, against £5,711.97 and £41,919.12 at e5b16d14b, and the savings analogue gives £6,130.82 against £6,118.22. marriage_allowance_tax_reduction.yaml pins both, among 16 cases we worked by hand from ss. 55B and 29 and S6M-16531.
  • We changed it for every recipient, not only the newly admitted. If the model kept the old deduction for the others, a Scottish recipient with £40,000 of pay alone would still save 21% of £1,260 (£264.60), and one who also had £5,000 of dividends would save £252.
  • Other readers follow the change. uc_income_tax_on_earnings takes the Step 6 reductions off the tax on earnings, so the Scottish £40,000 earner's Universal Credit deduction for income tax rises by £12.60. An English earner with £17,570 of pay and £3,000 of interest now pays £1,148 rather than £896, since the old deduction also opened £1,260 of the 0% starting rate band for savings. test_marriage_allowance_cps_switch.py now expects 20% of the allowance under the CPS reform: £11,180 and £10,928, in place of £10,928 and £10,424.
  • test_marriage_allowance_tax_reduction_properties.py checks generated couples in all four nations. Income tax falls by the smaller of the appropriate percentage of the allowance and the Step 5 tax left, the reduction never depends on the marginal rate, and the election leaves the rate test alone. On a grid of 25,088 person-years, the rate test and marriage_allowance give the same results as at e5b16d14b, and only allowance recipients' income tax moves.
  • Reverting the change fails 8 of the 16 new cases, Case 7 of property_income_band_base.yaml and all 3 property tests. Taking the reduction at the recipient's top non-savings rate fails the 4 Scottish cases and all 3 property tests.

The transferor side, the election, and #1947's rounding and double count stay with #1963. The known limits now link #2865 (the 2015-16 parameters), #2866 (Scottish taxpayers before 2017-18) and #2867 (the savings nil-rate slice under a raised starting rate limit). We queued the reduction's encoding as TheAxiomFoundation/rulespec-uk#536, beside #523.

@MaxGhenis
MaxGhenis requested a review from juaristi22 November 3, 2026 23:10

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed 89f2f9f34d3a39ea5909e1f8e3b8feed8047392e. COMPLETE — original C1 resolved; one required completion fix remains.

The Step6 reduction fixes the Scottish cash error. The £1,260 allowance now gives £252 relief, with the original dividend/savings cases producing tax £5,724.57/£6,130.82 and household net-income gains of £252. The remaining-liability cap also works: £86 of tax remaining permits £86 relief. The operative statutory treatment and appropriate-percentage history were independently checked.

C2 — Record the encoder blocker in actual queued issue #536. .github/CONTRIBUTING.md:61 requires: “Use queued only when the signed encoder is blocked; record the blocker in the issue.” The filed issue has the law, modules, outputs and companion cases, but neither its body nor comments state the blocker. #523 records one, but #536 does not incorporate it. Add the applicable blocker to #536, or explicitly incorporate the precise shared blocker. This requires completing the queued record; it does not require running the encoder or requesting another approval. No new tax-payment defect was found.

A1 — Update the adjacent Pension Credit test expectations. The exact-head YAML job has two failures in pension_credit_earnings_disregard.yaml: expected tax £3,016.62/£2,805.73, actual £3,029.22/£2,810.82. The old expectations reflect the removed income-exclusion method; the new figures follow the £252 Step6 reduction. Update these source-backed expectations and check the downstream disregard/Pension Credit assertions, which the failed tax assertion prevented the job from reaching. This is not a new claim of incorrect tax paid.

Validation: 139 local tests and six native final-income cases passed, with exact snapshot pins verified; independent source review checked 33 originals/extracts. Hosted YAML separately recorded 5,550 passes and those two failures. Its log was inspected without another local test run. Hosted CI readiness is unmet.

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed the updated source record at unchanged head 89f2f9f34d3a39ea5909e1f8e3b8feed8047392e. COMPLETE — C1 and C2 resolved; A1 remains open. No material source gaps.

The actual #536 Blocker section now records the approval, signing and corpus prerequisites, satisfying C2. Its substantive law, outputs and companion cases remain supported. The original tax correction and retained139 passing tests/six native cases remain valid; no code tests were repeated.

A1 still needs fixing: the unchanged Pension Credit YAML still expects tax £3,016.62/£2,805.73, while the corrected formula produces £3,029.22/£2,810.82. Update those expectations and check the downstream disregard/Pension Credit assertions. Exact-head hosted YAML/Result checks still fail, so approval remains withheld.

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Picking this up for the UK hub. Reply here if you're mid-change and I'll stop.


Generated by Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6GW4VyFJ2Wtu8apY8j
…ance reduction

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6GW4VyFJ2Wtu8apY8j
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

PR_BODY.md

Fixes #2350

Reproducer: `policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/marriage_allowance_tax_reduction.yaml::A Scottish intermediate-rate recipient with dividends gets 20% of the transferable amount`; `policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/meets_marriage_allowance_income_conditions.yaml::Under a raised Scottish higher rate, nil-rate savings meet the conditions`; `policyengine_uk/tests/test_tax_band_scottish_properties.py::test_marriage_allowance_follows_the_liability_with_nil_rates`

axiom: TheAxiomFoundation/rulespec-uk#523 queued, with TheAxiomFoundation/rulespec-uk#536 queued for the s. 55B(1) and (3) reduction at Step 6

## What and why

`tax_band` compared a Scottish taxpayer's total taxable income, savings and dividends included, with the Scottish limits. Parliament applies Scottish rates to income other than savings and dividends under ITA 2007 ss. 11A and 13. The Scottish Parliament's 2025-26 resolution (S6M-16531) calls this "non-savings and non-dividend income". Parliament puts savings and dividends at the top of income (s. 16) and charges them at the rates they would bear outside Scotland (ss. 11D(6) and 13(5)). The model already calculated non-savings, savings and dividend liabilities separately.

For a Scottish taxpayer, `tax_band` now takes the higher of two bands:

1. the Scottish band of `non_savings_income_after_allowances`, their income other than savings and dividends after allowances, which go to it first, as in `earned_income_tax`;
2. where the person has taxable savings or dividends, the rest-of-UK band of all taxable income (`net_income - allowances`), since Parliament puts savings and dividends at its top (s. 16).

The model keeps income up to a limit in the lower band. Parliament charges income "up to" a limit at the lower rate (s. 10(2) to (3A)), and the Scottish Parliament charges each Scottish rate "on income above" one limit "and up to" the next. As before, the model raises the Scottish limits from the basic rate's upper limit, and the basic and higher rate limits, by the grossed-up Gift Aid gift, as Parliament requires (s. 414(2)(b)). The model retains nil-rate savings and dividends in their underlying bands. Parliament sets separate rate conditions for the Marriage Allowance (s. 55B).

### Marriage Allowance rate conditions

`meets_marriage_allowance_income_conditions` no longer reads `tax_band`. It calls `liable_only_at_marriage_allowance_rates`, which applies s. 55B(2)(b) and (ba) to the person's income. A person fails it when any of these holds:

- their income other than savings and dividends, after allowances, exceeds the basic rate limit, or for a Scottish taxpayer the start of the Scottish higher rate;
- some savings above the basic rate limit lie outside the savings nil-rate slice. Savings up to the limit bear a basic rate or the starting rate for savings, both permitted, since Parliament charges the starting rate only on savings that would otherwise bear a basic rate (s. 12(1)). It charges the savings nil rate on the lowest savings above the starting rate limit for savings, up to the savings allowance (s. 12A(1) to (4)). Dividends sit above savings (s. 16) and don't move that slice;
- their dividends, counted as if the dividend nil rate did not exist (s. 55B(2)(ba) omits s. 13A), take their income past the basic rate limit, where the dividend upper rate starts (ss. 10(3) and 13(2)).

Under s. 414(2)(b), the model raises each limit by the grossed-up gift. Parliament and the Treasury set the permitted rates year by year:

- 2015-16: the basic rate, the dividend ordinary rate and the starting rate for savings. The Scottish rates of s. 11A start in 2016-17, the year the Treasury appointed (FA 2014 Sch. 38 para. 12, SI 2015/2000 art. 3), so the test holds a Scottish taxpayer to the basic rate limit. Parliament gave the savings nil rate effect from 2016-17 (FA 2016 s. 4(17)), so the test counts no savings nil rate in 2015-16;
- 2016-17: the Scottish basic rate (the Treasury's SI 2015/1810 art. 14(3)), and the savings and dividend nil rates with s. 55B(2)(ba) (FA 2016 ss. 4(8) and 5(6)). Parliament then charged the Scottish basic rate on the non-savings income that would otherwise bear the basic rate (s. 11A(1) as it stood), so the test again uses the basic rate limit;
- 2017-18: the Scottish basic rate only, among the Scottish rates, so the test uses the start of the Scottish higher rate, £31,500 of taxable income;
- from 2018-19: the Scottish starter and intermediate rates too (the Treasury's SI 2018/459 art. 6(2)), so the test uses the start of the Scottish higher rate.

The model's Scottish rate schedule starts in April 2017, and the model reads its first values in earlier years too, so the test sets a Scottish taxpayer's limit by the year, not from that schedule. The test also departs from three historical or reformed parameters that the liability reads. It starts the dividend upper rate at the basic rate limit, where the model's 2015-16 dividend scale starts it at £37,500. It counts no savings nil rate in 2015-16, where the model's Personal Savings Allowance starts in 2005. And it places the savings nil rate above the starting rate limit, where the liability starts it after the income charged at the starting rate. The two agree unless a reform raises that limit above the basic rate limit or changes the starting rate's phase-out, which the test no longer reads.

Parliament charges tax at each rate at Step 4 and takes tax reductions off at Step 6 (s. 23), and it gives the Marriage Allowance as a tax reduction at Step 6 (ss. 55A(2) and 55B(1)). So the allowance never changes the income each rate applies to, and the test never reads it. The test takes `non_savings_income_after_allowances`, `taxable_savings_interest_income`, `received_allowances_savings_income`, `savings_allowance` (from 2016-17), the starting rate limit for savings, `taxable_dividend_income`, `received_allowances_dividend_income` and `gift_aid_grossed_up`.

The direct test admits people at a permitted rate limit and people whose savings bear permitted nil rates:

- taxable income exactly at the basic rate limit (or the Scottish higher rate's start, or a limit Gift Aid raised). Parliament charges it at the basic rate (s. 10(2)). `tax_band` outside Scotland still calls it `HIGHER`;
- from 2016-17, people whose income passes the basic rate limit only by savings the savings nil rate covers. Parliament charges those savings at the savings nil rate (s. 12A(3)) and allows that rate for the Marriage Allowance (s. 55B(2)(b)). Under current limits no Scottish taxpayer reaches this case from 2017-18. The nil-rate slice starts at their non-savings income, so it reaches past the basic rate limit only when that income comes within a savings allowance of the limit, above the start of the Scottish higher rate.

Dividends the dividend allowance covers still fail when, without it, they would bear the dividend upper rate. `tax_band` stays the same for everyone outside Scotland, but the Marriage Allowance conditions move there too. We ran a grid of 4,816 single adults (3,596 of them outside Scotland) on `origin/main` and on this branch for each year from 2015-16 to 2028-29. Outside Scotland 91 person-years move, all to meeting the conditions:

- 90 have taxable income exactly at the basic rate limit, or at a limit Gift Aid raised, from 2019-20 on;
- 1 has savings above the limit that the savings nil rate covers, in 2016-17.

In Scotland 841 person-years move: 833 to meeting the conditions, and 8 in 2017-18 to failing them. Every adult's `income_tax` and `savings_allowance`, and every band outside Scotland, match `origin/main`; Scottish bands change in 3,339 person-years. These synthetic households give no population estimate, and the years after 2026-27 use the model's projections.

The `create_expanded_ma_reform` CPS reform calls the same helper. It keeps its rule: people meet its conditions when they meet the statutory ones or the reform's expansion conditions. We ran 400 generated married couples, 187 of them with a child, in 2017-18, 2018-19, 2021-22, 2025-26 and 2026-27. The rule holds for every person-year, under this branch's direct test and under conditions read off this branch's `tax_band`. The statutory conditions move for 21 person-years, the reform's for 20, and the reform's conditions and allowance move for no one whose statutory conditions stay the same.

This PR deletes `gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bands`, which nothing else read. A reform or saved policy that names it now fails with directions to the rate limits (`REMOVED_PARAMETERS`).

### Marriage Allowance tax reduction

The model used to take the Marriage Allowance off `earned_taxable_income` (`gov.hmrc.income_tax.earned_taxable_income_exclusions`). That saved the recipient tax at the rate on their top £1,260 of income other than savings and dividends, and it lowered the base under their savings and dividends. Parliament gives the recipient "a tax reduction for a tax year of the appropriate percentage of the transferable amount" (ITA 2007 s. 55B(1)) at Step 6 (s. 55A(2)). The appropriate percentage is "the basic rate or default basic rate or, in the case of a Scottish taxpayer or Welsh taxpayer, the Scottish basic rate or Welsh basic rate" (s. 55B(3)). The Scottish Parliament set the Scottish basic rate at 20% for 2025-26 ([S6M-16531](https://www.parliament.scot/chamber-and-committees/votes-and-motions/S6M-16531)). A reduction comes off "only so far as there is sufficient tax calculated at Step 5", counting "tax reductions already deducted at Step 6" (s. 29(2) and (3)).

This PR gives every recipient that reduction:

- `gov.hmrc.income_tax.earned_taxable_income_exclusions` no longer lists `marriage_allowance`, so the allowance no longer changes `earned_taxable_income`, `non_savings_taxable_income`, the savings rate bands or the dividend base.
- `marriage_allowance_appropriate_percentage` (new) gives the basic rate, or for a Scottish taxpayer from 2016-17 the Scottish basic rate. It reads the Scottish scale's basic rate band itself (`brackets[1]`), the way `pension_credit_self_employment_deductions` reads it. The model has no Welsh rates, so a Welsh taxpayer takes the basic rate.
- `marriage_allowance_tax_reduction` (new) gives the appropriate percentage times `marriage_allowance` and limits it to the Step 5 tax that the reductions listed before it leave (`earlier_tax_reductions`). `gov.hmrc.income_tax.step_6_tax_reductions` lists it last. Section 27(5) does not list Chapter 3A, so s. 27(2) sets its place: "the order which will result in the greatest reduction". Each listed reduction has an amount fixed before Step 6, so every order deducts the same total; listing this one last leaves the other reductions' amounts as they were.
- `marriage_allowance` keeps the amount the model books today: the transferor's unused personal allowance, up to 10% of the personal allowance, rounded up to £10.

This fixes items 2 and 3 of #1947 for the recipient: a recipient taxed mostly on dividends or savings now gets the reduction in full, and a Scottish recipient gets 20%, not their marginal rate. We ran each case on this branch and at `e5b16d14b` (the branch before this change), for a married earner whose spouse earns £5,000:

| 2025-26 unless stated | `e5b16d14b` | This branch | Law |
|---|---|---|---|
| Scotland: £40,000 pay, £5,000 dividends | £5,711.97 | £5,724.57 | £5,976.57 - 20% x £1,260 = £5,724.57 |
| Scotland: £40,000 pay, £5,000 savings | £6,118.22 | £6,130.82 | £6,382.82 - £252 = £6,130.82 |
| Scotland: £40,000 pay | £5,318.22 | £5,330.82 | £5,582.82 - £252 = £5,330.82 |
| Scotland: £14,000 pay | £32.30 | £19.70 | £1,430 x 19% - £252 = £19.70 |
| England: £17,570 pay, £3,000 savings | £896.00 | £1,148.00 | £1,000 + £400 - £252 = £1,148 |
| England, 2026-27: £12,570 pay, £5,000 dividends | £483.75 | £231.75 | £4,500 x 10.75% - £252 = £231.75 |
| England: £30,000 pay | £3,234.00 | £3,234.00 | £3,486 - £252 = £3,234 |
| England: £13,500 pay | £0.00 | £0.00 | £186 - min(£252, £186) = £0 |

In the first row household net income falls from £41,919.12 to £41,906.53. In the fifth, the old deduction cut the earner's taxable pay below the £5,000 starting rate limit for savings, so £1,260 of interest bore the 0% starting rate as well. The old model saved them £504 rather than £252. `uc_income_tax_on_earnings` takes the Step 6 reductions off the tax on earnings, so Universal Credit's deduction for income tax follows the change. The Scottish £40,000 earner's deduction rises by £12.60, from £5,318.22 to £5,330.82, and the English £30,000 earner's stays at £3,234.

### Readers of the old deduction

- `uc_income_tax_on_earnings` and `uc_income_tax_on_trade` read both lists, so they follow the change with no code change (above).
- `pension_credit_self_employment_deductions` takes `marriage_allowance` off the profit at a single notional rate, the basic rate or the Scottish basic rate. At one rate, with both floored at zero, rate x max(0, profit - reliefs - amount) equals max(0, rate x max(0, profit - reliefs) - rate x amount), and the married couple's allowance comes off after either. A million random draws of profit, reliefs, allowance, married couple's allowance and rate give the same notional tax both ways to within £0.000000000004. Its comment now says this; the code stays the same.
- `uc_earnings_deductions.yaml`'s case that sets its own exclusions list no longer lists `marriage_allowance`.
- The CPS reform (`create_expanded_ma_reform`) redefines `marriage_allowance`; `marriage_allowance_tax_reduction` reads the reform's allowance, and a property test checks that under the reform a higher- or additional-rate recipient's tax falls by 20% of the allowance (£252 in 2025-26), not 40% or 45%.
- `non_savings_taxable_income`, `higher_rate_savings_income`, `add_rate_savings_income`, `basic_rate_savings_income`, `savings_starter_rate_income` and `dividend_income_tax` read `marriage_allowance` through `earned_taxable_income` at `e5b16d14b`. They no longer do. `property_income_band_base.yaml`'s Case 7 pinned the old base for #1947; it now gives £17,430, not £16,170, and income tax of £3,234.
- The docstrings of `liable_only_at_marriage_allowance_rates` and `non_savings_taxable_income`, invariant 2's note in `test_property_income_band_base_properties.py`, `docs/engineering/gift-aid.md` and `marriage_allowance/max.yaml` now describe the reduction. The rate test computes the same thing as before.

### The rest-of-UK band needs savings or dividends

The issue proposes the higher of the Scottish band of non-savings income and the rest-of-UK band of total taxable income. That second band measures the savings and dividends only when the person has some. Without them it lifts a Scottish starter-rate taxpayer to `BASIC`: in 2018-19, £12,570 of pay leaves £720 of taxable income, all at the 19% starter rate, and the proposal gives `BASIC`. The existing case `Scottish intermediate rate recognised` (2022-23, £14,650 of income, `STARTER`) fails under the proposal. This PR applies the rest-of-UK band only when the person has taxable savings or dividends.

### Other years

The same band formula now runs from 2017-18. The model dispatches annual formulas at 1 January, so before this PR:

- In 2017-18 the model ran the formula for earlier years and banded Scottish taxpayers on the rest-of-UK limits. The model labelled £44,000 of pay, £1,000 of it at the 40% Scottish higher rate, `BASIC`, and the earner met the Marriage Allowance conditions, though in 2017-18 Parliament allowed only the Scottish basic rate (s. 55B(2)(b)).
- In 2018-19 it ran the 2017-18 formula, which read the first three of the five Scottish limits as the basic, higher and additional limits. So the model labelled every Scottish taxpayer with more than £12,150 of taxable income `ADDITIONAL`.

### Labels

`TaxBand` has no advanced or top label, so `ADDITIONAL` covers the Scottish advanced and top rates and the savings and dividend additional rates. `HIGHER` covers the Scottish higher rate and the savings higher and dividend upper rates. `STARTER` and `INTERMEDIATE` come from the Scottish band only.

### What reads `tax_band`, and what moves

- `meets_marriage_allowance_income_conditions` and the CPS reform no longer read it.
- `marriage_allowance` and `income_tax` move for married couples whose earner now meets, or no longer meets, the conditions. We ran an earner whose spouse earns £5,000 on `origin/main` and on this branch:

  | Year and earner's income | Earner's band | Marriage Allowance | Earner's income tax |
  |---|---|---|---|
  | 2025-26, Scotland: £40,000 pay, £5,000 dividends | `HIGHER` → `INTERMEDIATE` | £0 → £1,260 | £5,976.57 → £5,724.57 |
  | 2025-26, Scotland: £40,000 pay, £5,000 savings | `HIGHER` → `INTERMEDIATE` | £0 → £1,260 | £6,382.82 → £6,130.82 |
  | 2018-19, Scotland: £40,000 pay, £5,000 dividends | `ADDITIONAL` → `INTERMEDIATE` | £0 → £1,190 | £5,995.00 → £5,757.00 |
  | 2017-18, Scotland: £44,000 pay | `BASIC` → `HIGHER` | £1,150 → £0 | £6,270.00 → £6,700.00 |
  | 2025-26, England: £50,270 pay | `HIGHER` | £0 → £1,260 | £7,540.00 → £7,288.00 |
  | 2025-26, England: £50,070 pay, £500 savings | `HIGHER` | £0 → £1,260 | £7,500.00 → £7,248.00 |
  | 2025-26, England: £50,070 pay, £500 dividends | `HIGHER` | £0 | £7,500.00 |
  | 2025-26, England: £40,000 pay, £5,000 dividends | `BASIC` | £1,260 | £5,627.75 |

  The spouse pays no income tax in any row. Where the earner has the allowance, it now saves them the appropriate percentage of it: 20% x £1,260 = £252 in 2025-26 and 20% x £1,190 = £238 in 2018-19. `origin/main` deducted it from earned income, so in the 2017-18 row it saved £430, taking £1,000 out of the 40% band and £150 out of the 20% band; under this branch that earner fails the conditions. These synthetic households give no population estimate.
- Counts of taxpayers by marginal rate move, since Scottish taxpayers move to the band their income reaches (PolicyEngine/microcosm#1198 binds HMRC's Scottish higher and additional rate counts on `tax_band`). In the 4,816-adult grid, 3,129 of the 3,339 Scottish band changes move down; the grid gives no population shares. The other 210 move up: 8 Scottish taxpayers in 2017-18 above the Scottish higher-rate limit, and 202 starter-rate taxpayers with some savings or dividends, whom the model now bands `BASIC`. The model charges savings that low at the 0% starting rate for savings and such dividends at the nil or ordinary rate, and the band counts nil-rate income where it sits.
- `savings_allowance` does not read `tax_band`. Since the fix for #2347 it sets the Personal Savings Allowance on the rest-of-UK bands itself (s. 12B(8)), and its documentation now says so. This PR does not move it: `test_savings_allowance_does_not_read_the_band` forces every band as an input and the allowance stays the same, and the 4,816-adult differential above finds no change in it.

Microcosm's engine test `test_scottish_savings_and_dividends_count_against_the_scottish_thresholds` pins the issue's first case (Scotland, £40,000 of pay and £5,000 of dividends, `HIGHER`). With this change the model gives `INTERMEDIATE`, so that test fails until Microcosm updates it.

### Existing tests changed

- The eleventh row (index 10) of the `test_gift_aid.py` bit-for-bit snapshot, a Scottish taxpayer in 2026-27 with no pay, £10,000 of property income, £20,000 of savings and £10,000 of dividends, moves from `INTERMEDIATE` to `BASIC`. The model sets the allowance against all the property income, so no income bears a Scottish rate (s. 11A), and the remaining £27,430 of savings and dividends falls below the £37,700 UK basic rate limit (ss. 11D(6) and 13(5)). Its other eleven rows and every other snapshot value stay the same.
- On `origin/main`, the six cases in `meets_marriage_allowance_income_conditions.yaml` set `tax_band` as an input. They now set the income that puts a person in each band; every expected value stays the same.
- `test_marriage_allowance_cps_switch.py`'s invariant 5 pinned the CPS reform's values from before the reduction: with the reform on, the £60,000 earner saved 40% of the allowance. Its expected tax now comes from s. 55B(1) and (3): £11,432 - 20% x £1,260 = £11,180 at the reform's 10% rate, and £11,432 - 20% x £2,520 = £10,928 at 20%, in place of £10,928 and £10,424.
- `property_income_band_base.yaml`'s Case 7 pinned the old Marriage Allowance base for #1947; it now gives £17,430 and income tax of £3,234 (above).
- `pension_credit_earnings_disregard.yaml`'s two Scottish couple cases (2025-26: the claimant has £12,000 of State Pension and £16,000 of private pension, with and without £1,040 of pay; the partner has no taxable income) pinned the old deduction. The claimant's taxable income of £16,470 (with pay) and £15,430 (without) already exceeds £14,921, the start of the Scottish intermediate rate, so the pay does not cross into that band. Before the Marriage Allowance, tax comes to £2,827 x 19% + £12,094 x 20% + £1,549 x 21% = £3,281.22 with pay and £3,062.82 without; the s. 55B reduction takes off 20% x £1,260 = £252 from each. So:

  | Output | Old | New |
  |---|---|---|
  | `income_tax`, with pay | £3,016.62 | £3,029.22 |
  | `income_tax`, without pay | £2,805.73 | £2,810.82 |
  | `pension_credit_earnings_disregard`, with pay | £829.11 | £821.60 |
  | `pension_credit_income`, both cases | £25,194.27 | £25,189.18 |

  The pay adds £3,029.22 - £2,810.82 = £218.40 of tax (all £1,040 at 21%), no Class 1 contributions above State Pension age, so net earnings come to £821.60 and the £20-a-week disregard of £1,040 stops there. Pension Credit income stays the same with and without pay: £29,040 - £3,029.22 - £821.60 = £28,000 - £2,810.82 = £25,189.18. The old deduction took £1,260 off the claimant's taxable income, to £14,170 without pay, below the intermediate rate's start. So £751 of the pay bore 20% and £289 bore 21%, and the pay added £210.89 of tax.
- `test_marriage_allowance_cps_switch.py`'s invariant 3 read `eligible_bands`. It now checks that no one with taxable income above the basic rate limit, or above £31,092 (the start of the Scottish higher rate) for a Scottish taxpayer, meets the conditions or has the allowance, and that everyone else meets them.

### Known limits, unchanged here

- Outside Scotland, from 2018-19 `tax_band` puts taxable income exactly at a limit in the band above, and pay equal to the personal allowance in `BASIC`, where Parliament charges income up to a limit at the lower rate (s. 10). #1963 pins the first at £50,270 of pay. The Marriage Allowance no longer reads the band, so this affects counts by marginal rate only. #2782 tracks it.
- The model tests only the receiving spouse. Parliament also bars an election by a spouse who, with their allowance cut by the transferable amount, would be liable above the permitted rates (s. 55C(1)(c)); #1947 tracks this and #1963 models it.
- `marriage_allowance` still books the transferor's unused personal allowance on the recipient, up to 10% of the personal allowance and rounded up to £10. Parliament instead fixes the transferable amount (s. 55B(4) and (5)) and cuts the transferor's own allowance by it (s. 55B(6)). The rest of #1947 (the fixed transfer, the transferor's reduced allowance, the election and its conditions, the rounding of a partial amount and the double count) stays with #1963. `test_state_pension_does_not_change_partners_marriage_allowance` still fails, as its strict xfail expects.
- For 2018-19 the model's Scottish higher-rate limit and rate (£31,500 of taxable income and 40%, which the model keeps until 2021-22) differ from the Scottish Parliament's 2018-19 resolution (£31,580 and 41%, S5M-10397). #2783 tracks the historical Scottish rates and limits; this branch's cases sit clear of the changed limit.
- The code tells the Scottish schedules apart by their number of limits (three in 2017-18), as `first_extended_scottish_threshold` already does, so a reform that changes the number of Scottish brackets gets wrong labels.
- The model's Scottish rate schedule starts in April 2017, and the model reads its first values in 2015-16 and 2016-17 too. So `earned_income_tax` charges a Scottish taxpayer 40% above £31,500 of taxable pay in those years, where Parliament taxed that pay on the rest-of-UK limits. In 2015-16, £42,200 of pay leaves £31,600 of taxable pay, below the statutory £31,785 limit, and the model charges a Scottish taxpayer £6,340 against £6,320 in England. In 2016-17, £43,000 of pay leaves £32,000, the basic rate limit Parliament set for 2016-17 (FA 2015 s. 4(1)(a), as Finance (No. 2) Act 2015 s. 6(a) amended it), and the model charges £6,500 against £6,400. The Marriage Allowance test uses the basic rate limit in those years. A Scottish taxpayer can therefore meet this income test while the model charges some of their income at 40% in 2015-16 or 2016-17. The property test leaves those Scottish taxpayers out (#2866).
- Parliament set the basic rate limit at £31,785 for 2015-16 (s. 10(5)); the model uses £32,000. In 2015-16 the model's dividend scale also starts the dividend upper rate at £37,500, and its Personal Savings Allowance applies from 2005. The model's liability keeps these values, and the Marriage Allowance test follows the statute instead (#2865).
- When a reform raises the starting rate limit for savings above the basic rate limit, the model's savings liability starts the savings nil rate where the starting rate ends, and Parliament starts it at the limit (s. 12A). Under a £40,000 limit, with £12,570 of pay and £38,000 of interest, the test fails the conditions. The model charges no savings tax there, where Parliament charges £120 on the £300 above the basic rate limit (ss. 11D and 12A) (#2867).

### Overlap

#1963 (draft, `marriage-allowance-election` at 69c919f60) models the Marriage Allowance as the statutory transfer and Step 6 reduction. Both branches define `liable_only_at_marriage_allowance_rates` in the same file, and this branch now adds `marriage_allowance_appropriate_percentage` and `marriage_allowance_tax_reduction` under #1963's names. This branch deducts the reduction after the reductions listed before it in `step_6_tax_reductions`, through `earlier_tax_reductions`, and has no `marriage_allowance_tax_reduction_limit`. Against this branch's head, which merges `main` at 9dd44e142, git conflicts with #1963 in 19 files: `marriage_allowance/max.yaml`, `income_tax_subtractions.yaml`, the CPS reform, `pension_credit_earnings_disregard.yaml`, `meets_marriage_allowance_income_conditions.yaml`, `property_income_band_base.yaml`, `test_marriage_allowance_cps_switch.py`, `test_property_income_properties.py`, `test_state_pension_components.py`, `basic_state_pension.py`, `new_state_pension.py`, `pension_credit_self_employment_deductions.py`, `marriage_allowance.py`, `marriage_allowance_appropriate_percentage.py`, `marriage_allowance_tax_reduction.py`, `meets_marriage_allowance_income_conditions.py`, `uses_property_allowance.py`, `non_savings_taxable_income.py` and `property_finance_cost_relief.py`. Seven of those (`income_tax_subtractions.yaml`, `test_property_income_properties.py`, `test_state_pension_components.py`, `basic_state_pension.py`, `new_state_pension.py`, `uses_property_allowance.py` and `property_finance_cost_relief.py`) conflict with `main` at 9dd44e142 itself.

#2830 (`fix-2106-allowance-order` at 6602ccce4) conflicts with this branch in `non_savings_income_after_allowances.py`, as before, and now in `test_property_income_band_base_properties.py`, whose invariant 2 note both branches rewrite. #2841 (`fix-2782-tax-band-boundaries` at a15905ca8) conflicts in `tax_band.py`, which this change does not touch. Git merges #2830 and #2841 cleanly with `main` at 9dd44e142, and #1963 conflicts with it as above.

#2670 also edits `create_expanded_ma_reform` (its child condition). No other open PR touches these files.

We ran 1,000 generated households in all four nations (607 married couples and 393 single adults) for each year from 2015-16 to 2028-29. This branch's rate test and #1963's at 69c919f6 agree in 22,497 of 22,498 person-years, couples included. In the one difference, in 2016-17, a single Scottish taxpayer with £20,519 of pay, £22,267 of property income and £1 of interest has £31,786 of taxable income other than savings and dividends. This branch holds them to the £32,000 basic rate limit and finds the conditions met, where #1963 uses the £31,500 that the model's Scottish schedule shows in that year.

#### Merge notes

- This branch merges `main` at 9dd44e142. Its head merges with that `main` without conflicts.
- In `pension_credit_earnings_disregard.yaml`, #1963 gives the two Scottish couple cases the same `income_tax`, `pension_credit_earnings_disregard` and `pension_credit_income` as this branch and adds Pension Credit outputs below them, so #1963 can take its own side of that conflict.

- When #1963 rebases onto this branch, it keeps this branch's helper, both callers, the removed-parameter migration and the regression cases. The helper carries the pre-2017-18 year rule for Scottish taxpayers, the strict comparisons at each limit, the Gift Aid extensions and the dividend test on the basic rate limit, and it places the savings nil rate from 2016-17 above the starting rate limit.
- #1963 also keeps this branch's reduction: `marriage_allowance_appropriate_percentage` (which reads the Scottish basic rate band, `brackets[1]`, and gives the basic rate before 2016-17), `marriage_allowance_tax_reduction` (limited through `earlier_tax_reductions`), its place last in `step_6_tax_reductions.yaml`, the removal of `marriage_allowance` from `earned_taxable_income_exclusions.yaml`, and `marriage_allowance_tax_reduction.yaml`. #1963's `income_tax_subtractions.yaml` entry goes, since `origin/main` lists Step 6 reductions in `step_6_tax_reductions.yaml`. Where #1963's election reads `marriage_allowance_tax_reduction_limit`, it can compute the same limit from `income_tax_pre_charges` less `earlier_tax_reductions`.
- #1963 still brings the transferor side and the election: the fixed transferable amount (s. 55B(4) and (5)), the transferor's reduced personal allowance (s. 55B(6)), the election and its conditions (s. 55C), and the fixes for #1947's rounding of a partial amount (item 4) and double count (item 5). Its expected values for the recipient's tax should come out the same, since both branches give 20% of the transferable amount at Step 6.
- The helper's docstring on this branch replaces the two paragraphs it shared with #1963. #1963 should take this wording:

  > Apply the rates Parliament permits for the tax year (s. 55B(2)(b) and s. 55C(1)(c)). From 2016-17 these include the savings nil rate; from 2018-19 the Scottish list includes rates below basic and the intermediate rate. Where s. 55B(2)(ba) and s. 55C(1)(ca) apply, test dividends as if s. 13A were omitted.
  >
  > Parliament extends the rate limits by the grossed-up Gift Aid gift (s. 414(2)(b)); the gift does not reduce taxable income. Before 2017-18 this test uses the basic rate limit for Scottish taxpayers, even though the model's historical Scottish liability currently reads the 2017-18 schedule. The test also follows the statute where the model's liability departs from it: it starts the dividend upper rate at the basic rate limit (ss. 10 and 13), counts no savings nil rate before 2016-17 (FA 2016 s. 4(17)), and places the nil-rate slice above the starting rate limit for savings (s. 12A).
- For #2830, take #2830's `non_savings_income_after_allowances.py` and replace its last documentation sentence, "property_income_tax, taxable_property_income_after_allowances and earned_taxable_income read it, and non_savings_taxable_income reads it through the last two.", with "property_income_tax, taxable_property_income_after_allowances, earned_taxable_income, the Marriage Allowance rate test and, for Scottish taxpayers, tax_band read it, and non_savings_taxable_income reads it through taxable_property_income_after_allowances and earned_taxable_income." In `test_property_income_band_base_properties.py`, take #2830's invariant 2 and replace "with no Marriage Allowance, " and "(earned_taxable_income also subtracts Marriage Allowance; #1947)" with a closing sentence: "The Marriage Allowance does not enter it: the model gives the allowance as a tax reduction at Step 6 (ITA 2007 s. 55B(1))." `earned_taxable_income_exclusions.yaml` no longer lists `marriage_allowance`, so #2830's `IGNORED_EXCLUSIONS` no longer changes anything and can go. We merged #2830's head into a copy of this branch's head, taking #2830's side of both conflicts. The merge computes `income_tax` with no cycle, and five of the households in the table above give the same income tax as on this branch (£5,724.57, £6,130.82, £19.70, £1,148 and £231.75). The HMRC allowance YAML directory (248 cases) and `property_income_band_base.yaml` (7 cases) pass on it.
- #2841 conflicts only in `tax_band.py`, which this change leaves as it was at `e5b16d14b`.
## Invariants

The property tests assert these on generated cases:

1. With the starting rate for savings, the Personal Savings Allowance and the dividend allowance set to zero, every single Scottish taxpayer pays tax at their band's rates on some income and at no higher band's rates; with no band they pay no tax.
2. With the baseline nil-rate amounts, no single Scottish taxpayer pays tax at the higher or additional rates above their band.
3. With the nil-rate amounts set to zero, the Marriage Allowance income conditions hold for a single Scottish taxpayer exactly when they pay nothing at the higher or additional rates.
4. With the baseline nil-rate amounts and with reformed limits and amounts, the conditions hold for every single person in England, and in Scotland from 2017-18, exactly when the liability charges no income at a rate s. 55B(2)(b) forbids and, without the dividend allowance, no dividends at the dividend upper or additional rate. The reforms change the start of the Scottish higher rate, the basic rate limit (with the dividend upper rate moved to it, where Parliament starts it (s. 13(2))), the starting rate limit for savings up to the basic rate limit, the Personal Savings Allowance or the dividend allowance. So savings at a nil rate never stop the allowance.
5. From 2019-20, the band never rises against the formula before this PR, except from `STARTER` to `BASIC` where savings or dividends sit below the Scottish starter limit: they sit in the rest-of-UK basic band.
6. With the CPS expanded reform on, its conditions equal the statutory conditions or its expansion conditions.

`test_marriage_allowance_tax_reduction_properties.py` asserts these on generated married couples in England, Scotland, Wales and Northern Ireland, with pay, private pensions, savings and dividends drawn freely, in 2016-17, 2017-18, 2018-19, 2021-22, 2025-26 and 2026-27:

7. For every person, `income_tax` equals the income tax with `would_claim_marriage_allowance` false, less the smaller of the appropriate percentage of `marriage_allowance` and the Step 5 tax that the earlier reductions leave.
8. The reduction does not depend on the recipient's marginal rate. Under the CPS expanded reform, which gives the allowance to recipients in every band, a recipient with enough tax gets the appropriate percentage of the allowance, 20% in each year drawn, and their income tax falls by that amount. A fixed case checks £252 for 2025-26 recipients with £60,000 and £150,000 of pay in England and £60,000 in Scotland.
9. The election does not move the rate test: `meets_marriage_allowance_income_conditions` gives the same result with `would_claim_marriage_allowance` true and false.
10. The reduction lies between zero and the appropriate percentage of the allowance, the Step 6 reductions together never exceed the Step 5 tax, and the allowance never changes the Step 5 tax.

We ran a grid of 896 married couples in each year from 2015-16 to 2028-29 (25,088 person-years) at `e5b16d14b` and on this branch. The earner has £0 to £130,000 of pay (14 levels) and no other income, £3,000 of interest, £5,000 of dividends or £10,000 of private pension; the spouse earns £0, £5,000, £11,000 or £20,000; the couple lives in England, Scotland, Wales or Northern Ireland. Across the grid, two invariants hold:

11. `meets_marriage_allowance_income_conditions` gives the same result in all 25,088 person-years, and `marriage_allowance` stays the same in every one.
12. Everyone without the allowance pays the same `income_tax`: every person-year whose `income_tax` moves has the allowance.

For everyone outside Scotland, `tax_band` stays the same. For single people anywhere, `income_tax` and `savings_allowance` stay the same.

On the same grid, against `e5b16d14b`, the reduction moves `income_tax` in these person-years, all of them Marriage Allowance recipients (6,272 person-years in each nation):

| Nation | Recipients | Tax rises | Tax falls |
|---|---|---|---|
| England | 1,708 | 34 | 33 |
| Wales | 1,708 | 34 | 33 |
| Northern Ireland | 1,708 | 34 | 33 |
| Scotland | 1,522 | 316 | 141 |

`household_net_income` moves in the same couples, the other way: 33 households rise and 34 fall in each of England, Wales and Northern Ireland, and 141 rise and 316 fall in Scotland (3,136 household-years in each nation). Outside Scotland, tax rises only for earners with £14,000 or £18,000 of pay and £3,000 of interest, whose deduction used to open the 0% starting rate band for savings (up to £199.20). It falls only for earners with £12,570 of pay and £5,000 of dividends, whose tax the deduction could not reach (from 2018-19, by £26 to £252). In Scotland tax rises by up to £12.60 for earners whose top £1,260 of non-savings income bore the 21% intermediate rate (with pay only, dividends or a pension). With savings it rises by up to £199.20 (2027-28: £18,000 of pay and £3,000 of interest, £1,073.77 to £1,272.97). It falls by up to £12.60 where that slice bore the 19% starter rate, and by up to £252 for earners whose tax comes mostly from dividends. The largest falls, £252, come in 2022-23 and later for earners with £12,570 of pay and £5,000 of dividends (2022-23: £262.50 to £10.50). Universal Credit's `uc_income_tax_on_earnings` rises in 234 person-years and falls in 144. These synthetic households give no population estimate, and the years after 2026-27 use the model's projections.

Invariant 4 compares the test with the model's liability, so its reforms hold the starting rate limit at or below the basic rate limit, the range in which the model's liability places the savings nil rate where Parliament does (s. 12A). It also leaves out Scottish taxpayers before 2017-18, and its years start in 2016-17. YAML cases worked from the statute cover those: the 2015-16 dividend and savings cases at the model's £32,000 limit and at the statutory £31,785, and the two cases under a raised starting rate limit.

## Test plan

- [x] YAML tests whose expected values come from an external source: new cases in `scottish_rates.yaml` and `meets_marriage_allowance_income_conditions.yaml`, which we worked by hand from ITA 2007, FA 2016, SI 2015/1810, SI 2018/459 and the Scottish rate resolutions. Both files pass: 36 and 31 cases.
- [x] `marriage_allowance_tax_reduction.yaml`: 16 cases worked by hand from ss. 55B(1) and (3) and 29(2) and (3), S6M-16531 and the parameter files, with the arithmetic in each comment. All pass.
- [x] Scoped Ruff format and lint checks, the repository F811/F821 check, and `git diff --check`.
- [x] Changelog fragment `changelog.d/2350.fixed.md`.

We ran these locally with no survey data:

- `scottish_rates.yaml`: 36 passed.
- `meets_marriage_allowance_income_conditions.yaml`: 31 passed.
- We ran `liable_only_at_marriage_allowance_rates` on 200,000 generated sets of non-savings, savings and dividend income, basic rate limits, starting rate limits, savings allowances, Gift Aid, years and nations. It agrees in every case with a hand-worked oracle of ss. 10, 12, 12A and 13 and FA 2016 s. 4(17).
- HMRC income tax YAML directory (`policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/`): 570 passed.
- At this branch's head, which merges `main` at 9dd44e142: `pension_credit_earnings_disregard.yaml`, 34 passed; the whole `policyengine_uk/tests/policy/baseline` YAML tree, 5,589 passed and none failed; `scottish_rates.yaml`, `meets_marriage_allowance_income_conditions.yaml`, `marriage_allowance_tax_reduction.yaml`, `marriage_allowance_statutory_rate.yaml` and `marriage_allowance.yaml` together, 96 passed. With `marriage_allowance` put back on the exclusions list and the reduction taken off the Step 6 list, the two Scottish Pension Credit cases fail on `income_tax` (£3,016.62 and £2,805.73) and the file's other 32 pass. With `-n 4`, the eleven property and snapshot files above together with `test_marriage_allowance_cps_switch.py`: 245 passed and 1 xfailed (the same strict xfail). `code_health`: 3,150 passed. Ruff 0.17.2 format and lint, the F811/F821 check and `git diff --check`: clean.
- Every other YAML file that names `marriage_allowance`: `marriage_allowance.yaml` 7, `marriage_allowance_statutory_rate.yaml` 6, `marriage_allowance_tax_reduction.yaml` 16, `property_income_band_base.yaml` 7, `property_finance_cost_relief.yaml` 21, `gift_aid.yaml` 23, `tax_band_historical.yaml` 16, `uc_earnings_deductions.yaml` 15, `uc_mif_earned_income.yaml` 29, `uc_is_responsible_carer.yaml` 8 and `pension_credit_statutory_pay_earnings.yaml` 12, all passed.
- `marriage_tax_reforms.yaml`: 10 passed.
- `integration/income.yaml`: 8 passed.
- `test_tax_band_scottish_properties.py`: 5 passed.
- `test_marriage_allowance_cps_switch.py`: 45 passed.
- With `-n 4`: `test_marriage_allowance_tax_reduction_properties.py`, `test_tax_band_scottish_properties.py`, `test_gift_aid.py`, `test_income_tax_step_6_step_7_properties.py`, `test_property_income_band_base_properties.py`, `test_pension_credit_earnings_disregard_properties.py`, `test_uc_state_pension_properties.py`, `test_uc_income_from_capital_properties.py`, `test_uc_unearned_benefits_properties.py`, `test_deterministic_variables.py` and `test_dated_reform_routes.py` together: 200 passed and 1 xfailed. The strict xfail `test_state_pension_does_not_change_partners_marriage_allowance` still fails: the recipient's allowance still reads the transferor's unused personal allowance (#1947, #1963).
- `code_health`: 3,095 passed.
- Ruff 0.17.2 format and lint, the F811/F821 check and `git diff --check`: clean.

We ran each mutation of the reduction on a copy of the branch, against `marriage_allowance_tax_reduction.yaml` (16 cases), `marriage_allowance_statutory_rate.yaml` (6), `property_income_band_base.yaml` (7), `uc_earnings_deductions.yaml` (15), `meets_marriage_allowance_income_conditions.yaml` (31), `marriage_tax_reforms.yaml` (10) and the three property tests:

| Mutation | Reduction YAML | Other YAML | Property tests |
|---|---|---|---|
| Revert: `marriage_allowance` back on the exclusions list, the reduction off the Step 6 list | 8 fail | Case 7 of `property_income_band_base.yaml` fails | 3 fail |
| Keep `marriage_allowance` on the exclusions list as well as the reduction | 8 fail | 2 statutory-rate cases, Case 7 and the UC Marriage Allowance case fail | 3 fail |
| Take the reduction at the recipient's top non-savings rate | the 4 Scottish cases fail | all pass | 3 fail |
| Drop the Step 5 limit | the 2 limit cases fail | all pass | the test of invariants 7, 9 and 10 fails (at 7); the other 2 pass |

No mutation changes the rate test's 31 cases or the CPS reform's 10.

We ran one-line mutations of the Marriage Allowance test and of `tax_band` against both YAML files:

| Mutation | Marriage Allowance YAML (31 cases) | `scottish_rates.yaml` (36 cases) | Cases that fail |
|---|---|---|---|
| Dividend upper rate read from the model's dividend scale | 2 fail | all pass | the two 2015-16 dividend cases |
| Savings nil rate counted in 2015-16 | 2 fail | all pass | the two 2015-16 savings cases |
| Savings nil-rate slice starts at non-savings income, not at the starting rate limit | 1 fails | all pass | the £37,500 starting rate limit case |
| Scottish limit before 2017-18 read off the 2017-18 schedule | 2 fail | all pass | the 2015-16 and 2016-17 Scottish cases |
| Savings test on all taxable income instead of non-savings income and savings | all pass | all pass | none (see below) |
| `tax_band` without the Gift Aid rise in the UK limits | all pass | 1 fails | Scottish 2025 dividends at the Gift Aid limit |
| `tax_band` puts income at the UK additional limit above it | all pass | 1 fails | Scottish 2025 savings at the higher rate limit |
| `tax_band` reads `earned_taxable_income` | all pass | 2 fail | both property-income cases at the higher rate limit |

Under the £5,000 starting rate limit, a slice that starts at non-savings income and one that starts at the larger of it and the limit give the same answer: where they differ, both end below the basic rate limit. So only a raised starting rate limit separates the slice mutation, and the YAML case under a £37,500 limit does. The savings-test mutation changes the savings result only where dividends sit above the savings and take income past the basic rate limit. There the dividend test already fails the person. So no input whose net income equals the sum of its non-savings, savings and dividend income separates the mutation at the helper's output, and the 200,000-case differential above finds no difference with it either. A supplied `adjusted_net_income` below the income components breaks that equality and separates them.

🤖 Generated with [Claude Code](https://claude.com/claude-code)





Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Ready for hub review

Head: 2ca7c5ff77ed88c8a00580d0a659f54637049133 on branch claude/scottish-pension-credit-tax-fd16g4 (no PR; #2828's branch untouched). It branches from 89f2f9f34 and merges main at 9dd44e142 as its own commit (b860e673, no conflicts), then one commit, 2ca7c5ff, edits only policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_earnings_disregard.yaml.

Before starting: #2828's branch last moved at 2026-11-03 21:41 UTC (about 15 hours earlier) and no comment said anyone was mid-change, so I posted the pickup comment.

A1

pension_credit_earnings_disregard.yaml, lines 339-371 (first case) and 390-397 (second). Hand workings for 2025 from rates/scotland/rates.yaml at 2025-04-06 (starter 19% from 0, basic 20% from 2,827, intermediate 21% from 14,921, higher from 31,092), personal allowance 12,570, Marriage Allowance 1,260 at the 20% Scottish basic rate (s. 55B(1) and (3)):

Output Old Hand Model
income_tax, with pay 3,016.62 537.13 + 2,418.80 + 1,549 x 21% = 3,281.22, less 252 = 3,029.22 3,029.22
income_tax, without pay 2,805.73 537.13 + 2,418.80 + 509 x 21% = 3,062.82, less 252 = 2,810.82 2,810.82
pension_credit_earnings_disregard, with pay 829.11 min(1,040, 1,040 - 218.40 - 0 NI) = 821.60 821.60
pension_credit_income, both 25,194.27 29,040 - 3,029.22 - 821.60 = 28,000 - 2,810.82 = 25,189.18 25,189.18

The hub's arithmetic holds. The earnings do not cross into the intermediate band: taxable income without them (15,430) already exceeds 14,921, so all 1,040 bear 21%. The old comment's crossing came from the old deduction, which cut taxable income to 14,170 without pay; the new comment says so. No hand value differs from the model.

Task 2

The whole policyengine_uk/tests/policy/baseline tree after the merge: 5,589 passed, none failed. No other case moves.

Tests at the head (clean runs)

  • pension_credit_earnings_disregard.yaml: 34 passed.
  • Whole policyengine_uk/tests/policy/baseline tree, one policyengine-core test run: 5,589 passed.
  • scottish_rates.yaml, meets_marriage_allowance_income_conditions.yaml, marriage_allowance_tax_reduction.yaml, marriage_allowance_statutory_rate.yaml, marriage_allowance.yaml: 96 passed (36 + 31 + 16 + 6 + 7).
  • -n 4: the eleven property/snapshot files the body names plus test_marriage_allowance_cps_switch.py: 245 passed, 1 xfailed (test_state_pension_does_not_change_partners_marriage_allowance, strict xfail, as before; 200 + 45 as in the body).
  • code_health -n 4: 3,150 passed.
  • .github/check_fix_pr.py with the live title, the new body, no labels, and the changes from merge-base(origin/main, HEAD)..HEAD: PASS, 12 changed executable tests.
  • uvx ruff@0.17.2 format --check . (2,218 files formatted), check . and check --select F811,F821 policyengine_uk: clean. git diff --check 89f2f9f34..HEAD: clean.
  • git merge-tree --write-tree --name-only HEAD origin/main (origin/main still at 9dd44e142): exit 0, 48026ed4f.

Revert check

On a scratch worktree of the head, with marriage_allowance put back on earned_taxable_income_exclusions and marriage_allowance_tax_reduction removed from step_6_tax_reductions, run against that worktree's package: the two Scottish cases fail on income_tax (3,016.62 and 2,805.73, the old values), 32 pass.

Judgment calls

Skipped

Nothing needing survey data ran. I didn't run the HMRC directory separately (the whole tree covers it) or the full pytest suite.

PR_BODY.md

Fixes #2350

Reproducer: `policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/marriage_allowance_tax_reduction.yaml::A Scottish intermediate-rate recipient with dividends gets 20% of the transferable amount`; `policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/meets_marriage_allowance_income_conditions.yaml::Under a raised Scottish higher rate, nil-rate savings meet the conditions`; `policyengine_uk/tests/test_tax_band_scottish_properties.py::test_marriage_allowance_follows_the_liability_with_nil_rates`

axiom: TheAxiomFoundation/rulespec-uk#523 queued, with TheAxiomFoundation/rulespec-uk#536 queued for the s. 55B(1) and (3) reduction at Step 6

## What and why

`tax_band` compared a Scottish taxpayer's total taxable income, savings and dividends included, with the Scottish limits. Parliament applies Scottish rates to income other than savings and dividends under ITA 2007 ss. 11A and 13. The Scottish Parliament's 2025-26 resolution (S6M-16531) calls this "non-savings and non-dividend income". Parliament puts savings and dividends at the top of income (s. 16) and charges them at the rates they would bear outside Scotland (ss. 11D(6) and 13(5)). The model already calculated non-savings, savings and dividend liabilities separately.

For a Scottish taxpayer, `tax_band` now takes the higher of two bands:

1. the Scottish band of `non_savings_income_after_allowances`, their income other than savings and dividends after allowances, which go to it first, as in `earned_income_tax`;
2. where the person has taxable savings or dividends, the rest-of-UK band of all taxable income (`net_income - allowances`), since Parliament puts savings and dividends at its top (s. 16).

The model keeps income up to a limit in the lower band. Parliament charges income "up to" a limit at the lower rate (s. 10(2) to (3A)), and the Scottish Parliament charges each Scottish rate "on income above" one limit "and up to" the next. As before, the model raises the Scottish limits from the basic rate's upper limit, and the basic and higher rate limits, by the grossed-up Gift Aid gift, as Parliament requires (s. 414(2)(b)). The model retains nil-rate savings and dividends in their underlying bands. Parliament sets separate rate conditions for the Marriage Allowance (s. 55B).

### Marriage Allowance rate conditions

`meets_marriage_allowance_income_conditions` no longer reads `tax_band`. It calls `liable_only_at_marriage_allowance_rates`, which applies s. 55B(2)(b) and (ba) to the person's income. A person fails it when any of these holds:

- their income other than savings and dividends, after allowances, exceeds the basic rate limit, or for a Scottish taxpayer the start of the Scottish higher rate;
- some savings above the basic rate limit lie outside the savings nil-rate slice. Savings up to the limit bear a basic rate or the starting rate for savings, both permitted, since Parliament charges the starting rate only on savings that would otherwise bear a basic rate (s. 12(1)). It charges the savings nil rate on the lowest savings above the starting rate limit for savings, up to the savings allowance (s. 12A(1) to (4)). Dividends sit above savings (s. 16) and don't move that slice;
- their dividends, counted as if the dividend nil rate did not exist (s. 55B(2)(ba) omits s. 13A), take their income past the basic rate limit, where the dividend upper rate starts (ss. 10(3) and 13(2)).

Under s. 414(2)(b), the model raises each limit by the grossed-up gift. Parliament and the Treasury set the permitted rates year by year:

- 2015-16: the basic rate, the dividend ordinary rate and the starting rate for savings. The Scottish rates of s. 11A start in 2016-17, the year the Treasury appointed (FA 2014 Sch. 38 para. 12, SI 2015/2000 art. 3), so the test holds a Scottish taxpayer to the basic rate limit. Parliament gave the savings nil rate effect from 2016-17 (FA 2016 s. 4(17)), so the test counts no savings nil rate in 2015-16;
- 2016-17: the Scottish basic rate (the Treasury's SI 2015/1810 art. 14(3)), and the savings and dividend nil rates with s. 55B(2)(ba) (FA 2016 ss. 4(8) and 5(6)). Parliament then charged the Scottish basic rate on the non-savings income that would otherwise bear the basic rate (s. 11A(1) as it stood), so the test again uses the basic rate limit;
- 2017-18: the Scottish basic rate only, among the Scottish rates, so the test uses the start of the Scottish higher rate, £31,500 of taxable income;
- from 2018-19: the Scottish starter and intermediate rates too (the Treasury's SI 2018/459 art. 6(2)), so the test uses the start of the Scottish higher rate.

The model's Scottish rate schedule starts in April 2017, and the model reads its first values in earlier years too, so the test sets a Scottish taxpayer's limit by the year, not from that schedule. The test also departs from three historical or reformed parameters that the liability reads. It starts the dividend upper rate at the basic rate limit, where the model's 2015-16 dividend scale starts it at £37,500. It counts no savings nil rate in 2015-16, where the model's Personal Savings Allowance starts in 2005. And it places the savings nil rate above the starting rate limit, where the liability starts it after the income charged at the starting rate. The two agree unless a reform raises that limit above the basic rate limit or changes the starting rate's phase-out, which the test no longer reads.

Parliament charges tax at each rate at Step 4 and takes tax reductions off at Step 6 (s. 23), and it gives the Marriage Allowance as a tax reduction at Step 6 (ss. 55A(2) and 55B(1)). So the allowance never changes the income each rate applies to, and the test never reads it. The test takes `non_savings_income_after_allowances`, `taxable_savings_interest_income`, `received_allowances_savings_income`, `savings_allowance` (from 2016-17), the starting rate limit for savings, `taxable_dividend_income`, `received_allowances_dividend_income` and `gift_aid_grossed_up`.

The direct test admits people at a permitted rate limit and people whose savings bear permitted nil rates:

- taxable income exactly at the basic rate limit (or the Scottish higher rate's start, or a limit Gift Aid raised). Parliament charges it at the basic rate (s. 10(2)). `tax_band` outside Scotland still calls it `HIGHER`;
- from 2016-17, people whose income passes the basic rate limit only by savings the savings nil rate covers. Parliament charges those savings at the savings nil rate (s. 12A(3)) and allows that rate for the Marriage Allowance (s. 55B(2)(b)). Under current limits no Scottish taxpayer reaches this case from 2017-18. The nil-rate slice starts at their non-savings income, so it reaches past the basic rate limit only when that income comes within a savings allowance of the limit, above the start of the Scottish higher rate.

Dividends the dividend allowance covers still fail when, without it, they would bear the dividend upper rate. `tax_band` stays the same for everyone outside Scotland, but the Marriage Allowance conditions move there too. We ran a grid of 4,816 single adults (3,596 of them outside Scotland) on `origin/main` and on this branch for each year from 2015-16 to 2028-29. Outside Scotland 91 person-years move, all to meeting the conditions:

- 90 have taxable income exactly at the basic rate limit, or at a limit Gift Aid raised, from 2019-20 on;
- 1 has savings above the limit that the savings nil rate covers, in 2016-17.

In Scotland 841 person-years move: 833 to meeting the conditions, and 8 in 2017-18 to failing them. Every adult's `income_tax` and `savings_allowance`, and every band outside Scotland, match `origin/main`; Scottish bands change in 3,339 person-years. These synthetic households give no population estimate, and the years after 2026-27 use the model's projections.

The `create_expanded_ma_reform` CPS reform calls the same helper. It keeps its rule: people meet its conditions when they meet the statutory ones or the reform's expansion conditions. We ran 400 generated married couples, 187 of them with a child, in 2017-18, 2018-19, 2021-22, 2025-26 and 2026-27. The rule holds for every person-year, under this branch's direct test and under conditions read off this branch's `tax_band`. The statutory conditions move for 21 person-years, the reform's for 20, and the reform's conditions and allowance move for no one whose statutory conditions stay the same.

This PR deletes `gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bands`, which nothing else read. A reform or saved policy that names it now fails with directions to the rate limits (`REMOVED_PARAMETERS`).

### Marriage Allowance tax reduction

The model used to take the Marriage Allowance off `earned_taxable_income` (`gov.hmrc.income_tax.earned_taxable_income_exclusions`). That saved the recipient tax at the rate on their top £1,260 of income other than savings and dividends, and it lowered the base under their savings and dividends. Parliament gives the recipient "a tax reduction for a tax year of the appropriate percentage of the transferable amount" (ITA 2007 s. 55B(1)) at Step 6 (s. 55A(2)). The appropriate percentage is "the basic rate or default basic rate or, in the case of a Scottish taxpayer or Welsh taxpayer, the Scottish basic rate or Welsh basic rate" (s. 55B(3)). The Scottish Parliament set the Scottish basic rate at 20% for 2025-26 ([S6M-16531](https://www.parliament.scot/chamber-and-committees/votes-and-motions/S6M-16531)). A reduction comes off "only so far as there is sufficient tax calculated at Step 5", counting "tax reductions already deducted at Step 6" (s. 29(2) and (3)).

This PR gives every recipient that reduction:

- `gov.hmrc.income_tax.earned_taxable_income_exclusions` no longer lists `marriage_allowance`, so the allowance no longer changes `earned_taxable_income`, `non_savings_taxable_income`, the savings rate bands or the dividend base.
- `marriage_allowance_appropriate_percentage` (new) gives the basic rate, or for a Scottish taxpayer from 2016-17 the Scottish basic rate. It reads the Scottish scale's basic rate band itself (`brackets[1]`), the way `pension_credit_self_employment_deductions` reads it. The model has no Welsh rates, so a Welsh taxpayer takes the basic rate.
- `marriage_allowance_tax_reduction` (new) gives the appropriate percentage times `marriage_allowance` and limits it to the Step 5 tax that the reductions listed before it leave (`earlier_tax_reductions`). `gov.hmrc.income_tax.step_6_tax_reductions` lists it last. Section 27(5) does not list Chapter 3A, so s. 27(2) sets its place: "the order which will result in the greatest reduction". Each listed reduction has an amount fixed before Step 6, so every order deducts the same total; listing this one last leaves the other reductions' amounts as they were.
- `marriage_allowance` keeps the amount the model books today: the transferor's unused personal allowance, up to 10% of the personal allowance, rounded up to £10.

This fixes items 2 and 3 of #1947 for the recipient: a recipient taxed mostly on dividends or savings now gets the reduction in full, and a Scottish recipient gets 20%, not their marginal rate. We ran each case on this branch and at `e5b16d14b` (the branch before this change), for a married earner whose spouse earns £5,000:

| 2025-26 unless stated | `e5b16d14b` | This branch | Law |
|---|---|---|---|
| Scotland: £40,000 pay, £5,000 dividends | £5,711.97 | £5,724.57 | £5,976.57 - 20% x £1,260 = £5,724.57 |
| Scotland: £40,000 pay, £5,000 savings | £6,118.22 | £6,130.82 | £6,382.82 - £252 = £6,130.82 |
| Scotland: £40,000 pay | £5,318.22 | £5,330.82 | £5,582.82 - £252 = £5,330.82 |
| Scotland: £14,000 pay | £32.30 | £19.70 | £1,430 x 19% - £252 = £19.70 |
| England: £17,570 pay, £3,000 savings | £896.00 | £1,148.00 | £1,000 + £400 - £252 = £1,148 |
| England, 2026-27: £12,570 pay, £5,000 dividends | £483.75 | £231.75 | £4,500 x 10.75% - £252 = £231.75 |
| England: £30,000 pay | £3,234.00 | £3,234.00 | £3,486 - £252 = £3,234 |
| England: £13,500 pay | £0.00 | £0.00 | £186 - min(£252, £186) = £0 |

In the first row household net income falls from £41,919.12 to £41,906.53. In the fifth, the old deduction cut the earner's taxable pay below the £5,000 starting rate limit for savings, so £1,260 of interest bore the 0% starting rate as well. The old model saved them £504 rather than £252. `uc_income_tax_on_earnings` takes the Step 6 reductions off the tax on earnings, so Universal Credit's deduction for income tax follows the change. The Scottish £40,000 earner's deduction rises by £12.60, from £5,318.22 to £5,330.82, and the English £30,000 earner's stays at £3,234.

### Readers of the old deduction

- `uc_income_tax_on_earnings` and `uc_income_tax_on_trade` read both lists, so they follow the change with no code change (above).
- `pension_credit_self_employment_deductions` takes `marriage_allowance` off the profit at a single notional rate, the basic rate or the Scottish basic rate. At one rate, with both floored at zero, rate x max(0, profit - reliefs - amount) equals max(0, rate x max(0, profit - reliefs) - rate x amount), and the married couple's allowance comes off after either. A million random draws of profit, reliefs, allowance, married couple's allowance and rate give the same notional tax both ways to within £0.000000000004. Its comment now says this; the code stays the same.
- `uc_earnings_deductions.yaml`'s case that sets its own exclusions list no longer lists `marriage_allowance`.
- The CPS reform (`create_expanded_ma_reform`) redefines `marriage_allowance`; `marriage_allowance_tax_reduction` reads the reform's allowance, and a property test checks that under the reform a higher- or additional-rate recipient's tax falls by 20% of the allowance (£252 in 2025-26), not 40% or 45%.
- `non_savings_taxable_income`, `higher_rate_savings_income`, `add_rate_savings_income`, `basic_rate_savings_income`, `savings_starter_rate_income` and `dividend_income_tax` read `marriage_allowance` through `earned_taxable_income` at `e5b16d14b`. They no longer do. `property_income_band_base.yaml`'s Case 7 pinned the old base for #1947; it now gives £17,430, not £16,170, and income tax of £3,234.
- The docstrings of `liable_only_at_marriage_allowance_rates` and `non_savings_taxable_income`, invariant 2's note in `test_property_income_band_base_properties.py`, `docs/engineering/gift-aid.md` and `marriage_allowance/max.yaml` now describe the reduction. The rate test computes the same thing as before.

### The rest-of-UK band needs savings or dividends

The issue proposes the higher of the Scottish band of non-savings income and the rest-of-UK band of total taxable income. That second band measures the savings and dividends only when the person has some. Without them it lifts a Scottish starter-rate taxpayer to `BASIC`: in 2018-19, £12,570 of pay leaves £720 of taxable income, all at the 19% starter rate, and the proposal gives `BASIC`. The existing case `Scottish intermediate rate recognised` (2022-23, £14,650 of income, `STARTER`) fails under the proposal. This PR applies the rest-of-UK band only when the person has taxable savings or dividends.

### Other years

The same band formula now runs from 2017-18. The model dispatches annual formulas at 1 January, so before this PR:

- In 2017-18 the model ran the formula for earlier years and banded Scottish taxpayers on the rest-of-UK limits. The model labelled £44,000 of pay, £1,000 of it at the 40% Scottish higher rate, `BASIC`, and the earner met the Marriage Allowance conditions, though in 2017-18 Parliament allowed only the Scottish basic rate (s. 55B(2)(b)).
- In 2018-19 it ran the 2017-18 formula, which read the first three of the five Scottish limits as the basic, higher and additional limits. So the model labelled every Scottish taxpayer with more than £12,150 of taxable income `ADDITIONAL`.

### Labels

`TaxBand` has no advanced or top label, so `ADDITIONAL` covers the Scottish advanced and top rates and the savings and dividend additional rates. `HIGHER` covers the Scottish higher rate and the savings higher and dividend upper rates. `STARTER` and `INTERMEDIATE` come from the Scottish band only.

### What reads `tax_band`, and what moves

- `meets_marriage_allowance_income_conditions` and the CPS reform no longer read it.
- `marriage_allowance` and `income_tax` move for married couples whose earner now meets, or no longer meets, the conditions. We ran an earner whose spouse earns £5,000 on `origin/main` and on this branch:

  | Year and earner's income | Earner's band | Marriage Allowance | Earner's income tax |
  |---|---|---|---|
  | 2025-26, Scotland: £40,000 pay, £5,000 dividends | `HIGHER` → `INTERMEDIATE` | £0 → £1,260 | £5,976.57 → £5,724.57 |
  | 2025-26, Scotland: £40,000 pay, £5,000 savings | `HIGHER` → `INTERMEDIATE` | £0 → £1,260 | £6,382.82 → £6,130.82 |
  | 2018-19, Scotland: £40,000 pay, £5,000 dividends | `ADDITIONAL` → `INTERMEDIATE` | £0 → £1,190 | £5,995.00 → £5,757.00 |
  | 2017-18, Scotland: £44,000 pay | `BASIC` → `HIGHER` | £1,150 → £0 | £6,270.00 → £6,700.00 |
  | 2025-26, England: £50,270 pay | `HIGHER` | £0 → £1,260 | £7,540.00 → £7,288.00 |
  | 2025-26, England: £50,070 pay, £500 savings | `HIGHER` | £0 → £1,260 | £7,500.00 → £7,248.00 |
  | 2025-26, England: £50,070 pay, £500 dividends | `HIGHER` | £0 | £7,500.00 |
  | 2025-26, England: £40,000 pay, £5,000 dividends | `BASIC` | £1,260 | £5,627.75 |

  The spouse pays no income tax in any row. Where the earner has the allowance, it now saves them the appropriate percentage of it: 20% x £1,260 = £252 in 2025-26 and 20% x £1,190 = £238 in 2018-19. `origin/main` deducted it from earned income, so in the 2017-18 row it saved £430, taking £1,000 out of the 40% band and £150 out of the 20% band; under this branch that earner fails the conditions. These synthetic households give no population estimate.
- Counts of taxpayers by marginal rate move, since Scottish taxpayers move to the band their income reaches (PolicyEngine/microcosm#1198 binds HMRC's Scottish higher and additional rate counts on `tax_band`). In the 4,816-adult grid, 3,129 of the 3,339 Scottish band changes move down; the grid gives no population shares. The other 210 move up: 8 Scottish taxpayers in 2017-18 above the Scottish higher-rate limit, and 202 starter-rate taxpayers with some savings or dividends, whom the model now bands `BASIC`. The model charges savings that low at the 0% starting rate for savings and such dividends at the nil or ordinary rate, and the band counts nil-rate income where it sits.
- `savings_allowance` does not read `tax_band`. Since the fix for #2347 it sets the Personal Savings Allowance on the rest-of-UK bands itself (s. 12B(8)), and its documentation now says so. This PR does not move it: `test_savings_allowance_does_not_read_the_band` forces every band as an input and the allowance stays the same, and the 4,816-adult differential above finds no change in it.

Microcosm's engine test `test_scottish_savings_and_dividends_count_against_the_scottish_thresholds` pins the issue's first case (Scotland, £40,000 of pay and £5,000 of dividends, `HIGHER`). With this change the model gives `INTERMEDIATE`, so that test fails until Microcosm updates it.

### Existing tests changed

- The eleventh row (index 10) of the `test_gift_aid.py` bit-for-bit snapshot, a Scottish taxpayer in 2026-27 with no pay, £10,000 of property income, £20,000 of savings and £10,000 of dividends, moves from `INTERMEDIATE` to `BASIC`. The model sets the allowance against all the property income, so no income bears a Scottish rate (s. 11A), and the remaining £27,430 of savings and dividends falls below the £37,700 UK basic rate limit (ss. 11D(6) and 13(5)). Its other eleven rows and every other snapshot value stay the same.
- On `origin/main`, the six cases in `meets_marriage_allowance_income_conditions.yaml` set `tax_band` as an input. They now set the income that puts a person in each band; every expected value stays the same.
- `test_marriage_allowance_cps_switch.py`'s invariant 5 pinned the CPS reform's values from before the reduction: with the reform on, the £60,000 earner saved 40% of the allowance. Its expected tax now comes from s. 55B(1) and (3): £11,432 - 20% x £1,260 = £11,180 at the reform's 10% rate, and £11,432 - 20% x £2,520 = £10,928 at 20%, in place of £10,928 and £10,424.
- `property_income_band_base.yaml`'s Case 7 pinned the old Marriage Allowance base for #1947; it now gives £17,430 and income tax of £3,234 (above).
- `pension_credit_earnings_disregard.yaml`'s two Scottish couple cases (2025-26: the claimant has £12,000 of State Pension and £16,000 of private pension, with and without £1,040 of pay; the partner has no taxable income) pinned the old deduction. The claimant's taxable income of £16,470 (with pay) and £15,430 (without) already exceeds £14,921, the start of the Scottish intermediate rate, so the pay does not cross into that band. Before the Marriage Allowance, tax comes to £2,827 x 19% + £12,094 x 20% + £1,549 x 21% = £3,281.22 with pay and £3,062.82 without; the s. 55B reduction takes off 20% x £1,260 = £252 from each. So:

  | Output | Old | New |
  |---|---|---|
  | `income_tax`, with pay | £3,016.62 | £3,029.22 |
  | `income_tax`, without pay | £2,805.73 | £2,810.82 |
  | `pension_credit_earnings_disregard`, with pay | £829.11 | £821.60 |
  | `pension_credit_income`, both cases | £25,194.27 | £25,189.18 |

  The pay adds £3,029.22 - £2,810.82 = £218.40 of tax (all £1,040 at 21%), no Class 1 contributions above State Pension age, so net earnings come to £821.60 and the £20-a-week disregard of £1,040 stops there. Pension Credit income stays the same with and without pay: £29,040 - £3,029.22 - £821.60 = £28,000 - £2,810.82 = £25,189.18. The old deduction took £1,260 off the claimant's taxable income, to £14,170 without pay, below the intermediate rate's start. So £751 of the pay bore 20% and £289 bore 21%, and the pay added £210.89 of tax.
- `test_marriage_allowance_cps_switch.py`'s invariant 3 read `eligible_bands`. It now checks that no one with taxable income above the basic rate limit, or above £31,092 (the start of the Scottish higher rate) for a Scottish taxpayer, meets the conditions or has the allowance, and that everyone else meets them.

### Known limits, unchanged here

- Outside Scotland, from 2018-19 `tax_band` puts taxable income exactly at a limit in the band above, and pay equal to the personal allowance in `BASIC`, where Parliament charges income up to a limit at the lower rate (s. 10). #1963 pins the first at £50,270 of pay. The Marriage Allowance no longer reads the band, so this affects counts by marginal rate only. #2782 tracks it.
- The model tests only the receiving spouse. Parliament also bars an election by a spouse who, with their allowance cut by the transferable amount, would be liable above the permitted rates (s. 55C(1)(c)); #1947 tracks this and #1963 models it.
- `marriage_allowance` still books the transferor's unused personal allowance on the recipient, up to 10% of the personal allowance and rounded up to £10. Parliament instead fixes the transferable amount (s. 55B(4) and (5)) and cuts the transferor's own allowance by it (s. 55B(6)). The rest of #1947 (the fixed transfer, the transferor's reduced allowance, the election and its conditions, the rounding of a partial amount and the double count) stays with #1963. `test_state_pension_does_not_change_partners_marriage_allowance` still fails, as its strict xfail expects.
- For 2018-19 the model's Scottish higher-rate limit and rate (£31,500 of taxable income and 40%, which the model keeps until 2021-22) differ from the Scottish Parliament's 2018-19 resolution (£31,580 and 41%, S5M-10397). #2783 tracks the historical Scottish rates and limits; this branch's cases sit clear of the changed limit.
- The code tells the Scottish schedules apart by their number of limits (three in 2017-18), as `first_extended_scottish_threshold` already does, so a reform that changes the number of Scottish brackets gets wrong labels.
- The model's Scottish rate schedule starts in April 2017, and the model reads its first values in 2015-16 and 2016-17 too. So `earned_income_tax` charges a Scottish taxpayer 40% above £31,500 of taxable pay in those years, where Parliament taxed that pay on the rest-of-UK limits. In 2015-16, £42,200 of pay leaves £31,600 of taxable pay, below the statutory £31,785 limit, and the model charges a Scottish taxpayer £6,340 against £6,320 in England. In 2016-17, £43,000 of pay leaves £32,000, the basic rate limit Parliament set for 2016-17 (FA 2015 s. 4(1)(a), as Finance (No. 2) Act 2015 s. 6(a) amended it), and the model charges £6,500 against £6,400. The Marriage Allowance test uses the basic rate limit in those years. A Scottish taxpayer can therefore meet this income test while the model charges some of their income at 40% in 2015-16 or 2016-17. The property test leaves those Scottish taxpayers out (#2866).
- Parliament set the basic rate limit at £31,785 for 2015-16 (s. 10(5)); the model uses £32,000. In 2015-16 the model's dividend scale also starts the dividend upper rate at £37,500, and its Personal Savings Allowance applies from 2005. The model's liability keeps these values, and the Marriage Allowance test follows the statute instead (#2865).
- When a reform raises the starting rate limit for savings above the basic rate limit, the model's savings liability starts the savings nil rate where the starting rate ends, and Parliament starts it at the limit (s. 12A). Under a £40,000 limit, with £12,570 of pay and £38,000 of interest, the test fails the conditions. The model charges no savings tax there, where Parliament charges £120 on the £300 above the basic rate limit (ss. 11D and 12A) (#2867).

### Overlap

#1963 (draft, `marriage-allowance-election` at 69c919f60) models the Marriage Allowance as the statutory transfer and Step 6 reduction. Both branches define `liable_only_at_marriage_allowance_rates` in the same file, and this branch now adds `marriage_allowance_appropriate_percentage` and `marriage_allowance_tax_reduction` under #1963's names. This branch deducts the reduction after the reductions listed before it in `step_6_tax_reductions`, through `earlier_tax_reductions`, and has no `marriage_allowance_tax_reduction_limit`. Against this branch's head, which merges `main` at 9dd44e142, git conflicts with #1963 in 19 files: `marriage_allowance/max.yaml`, `income_tax_subtractions.yaml`, the CPS reform, `pension_credit_earnings_disregard.yaml`, `meets_marriage_allowance_income_conditions.yaml`, `property_income_band_base.yaml`, `test_marriage_allowance_cps_switch.py`, `test_property_income_properties.py`, `test_state_pension_components.py`, `basic_state_pension.py`, `new_state_pension.py`, `pension_credit_self_employment_deductions.py`, `marriage_allowance.py`, `marriage_allowance_appropriate_percentage.py`, `marriage_allowance_tax_reduction.py`, `meets_marriage_allowance_income_conditions.py`, `uses_property_allowance.py`, `non_savings_taxable_income.py` and `property_finance_cost_relief.py`. Seven of those (`income_tax_subtractions.yaml`, `test_property_income_properties.py`, `test_state_pension_components.py`, `basic_state_pension.py`, `new_state_pension.py`, `uses_property_allowance.py` and `property_finance_cost_relief.py`) conflict with `main` at 9dd44e142 itself.

#2830 (`fix-2106-allowance-order` at 6602ccce4) conflicts with this branch in `non_savings_income_after_allowances.py`, as before, and now in `test_property_income_band_base_properties.py`, whose invariant 2 note both branches rewrite. #2841 (`fix-2782-tax-band-boundaries` at a15905ca8) conflicts in `tax_band.py`, which this change does not touch. Git merges #2830 and #2841 cleanly with `main` at 9dd44e142, and #1963 conflicts with it as above.

#2670 also edits `create_expanded_ma_reform` (its child condition). No other open PR touches these files.

We ran 1,000 generated households in all four nations (607 married couples and 393 single adults) for each year from 2015-16 to 2028-29. This branch's rate test and #1963's at 69c919f6 agree in 22,497 of 22,498 person-years, couples included. In the one difference, in 2016-17, a single Scottish taxpayer with £20,519 of pay, £22,267 of property income and £1 of interest has £31,786 of taxable income other than savings and dividends. This branch holds them to the £32,000 basic rate limit and finds the conditions met, where #1963 uses the £31,500 that the model's Scottish schedule shows in that year.

#### Merge notes

- This branch merges `main` at 9dd44e142. Its head merges with that `main` without conflicts.
- In `pension_credit_earnings_disregard.yaml`, #1963 gives the two Scottish couple cases the same `income_tax`, `pension_credit_earnings_disregard` and `pension_credit_income` as this branch and adds Pension Credit outputs below them, so #1963 can take its own side of that conflict.

- When #1963 rebases onto this branch, it keeps this branch's helper, both callers, the removed-parameter migration and the regression cases. The helper carries the pre-2017-18 year rule for Scottish taxpayers, the strict comparisons at each limit, the Gift Aid extensions and the dividend test on the basic rate limit, and it places the savings nil rate from 2016-17 above the starting rate limit.
- #1963 also keeps this branch's reduction: `marriage_allowance_appropriate_percentage` (which reads the Scottish basic rate band, `brackets[1]`, and gives the basic rate before 2016-17), `marriage_allowance_tax_reduction` (limited through `earlier_tax_reductions`), its place last in `step_6_tax_reductions.yaml`, the removal of `marriage_allowance` from `earned_taxable_income_exclusions.yaml`, and `marriage_allowance_tax_reduction.yaml`. #1963's `income_tax_subtractions.yaml` entry goes, since `origin/main` lists Step 6 reductions in `step_6_tax_reductions.yaml`. Where #1963's election reads `marriage_allowance_tax_reduction_limit`, it can compute the same limit from `income_tax_pre_charges` less `earlier_tax_reductions`.
- #1963 still brings the transferor side and the election: the fixed transferable amount (s. 55B(4) and (5)), the transferor's reduced personal allowance (s. 55B(6)), the election and its conditions (s. 55C), and the fixes for #1947's rounding of a partial amount (item 4) and double count (item 5). Its expected values for the recipient's tax should come out the same, since both branches give 20% of the transferable amount at Step 6.
- The helper's docstring on this branch replaces the two paragraphs it shared with #1963. #1963 should take this wording:

  > Apply the rates Parliament permits for the tax year (s. 55B(2)(b) and s. 55C(1)(c)). From 2016-17 these include the savings nil rate; from 2018-19 the Scottish list includes rates below basic and the intermediate rate. Where s. 55B(2)(ba) and s. 55C(1)(ca) apply, test dividends as if s. 13A were omitted.
  >
  > Parliament extends the rate limits by the grossed-up Gift Aid gift (s. 414(2)(b)); the gift does not reduce taxable income. Before 2017-18 this test uses the basic rate limit for Scottish taxpayers, even though the model's historical Scottish liability currently reads the 2017-18 schedule. The test also follows the statute where the model's liability departs from it: it starts the dividend upper rate at the basic rate limit (ss. 10 and 13), counts no savings nil rate before 2016-17 (FA 2016 s. 4(17)), and places the nil-rate slice above the starting rate limit for savings (s. 12A).
- For #2830, take #2830's `non_savings_income_after_allowances.py` and replace its last documentation sentence, "property_income_tax, taxable_property_income_after_allowances and earned_taxable_income read it, and non_savings_taxable_income reads it through the last two.", with "property_income_tax, taxable_property_income_after_allowances, earned_taxable_income, the Marriage Allowance rate test and, for Scottish taxpayers, tax_band read it, and non_savings_taxable_income reads it through taxable_property_income_after_allowances and earned_taxable_income." In `test_property_income_band_base_properties.py`, take #2830's invariant 2 and replace "with no Marriage Allowance, " and "(earned_taxable_income also subtracts Marriage Allowance; #1947)" with a closing sentence: "The Marriage Allowance does not enter it: the model gives the allowance as a tax reduction at Step 6 (ITA 2007 s. 55B(1))." `earned_taxable_income_exclusions.yaml` no longer lists `marriage_allowance`, so #2830's `IGNORED_EXCLUSIONS` no longer changes anything and can go. We merged #2830's head into a copy of this branch's head, taking #2830's side of both conflicts. The merge computes `income_tax` with no cycle, and five of the households in the table above give the same income tax as on this branch (£5,724.57, £6,130.82, £19.70, £1,148 and £231.75). The HMRC allowance YAML directory (248 cases) and `property_income_band_base.yaml` (7 cases) pass on it.
- #2841 conflicts only in `tax_band.py`, which this change leaves as it was at `e5b16d14b`.
## Invariants

The property tests assert these on generated cases:

1. With the starting rate for savings, the Personal Savings Allowance and the dividend allowance set to zero, every single Scottish taxpayer pays tax at their band's rates on some income and at no higher band's rates; with no band they pay no tax.
2. With the baseline nil-rate amounts, no single Scottish taxpayer pays tax at the higher or additional rates above their band.
3. With the nil-rate amounts set to zero, the Marriage Allowance income conditions hold for a single Scottish taxpayer exactly when they pay nothing at the higher or additional rates.
4. With the baseline nil-rate amounts and with reformed limits and amounts, the conditions hold for every single person in England, and in Scotland from 2017-18, exactly when the liability charges no income at a rate s. 55B(2)(b) forbids and, without the dividend allowance, no dividends at the dividend upper or additional rate. The reforms change the start of the Scottish higher rate, the basic rate limit (with the dividend upper rate moved to it, where Parliament starts it (s. 13(2))), the starting rate limit for savings up to the basic rate limit, the Personal Savings Allowance or the dividend allowance. So savings at a nil rate never stop the allowance.
5. From 2019-20, the band never rises against the formula before this PR, except from `STARTER` to `BASIC` where savings or dividends sit below the Scottish starter limit: they sit in the rest-of-UK basic band.
6. With the CPS expanded reform on, its conditions equal the statutory conditions or its expansion conditions.

`test_marriage_allowance_tax_reduction_properties.py` asserts these on generated married couples in England, Scotland, Wales and Northern Ireland, with pay, private pensions, savings and dividends drawn freely, in 2016-17, 2017-18, 2018-19, 2021-22, 2025-26 and 2026-27:

7. For every person, `income_tax` equals the income tax with `would_claim_marriage_allowance` false, less the smaller of the appropriate percentage of `marriage_allowance` and the Step 5 tax that the earlier reductions leave.
8. The reduction does not depend on the recipient's marginal rate. Under the CPS expanded reform, which gives the allowance to recipients in every band, a recipient with enough tax gets the appropriate percentage of the allowance, 20% in each year drawn, and their income tax falls by that amount. A fixed case checks £252 for 2025-26 recipients with £60,000 and £150,000 of pay in England and £60,000 in Scotland.
9. The election does not move the rate test: `meets_marriage_allowance_income_conditions` gives the same result with `would_claim_marriage_allowance` true and false.
10. The reduction lies between zero and the appropriate percentage of the allowance, the Step 6 reductions together never exceed the Step 5 tax, and the allowance never changes the Step 5 tax.

We ran a grid of 896 married couples in each year from 2015-16 to 2028-29 (25,088 person-years) at `e5b16d14b` and on this branch. The earner has £0 to £130,000 of pay (14 levels) and no other income, £3,000 of interest, £5,000 of dividends or £10,000 of private pension; the spouse earns £0, £5,000, £11,000 or £20,000; the couple lives in England, Scotland, Wales or Northern Ireland. Across the grid, two invariants hold:

11. `meets_marriage_allowance_income_conditions` gives the same result in all 25,088 person-years, and `marriage_allowance` stays the same in every one.
12. Everyone without the allowance pays the same `income_tax`: every person-year whose `income_tax` moves has the allowance.

For everyone outside Scotland, `tax_band` stays the same. For single people anywhere, `income_tax` and `savings_allowance` stay the same.

On the same grid, against `e5b16d14b`, the reduction moves `income_tax` in these person-years, all of them Marriage Allowance recipients (6,272 person-years in each nation):

| Nation | Recipients | Tax rises | Tax falls |
|---|---|---|---|
| England | 1,708 | 34 | 33 |
| Wales | 1,708 | 34 | 33 |
| Northern Ireland | 1,708 | 34 | 33 |
| Scotland | 1,522 | 316 | 141 |

`household_net_income` moves in the same couples, the other way: 33 households rise and 34 fall in each of England, Wales and Northern Ireland, and 141 rise and 316 fall in Scotland (3,136 household-years in each nation). Outside Scotland, tax rises only for earners with £14,000 or £18,000 of pay and £3,000 of interest, whose deduction used to open the 0% starting rate band for savings (up to £199.20). It falls only for earners with £12,570 of pay and £5,000 of dividends, whose tax the deduction could not reach (from 2018-19, by £26 to £252). In Scotland tax rises by up to £12.60 for earners whose top £1,260 of non-savings income bore the 21% intermediate rate (with pay only, dividends or a pension). With savings it rises by up to £199.20 (2027-28: £18,000 of pay and £3,000 of interest, £1,073.77 to £1,272.97). It falls by up to £12.60 where that slice bore the 19% starter rate, and by up to £252 for earners whose tax comes mostly from dividends. The largest falls, £252, come in 2022-23 and later for earners with £12,570 of pay and £5,000 of dividends (2022-23: £262.50 to £10.50). Universal Credit's `uc_income_tax_on_earnings` rises in 234 person-years and falls in 144. These synthetic households give no population estimate, and the years after 2026-27 use the model's projections.

Invariant 4 compares the test with the model's liability, so its reforms hold the starting rate limit at or below the basic rate limit, the range in which the model's liability places the savings nil rate where Parliament does (s. 12A). It also leaves out Scottish taxpayers before 2017-18, and its years start in 2016-17. YAML cases worked from the statute cover those: the 2015-16 dividend and savings cases at the model's £32,000 limit and at the statutory £31,785, and the two cases under a raised starting rate limit.

## Test plan

- [x] YAML tests whose expected values come from an external source: new cases in `scottish_rates.yaml` and `meets_marriage_allowance_income_conditions.yaml`, which we worked by hand from ITA 2007, FA 2016, SI 2015/1810, SI 2018/459 and the Scottish rate resolutions. Both files pass: 36 and 31 cases.
- [x] `marriage_allowance_tax_reduction.yaml`: 16 cases worked by hand from ss. 55B(1) and (3) and 29(2) and (3), S6M-16531 and the parameter files, with the arithmetic in each comment. All pass.
- [x] Scoped Ruff format and lint checks, the repository F811/F821 check, and `git diff --check`.
- [x] Changelog fragment `changelog.d/2350.fixed.md`.

We ran these locally with no survey data:

- `scottish_rates.yaml`: 36 passed.
- `meets_marriage_allowance_income_conditions.yaml`: 31 passed.
- We ran `liable_only_at_marriage_allowance_rates` on 200,000 generated sets of non-savings, savings and dividend income, basic rate limits, starting rate limits, savings allowances, Gift Aid, years and nations. It agrees in every case with a hand-worked oracle of ss. 10, 12, 12A and 13 and FA 2016 s. 4(17).
- HMRC income tax YAML directory (`policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/`): 570 passed.
- At this branch's head, which merges `main` at 9dd44e142: `pension_credit_earnings_disregard.yaml`, 34 passed; the whole `policyengine_uk/tests/policy/baseline` YAML tree, 5,589 passed and none failed; `scottish_rates.yaml`, `meets_marriage_allowance_income_conditions.yaml`, `marriage_allowance_tax_reduction.yaml`, `marriage_allowance_statutory_rate.yaml` and `marriage_allowance.yaml` together, 96 passed. With `marriage_allowance` put back on the exclusions list and the reduction taken off the Step 6 list, the two Scottish Pension Credit cases fail on `income_tax` (£3,016.62 and £2,805.73) and the file's other 32 pass. With `-n 4`, the eleven property and snapshot files above together with `test_marriage_allowance_cps_switch.py`: 245 passed and 1 xfailed (the same strict xfail). `code_health`: 3,150 passed. Ruff 0.17.2 format and lint, the F811/F821 check and `git diff --check`: clean.
- Every other YAML file that names `marriage_allowance`: `marriage_allowance.yaml` 7, `marriage_allowance_statutory_rate.yaml` 6, `marriage_allowance_tax_reduction.yaml` 16, `property_income_band_base.yaml` 7, `property_finance_cost_relief.yaml` 21, `gift_aid.yaml` 23, `tax_band_historical.yaml` 16, `uc_earnings_deductions.yaml` 15, `uc_mif_earned_income.yaml` 29, `uc_is_responsible_carer.yaml` 8 and `pension_credit_statutory_pay_earnings.yaml` 12, all passed.
- `marriage_tax_reforms.yaml`: 10 passed.
- `integration/income.yaml`: 8 passed.
- `test_tax_band_scottish_properties.py`: 5 passed.
- `test_marriage_allowance_cps_switch.py`: 45 passed.
- With `-n 4`: `test_marriage_allowance_tax_reduction_properties.py`, `test_tax_band_scottish_properties.py`, `test_gift_aid.py`, `test_income_tax_step_6_step_7_properties.py`, `test_property_income_band_base_properties.py`, `test_pension_credit_earnings_disregard_properties.py`, `test_uc_state_pension_properties.py`, `test_uc_income_from_capital_properties.py`, `test_uc_unearned_benefits_properties.py`, `test_deterministic_variables.py` and `test_dated_reform_routes.py` together: 200 passed and 1 xfailed. The strict xfail `test_state_pension_does_not_change_partners_marriage_allowance` still fails: the recipient's allowance still reads the transferor's unused personal allowance (#1947, #1963).
- `code_health`: 3,095 passed.
- Ruff 0.17.2 format and lint, the F811/F821 check and `git diff --check`: clean.

We ran each mutation of the reduction on a copy of the branch, against `marriage_allowance_tax_reduction.yaml` (16 cases), `marriage_allowance_statutory_rate.yaml` (6), `property_income_band_base.yaml` (7), `uc_earnings_deductions.yaml` (15), `meets_marriage_allowance_income_conditions.yaml` (31), `marriage_tax_reforms.yaml` (10) and the three property tests:

| Mutation | Reduction YAML | Other YAML | Property tests |
|---|---|---|---|
| Revert: `marriage_allowance` back on the exclusions list, the reduction off the Step 6 list | 8 fail | Case 7 of `property_income_band_base.yaml` fails | 3 fail |
| Keep `marriage_allowance` on the exclusions list as well as the reduction | 8 fail | 2 statutory-rate cases, Case 7 and the UC Marriage Allowance case fail | 3 fail |
| Take the reduction at the recipient's top non-savings rate | the 4 Scottish cases fail | all pass | 3 fail |
| Drop the Step 5 limit | the 2 limit cases fail | all pass | the test of invariants 7, 9 and 10 fails (at 7); the other 2 pass |

No mutation changes the rate test's 31 cases or the CPS reform's 10.

We ran one-line mutations of the Marriage Allowance test and of `tax_band` against both YAML files:

| Mutation | Marriage Allowance YAML (31 cases) | `scottish_rates.yaml` (36 cases) | Cases that fail |
|---|---|---|---|
| Dividend upper rate read from the model's dividend scale | 2 fail | all pass | the two 2015-16 dividend cases |
| Savings nil rate counted in 2015-16 | 2 fail | all pass | the two 2015-16 savings cases |
| Savings nil-rate slice starts at non-savings income, not at the starting rate limit | 1 fails | all pass | the £37,500 starting rate limit case |
| Scottish limit before 2017-18 read off the 2017-18 schedule | 2 fail | all pass | the 2015-16 and 2016-17 Scottish cases |
| Savings test on all taxable income instead of non-savings income and savings | all pass | all pass | none (see below) |
| `tax_band` without the Gift Aid rise in the UK limits | all pass | 1 fails | Scottish 2025 dividends at the Gift Aid limit |
| `tax_band` puts income at the UK additional limit above it | all pass | 1 fails | Scottish 2025 savings at the higher rate limit |
| `tax_band` reads `earned_taxable_income` | all pass | 2 fail | both property-income cases at the higher rate limit |

Under the £5,000 starting rate limit, a slice that starts at non-savings income and one that starts at the larger of it and the limit give the same answer: where they differ, both end below the basic rate limit. So only a raised starting rate limit separates the slice mutation, and the YAML case under a £37,500 limit does. The savings-test mutation changes the savings result only where dividends sit above the savings and take income past the basic rate limit. There the dividend test already fails the person. So no input whose net income equals the sum of its non-savings, savings and dividend income separates the mutation at the helper's output, and the 200,000-case differential above finds no difference with it either. A supplied `adjusted_net_income` below the income components breaks that equality and separates them.

🤖 Generated with [Claude Code](https://claude.com/claude-code)




REPLY.md

Thanks for the re-review. A1: we updated the two Scottish couple cases in `pension_credit_earnings_disregard.yaml` (2025-26) to the Step 6 reduction and checked the outputs below `income_tax` by hand.

| Output | Old | New |
|---|---|---|
| `income_tax`, with £1,040 of pay | £3,016.62 | £3,029.22 |
| `income_tax`, without pay | £2,805.73 | £2,810.82 |
| `pension_credit_earnings_disregard`, with pay | £829.11 | £821.60 |
| `pension_credit_income`, both cases | £25,194.27 | £25,189.18 |

- Tax: £16,470 of taxable income with pay and £15,430 without both exceed £14,921, so the pay does not cross into the intermediate band; tax on the Scottish schedule comes to £3,281.22 and £3,062.82, less 20% x £1,260 = £252 under s. 55B(1) and (3).
- Disregard: the pay adds £218.40 of tax (£1,040 x 21%) and no Class 1 at age 70, so net earnings come to £821.60 and the £20-a-week disregard stops there.
- Pension Credit income: £29,040 - £3,029.22 - £821.60 = £28,000 - £2,810.82 = £25,189.18, the same with and without pay.

The case comments now show these steps. After merging `main` at 9dd44e142, the file passes 34 of 34, and the whole `policyengine_uk/tests/policy/baseline` tree passes 5,589 with none failing. With the old deduction restored on a copy, the two cases fail on `income_tax` at £3,016.62 and £2,805.73.

Generated by Claude Code

The taxable income exceeds 14,921 even without the earnings, so all 1,040
of them bear 21%. The claimant pays no Class 1 contributions above State
Pension age, and the 20 pound disregard covers all 821.60 of net earnings.
No expected value changes.

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

Copy link
Copy Markdown
Collaborator Author

Thanks for the re-review. For A1, the two Scottish couple cases in pension_credit_earnings_disregard.yaml (2025-26) now expect tax after the Step 6 reduction. We worked out each changed value by hand:

Output Old New
income_tax, with £1,040 of pay £3,016.62 £3,029.22
income_tax, without pay £2,805.73 £2,810.82
pension_credit_earnings_disregard, with pay £829.11 £821.60
pension_credit_income, both cases £25,194.27 £25,189.18
  • Tax at the Scottish rates comes to £3,281.22 with pay and £3,062.82 without, and Parliament takes 20% x £1,260 = £252 off each at Step 6 (s. 55B).
  • Taxable income exceeds £14,921, where the intermediate rate starts, even without pay, so the pay adds £218.40 of tax (£1,040 x 21%). The claimant pays no Class 1 contributions at age 70, so net earnings come to £821.60, and the £20-a-week disregard covers them in full.
  • Pension Credit income comes to £29,040 - £3,029.22 - £821.60 = £28,000 - £2,810.82 = £25,189.18, the same with and without pay.

The case comments now set out these steps. At 2ca7c5ff7, which merges main at 9dd44e1, the file passes 34 of 34 and the whole policyengine_uk/tests/policy/baseline tree passes 5,589, with none failing. When we restored the old deduction, the two cases failed on income_tax, at £3,016.62 and £2,805.73. Could you take another look at e511964cb, which changes only a comment after 2ca7c5ff7?

@MaxGhenis
MaxGhenis marked this pull request as ready for review November 4, 2026 14:06
@MaxGhenis
MaxGhenis requested a review from juaristi22 November 4, 2026 14:06

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed adopted head e511964cb5d3408713bf16910857c0ad00b595b7. COMPLETE — A1 resolved; C1 and C2 remain resolved; no open findings or material evidence gaps.

Both Scottish Pension Credit cases now use the statutory Step 6 reduction: tax £3,029.22 with pay and £2,810.82 without; the £218.40 tax increment leaves £821.60 net earnings, fully disregarded. Pension Credit income is £25,189.18 in both cases. Independent statutory arithmetic and current execution agree.

All 61 selected repository checks passed, including all 34 cases in the changed Pension Credit YAML. Final household checks also confirm unchanged calculated Pension Credit/CTR with wages and an £821.60 household-income increase, on the stated reported-AA and take-up assumptions. A reviewer input-name error stopped the first external PC diagnostic before calculation; only that diagnostic was corrected and rerun successfully. The original log is retained; repository tests were not repeated.

The current source records and earlier qualifications remain intact. Approval awaits the remaining exact-head CI; the completed review can be retained for that CI-only follow-up.

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved current head e511964cb5d3408713bf16910857c0ad00b595b7. COMPLETE — C1, C2 and A1 remain resolved; no findings or material evidence gaps. Applicable current-head checks have passed.

The completed review of the Scottish Marriage Allowance tax reduction and Pension Credit earnings-disregard regression is retained. The 61 passing repository checks, successful final tax/Pension Credit/CTR/household-income checks and 36 original/source-extract pairs were integrity-checked at this identical head. No tests or calculations were repeated for this CI-only approval; the original reviewer-fixture correction and historical results remain separately qualified in the full report.

The actual Axiom #523 and #536 records and their declared encoding blockers remain unchanged.

…s new tests

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

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incremental review at ffa8651ff178289a0935ba9349c3b0d87c4e2433: COMPLETE, no remaining findings or material evidence gaps. Prior C1, C2 and A1 remain resolved.

The previously approved Scottish tax-band and Marriage Allowance core logic is unchanged. This round checked the changed earnings/unearned-tax attribution through Welsh working-age Council Tax Reduction against the paid-tax disregard rule and the relevant Axiom source packets.

56 current repository tests passed (49 YAML and 7 Python), plus one actual-input Welsh couple control through final income tax, Council Tax Reduction and household net income: the £252 tax reduction lowers CTR by £50.40, giving a £201.60 net-income gain. The earlier 61 passes remain separate historical evidence. All 38 retained/new source originals and their extracts passed integrity checks. Reviewer-only harness setup/assertion errors were corrected against the saved outputs and are documented separately from repository test outcomes.

Fresh approval is deferred while current-head CI is pending. This completed code/source review can be retained while CI is checked on a later run.

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

All checks pass at ffa8651ff, and it merges cleanly with main at d60944e9e. Could you look again?

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved at ffa8651ff178289a0935ba9349c3b0d87c4e2433. The completed independent review has no remaining findings or material evidence gaps; C1, C2 and A1 remain resolved. All 21 latest checks now pass at this exact head, including the required Lint and Test / Result checks.

This closes the pending-CI approval hold. The reviewed code and description are unchanged, all 38 retained source pairs were integrity-checked, and the author's approval request adds no new scope. No code review, tests or model calculations were repeated.

MaxGhenis added a commit that referenced this pull request Nov 6, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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.

tax_band compares a Scottish taxpayer's total income with the Scottish thresholds; the Scottish rates apply to non-savings, non-dividend income only

3 participants