Skip to content

Commit e03fc3c

Browse files
vahid-ahmadiclaude
andauthored
Parametrise Marriage Allowance eligible bands and fix NONE case (#1624)
* Parametrise Marriage Allowance eligible bands and fix NONE case Fixes #395. The previous formula hard-coded BASIC / STARTER / INTERMEDIATE as the eligible tax bands for transferring Marriage Allowance. Replaces that with a list parameter gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bands so the set is declarative, reform-friendly, and documents itself against ITA 2007 s.55B. Also adds NONE to the default list. Someone whose taxable income sits below the personal allowance is band NONE, which the old check rejected — but ITA 2007 s.55B(1)(a) only excludes transferors who are liable at the higher rate or above, so a zero-tax spouse is eligible to transfer their unused allowance (this is a common motivation for electing MA in the first place). Adds regression YAML cases for NONE, STARTER, and INTERMEDIATE bands. The existing BASIC / HIGHER / ADDITIONAL assertions are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Route CPS expanded-MA reform through the eligible_bands parameter The CPS expanded-Marriage-Allowance reform was overriding meets_marriage_allowance_income_conditions with its own hard-coded BASIC | STARTER | INTERMEDIATE check (plus the HIGHER/ADDITIONAL expansion), so the baseline parametrisation and the NONE fix from 291774a did not reach simulations running under that reform. Replace the hard-coded base with the same np.isin(band.decode_to_str(), eligible_bands) lookup used in the baseline variable, then OR the existing HIGHER/ADDITIONAL expansion on top. Both code paths now read the parameter, and the NONE-band eligibility flows through to reform runs for free. Also adjust the changelog fragment to mention both call sites. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ed4f10b commit e03fc3c

5 files changed

Lines changed: 51 additions & 17 deletions

File tree

changelog.d/395.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Parametrise the Marriage Allowance transferor-eligible tax bands as `gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bands` and include `NONE` (below-personal-allowance earners) in the default list, matching ITA 2007 s.55B — a person with no taxable income is still eligible to transfer their unused allowance and was previously rejected by the hard-coded check. The CPS expanded-Marriage-Allowance reform now also consumes the parameter, so both code paths agree on the baseline eligible-band set.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
description: Tax bands whose members may transfer personal allowance under the Marriage Allowance election (ITA 2007 s.55B). A transferor is eligible if they are not liable at the higher rate or above; the Scottish intermediate rate is treated as within the basic-rate envelope for this purpose.
2+
values:
3+
0000-01-01:
4+
- NONE
5+
- STARTER
6+
- BASIC
7+
- INTERMEDIATE
8+
metadata:
9+
unit: list
10+
label: Marriage Allowance eligible tax bands
11+
period: year
12+
reference:
13+
- title: "Income Tax Act 2007, s. 55B"
14+
href: https://www.legislation.gov.uk/ukpga/2007/3/section/55B

policyengine_uk/reforms/cps/marriage_tax_reforms.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,18 @@ class meets_marriage_allowance_income_conditions(Variable):
3434
value_type = bool
3535
reference = "https://www.legislation.gov.uk/ukpga/2007/3/section/55B"
3636

37-
def formula(person, period):
37+
def formula(person, period, parameters):
3838
band = person("tax_band", period)
39+
eligible_bands = parameters(
40+
period
41+
).gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bands
42+
base_eligible = np.isin(band.decode_to_str(), eligible_bands)
43+
# Expand to higher bands if the reform's expansion conditions are met.
3944
bands = band.possible_values
40-
return (
41-
(band == bands.BASIC)
42-
| (band == bands.STARTER)
43-
| (band == bands.INTERMEDIATE)
44-
| ( # Expand to higher bands if reform conditions are met.
45-
person("meets_expanded_ma_conditions", period)
46-
& ((band == bands.HIGHER) | (band == bands.ADDITIONAL))
47-
)
45+
expansion = person("meets_expanded_ma_conditions", period) & (
46+
(band == bands.HIGHER) | (band == bands.ADDITIONAL)
4847
)
48+
return base_eligible | expansion
4949

5050
class marriage_allowance(Variable):
5151
value_type = float

policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/allowances/meets_marriage_allowance_income_conditions.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,24 @@
1818
tax_band: ADDITIONAL
1919
output:
2020
meets_marriage_allowance_income_conditions: false
21+
22+
- name: Below-PA earner (band NONE) is eligible for Marriage Allowance (regression for #395)
23+
period: 2021
24+
input:
25+
tax_band: NONE
26+
output:
27+
meets_marriage_allowance_income_conditions: true
28+
29+
- name: Scottish starter rate band is eligible for Marriage Allowance
30+
period: 2021
31+
input:
32+
tax_band: STARTER
33+
output:
34+
meets_marriage_allowance_income_conditions: true
35+
36+
- name: Scottish intermediate rate band is eligible for Marriage Allowance
37+
period: 2021
38+
input:
39+
tax_band: INTERMEDIATE
40+
output:
41+
meets_marriage_allowance_income_conditions: true
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from policyengine_uk.model_api import *
2-
from numpy import ceil
2+
import numpy as np
33

44

55
class meets_marriage_allowance_income_conditions(Variable):
@@ -10,11 +10,9 @@ class meets_marriage_allowance_income_conditions(Variable):
1010
value_type = bool
1111
reference = "https://www.legislation.gov.uk/ukpga/2007/3/section/55B"
1212

13-
def formula(person, period):
13+
def formula(person, period, parameters):
1414
band = person("tax_band", period)
15-
bands = band.possible_values
16-
return (
17-
(band == bands.BASIC)
18-
| (band == bands.STARTER)
19-
| (band == bands.INTERMEDIATE)
20-
)
15+
eligible_bands = parameters(
16+
period
17+
).gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bands
18+
return np.isin(band.decode_to_str(), eligible_bands)

0 commit comments

Comments
 (0)