From 59b17a7d2607efa957ee647e89e9e3003d1fec48 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 01:39:16 -0400 Subject: [PATCH 01/14] Set Scottish income tax limits and rates from each year's resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Scottish Parliament's rate resolutions set, as taxable income above the personal allowance: - 2018-19 (S5M-10397): a 41% higher rate from £31,580, where the file held 40% from £31,500 until 2021-22; - 2019-20 (S5M-15879) and 2020-21 (S5M-21090): limits of £2,049, £12,444 and £30,930, then £2,085, £12,658 and £30,930, where the file repeated the 2018-19 limits; - 2021-22 (S5M-24225): starter and basic rate limits of £2,097 and £12,726, where the file held the 2024-25 limits of £2,306 and £13,991. The 2017-18, 2022-23 and 2023-24 values already matched S5M-03912, S6M-03019 and S6M-07853. Each dated value now names its motion and paragraph, and the references list every resolution from 2017-18. Fixes #2783 Co-Authored-By: Claude Opus 5.5 --- .../hmrc/income_tax/rates/scotland/rates.yaml | 119 +++++++++++------- 1 file changed, 75 insertions(+), 44 deletions(-) diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml index c5526f3564..4967126118 100644 --- a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml @@ -1,4 +1,9 @@ description: Rates for Scottish Income Tax. +# Each year's Scottish rate resolution sets these rates and limits for that +# tax year only (Scotland Act 1998 s. 80C(3)). The comment on each dated value +# names the motion and paragraph. The resolutions state the limits as taxable +# income, above the personal allowance, and this file holds them as stated. +# gov.scot's tables add the standard personal allowance to the same limits. # The Scottish Budget 2026-27 announces higher, advanced and top threshold # freezes through 2028-29. These future values model announced policy; # Scottish rates and bands are still subject to annual rate resolutions. @@ -7,98 +12,124 @@ description: Rates for Scottish Income Tax. brackets: - threshold: values: - 2017-04-06: null - 2018-04-06: 0 + 2017-04-06: null # S5M-03912 sets no starter rate + 2018-04-06: 0 # S5M-10397 (a) and paragraph (a) of each later motion 2021-04-06: 0 metadata: uprating: gov.economic_assumptions.indices.obr.consumer_price_index rate: 2017-04-01: null - 2018-04-06: 0.19 # Starter rate + 2018-04-06: 0.19 # Starter rate: paragraph (a) from S5M-10397 - threshold: values: - 2017-04-06: 0 - 2018-04-06: 2_000 - 2021-04-06: 2_306 - 2022-04-06: 2_162 - 2023-04-06: 2_162 - 2024-04-06: 2_306 - 2025-04-06: 2_827 - 2026-04-06: 3_967 + 2017-04-06: 0 # S5M-03912 (a) + 2018-04-06: 2_000 # S5M-10397 (a) + 2019-04-06: 2_049 # S5M-15879 (a) + 2020-04-06: 2_085 # S5M-21090 (a) + 2021-04-06: 2_097 # S5M-24225 (a) + 2022-04-06: 2_162 # S6M-03019 (a) + 2023-04-06: 2_162 # S6M-07853 (a) + 2024-04-06: 2_306 # S6M-12252 (a) + 2025-04-06: 2_827 # S6M-16531 (a) + 2026-04-06: 3_967 # S6M-20844 (a) metadata: uprating: gov.economic_assumptions.indices.obr.consumer_price_index rate: - 2017-04-06: 0.2 # Basic rate + 2017-04-06: 0.2 # Basic rate: S5M-03912 (a), then paragraph (b) - threshold: values: - 2017-04-06: null - 2018-04-06: 12_150 - 2021-04-06: 13_991 - 2022-04-06: 13_118 - 2023-04-06: 13_118 - 2024-04-06: 13_991 - 2025-04-06: 14_921 - 2026-04-06: 16_956 + 2017-04-06: null # S5M-03912 sets no intermediate rate + 2018-04-06: 12_150 # S5M-10397 (b) + 2019-04-06: 12_444 # S5M-15879 (b) + 2020-04-06: 12_658 # S5M-21090 (b) + 2021-04-06: 12_726 # S5M-24225 (b) + 2022-04-06: 13_118 # S6M-03019 (b) + 2023-04-06: 13_118 # S6M-07853 (b) + 2024-04-06: 13_991 # S6M-12252 (b) + 2025-04-06: 14_921 # S6M-16531 (b) + 2026-04-06: 16_956 # S6M-20844 (b) metadata: uprating: gov.economic_assumptions.indices.obr.consumer_price_index rate: 2017-04-06: null - 2018-04-06: 0.21 # Intermediate rate + 2018-04-06: 0.21 # Intermediate rate: paragraph (c) from S5M-10397 - threshold: values: - 2017-04-06: 31_500 - 2021-04-06: 31_092 - 2022-04-06: 31_092 - 2023-04-06: 31_092 - 2024-04-06: 31_092 - 2025-04-06: 31_092 + 2017-04-06: 31_500 # S5M-03912 (a) + 2018-04-06: 31_580 # S5M-10397 (c) + 2019-04-06: 30_930 # S5M-15879 (c) + 2020-04-06: 30_930 # S5M-21090 (c) + 2021-04-06: 31_092 # S5M-24225 (c) + 2022-04-06: 31_092 # S6M-03019 (c) + 2023-04-06: 31_092 # S6M-07853 (c) + 2024-04-06: 31_092 # S6M-12252 (c) + 2025-04-06: 31_092 # S6M-16531 (c) # Scottish Budget 2026-27 announced freeze through 2028-29. - 2026-04-06: 31_092 + 2026-04-06: 31_092 # S6M-20844 (c) 2027-04-06: 31_092 2028-04-06: 31_092 metadata: uprating: gov.economic_assumptions.indices.obr.consumer_price_index rate: - 2017-04-06: 0.4 - 2021-04-06: 0.41 # Higher rate - 2023-04-06: 0.42 + 2017-04-06: 0.4 # S5M-03912 (b) + 2018-04-06: 0.41 # Higher rate: paragraph (d), S5M-10397 to S6M-03019 + 2023-04-06: 0.42 # S6M-07853 (d), then paragraph (d) to S6M-20844 - threshold: values: - 2017-04-06: 150_000 - 2023-04-06: 125_140 - 2024-04-06: 62_430 - 2025-04-06: 62_430 + 2017-04-06: 150_000 # S5M-03912 (b) + 2018-04-06: 150_000 # S5M-10397 (d) + 2019-04-06: 150_000 # S5M-15879 (d) + 2020-04-06: 150_000 # S5M-21090 (d) + 2021-04-06: 150_000 # S5M-24225 (d) + 2022-04-06: 150_000 # S6M-03019 (d) + 2023-04-06: 125_140 # S6M-07853 (d) + 2024-04-06: 62_430 # S6M-12252 (d) + 2025-04-06: 62_430 # S6M-16531 (d) # Scottish Budget 2026-27 announced freeze through 2028-29. - 2026-04-06: 62_430 + 2026-04-06: 62_430 # S6M-20844 (d) 2027-04-06: 62_430 2028-04-06: 62_430 metadata: uprating: gov.economic_assumptions.indices.obr.consumer_price_index rate: - 2017-04-06: 0.45 - 2018-04-06: 0.46 # Additional rate - 2023-04-06: 0.47 - 2024-04-06: 0.45 + 2017-04-06: 0.45 # S5M-03912 (c) + 2018-04-06: 0.46 # Top rate: paragraph (e), S5M-10397 to S6M-03019 + 2023-04-06: 0.47 # S6M-07853 (e) + 2024-04-06: 0.45 # Advanced rate: paragraph (e) from S6M-12252 - threshold: values: 2017-04-06: null # The personal allowance is fully withdrawn at £125,140, so the # taxable-income top limit equals total income: do not subtract PA. - 2024-04-06: 125_140 - 2025-04-06: 125_140 - 2026-04-06: 125_140 + 2024-04-06: 125_140 # S6M-12252 (e) + 2025-04-06: 125_140 # S6M-16531 (e) + 2026-04-06: 125_140 # S6M-20844 (e) 2027-04-06: 125_140 2028-04-06: 125_140 metadata: uprating: gov.economic_assumptions.indices.obr.consumer_price_index rate: 2017-04-06: null - 2024-04-06: 0.48 + 2024-04-06: 0.48 # Top rate: paragraph (f) from S6M-12252 metadata: threshold_unit: currency-GBP rate_unit: /1 label: Scottish Income Tax rates reference: + - title: Scottish Rate Resolution 2017-18 (S5M-03912), paragraphs (a)-(c) + href: https://www.parliament.scot/chamber-and-committees/votes-and-motions/S5M-03912 + - title: Scottish Rate Resolution 2018-19 (S5M-10397), paragraphs (a)-(e) + href: https://www.parliament.scot/chamber-and-committees/votes-and-motions/S5M-10397 + - title: Scottish Rate Resolution 2019-20 (S5M-15879), paragraphs (a)-(e) + href: https://www.parliament.scot/chamber-and-committees/votes-and-motions/S5M-15879 + - title: Scottish Rate Resolution 2020-21 (S5M-21090), paragraphs (a)-(e) + href: https://www.parliament.scot/chamber-and-committees/votes-and-motions/S5M-21090 + - title: Scottish Rate Resolution 2021-22 (S5M-24225), paragraphs (a)-(e) + href: https://www.parliament.scot/chamber-and-committees/votes-and-motions/S5M-24225 + - title: Scottish Rate Resolution 2022-23 (S6M-03019), paragraphs (a)-(e) + href: https://www.parliament.scot/chamber-and-committees/votes-and-motions/S6M-03019 + - title: Scottish Rate Resolution 2023-24 (S6M-07853), paragraphs (a)-(e) + href: https://www.parliament.scot/chamber-and-committees/votes-and-motions/S6M-07853 - title: Scottish Rate Resolution 2024-25 (S6M-12252), paragraphs (a)-(f) href: https://www.parliament.scot/chamber-and-committees/votes-and-motions/S6M-12252 - title: Scottish Rate Resolution 2025-26 (S6M-16531), paragraphs (a)-(f) From 463b69182e99f5ac97f4911efc53f511759d79d8 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 01:39:16 -0400 Subject: [PATCH 02/14] Test Scottish income tax against each rate resolution from 2017-18 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scottish_rate_resolutions.yaml: 29 cases worked by hand from S5M-10397, S5M-15879, S5M-21090 and S5M-24225, with a taxpayer in each band, one at each corrected limit and the issue's £50,000 of pay in 2018-19 (£9,184). - test_scottish_income_tax_rates.py: compares every limit and rate from 2017-18 to 2026-27 with the resolutions restated in the test, on the model year and across each tax year in the statutory tree; checks the limits plus the personal allowance against gov.scot's tables; and, on hand-built Scottish taxpayers, checks with Hypothesis that income tax on pay equals the resolution's bands and never falls as pay rises. Co-Authored-By: Claude Opus 5.5 --- .../income_tax/scottish_rate_resolutions.yaml | 379 ++++++++++++++++++ .../tests/test_scottish_income_tax_rates.py | 248 ++++++++++++ 2 files changed, 627 insertions(+) create mode 100644 policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml diff --git a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml new file mode 100644 index 0000000000..a44cbe718a --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml @@ -0,0 +1,379 @@ +# Scottish income tax on pay alone, in the tax years whose rates and limits +# PolicyEngine/policyengine-uk#2783 corrects. Each motion sets the rates and +# limits on taxable income, above the personal allowance: +# https://www.parliament.scot/chamber-and-committees/votes-and-motions/ +# Personal allowance: £11,850 (2018-19), £12,500 (2019-20 and 2020-21) and +# £12,570 (2021-22), withdrawn by £1 for every £2 of income above £100,000 +# (ITA 2007 s. 35), so it is nil at £160,000. gov.scot's tables for each year +# give the same bands with that allowance added. + +# 2018-19, S5M-10397: 19% to £2,000, 20% to £12,150, 21% to £31,580, +# 41% to £150,000, 46% above. + +- name: Scottish 2018-19 pay of 13000 is taxed at the starter rate + period: 2018 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 13_000 + region: SCOTLAND + output: + # 1,150 x 19% = 218.50. + earned_taxable_income: 1_150 + income_tax: 218.50 + +- name: Scottish 2018-19 pay of 20000 reaches the basic rate + period: 2018 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 20_000 + region: SCOTLAND + output: + # 2,000 x 19% + 6,150 x 20% = 380 + 1,230 = 1,610. + earned_taxable_income: 8_150 + income_tax: 1_610 + +- name: Scottish 2018-19 pay of 30000 reaches the intermediate rate + period: 2018 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 30_000 + region: SCOTLAND + output: + # 380 + 10,150 x 20% + 6,000 x 21% = 380 + 2,030 + 1,260 = 3,670. + earned_taxable_income: 18_150 + income_tax: 3_670 + +- name: Scottish 2018-19 taxable income at the 31580 higher rate limit has no tax at 41 percent + period: 2018 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 43_430 + region: SCOTLAND + output: + # gov.scot: intermediate rate "Over £24,000 to £43,430". + # 380 + 2,030 + 19,430 x 21% = 380 + 2,030 + 4,080.30 = 6,490.30. + earned_taxable_income: 31_580 + income_tax: 6_490.30 + +- name: Scottish 2018-19 pay of 50000 reaches the 41 percent higher rate + period: 2018 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 50_000 + region: SCOTLAND + output: + # The issue's case: 6,490.30 + 6,570 x 41% = 6,490.30 + 2,693.70 = 9,184. + earned_taxable_income: 38_150 + income_tax: 9_184 + +- name: Scottish 2018-19 pay of 160000 reaches the 46 percent top rate + period: 2018 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 160_000 + region: SCOTLAND + output: + # 6,490.30 + 118,420 x 41% + 10,000 x 46% + # = 6,490.30 + 48,552.20 + 4,600 = 59,642.50. + earned_taxable_income: 160_000 + income_tax: 59_642.50 + +# 2019-20, S5M-15879: 19% to £2,049, 20% to £12,444, 21% to £30,930, +# 41% to £150,000, 46% above. + +- name: Scottish 2019-20 pay of 13500 is taxed at the starter rate + period: 2019 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 13_500 + region: SCOTLAND + output: + # 1,000 x 19% = 190. + earned_taxable_income: 1_000 + income_tax: 190 + +- name: Scottish 2019-20 taxable income at the 2049 starter rate limit is all at 19 percent + period: 2019 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 14_549 + region: SCOTLAND + output: + # gov.scot: starter rate "Over £12,500-£14,549". 2,049 x 19% = 389.31. + earned_taxable_income: 2_049 + income_tax: 389.31 + +- name: Scottish 2019-20 pay of 20000 reaches the basic rate + period: 2019 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 20_000 + region: SCOTLAND + output: + # 389.31 + 5,451 x 20% = 389.31 + 1,090.20 = 1,479.51. + earned_taxable_income: 7_500 + income_tax: 1_479.51 + +- name: Scottish 2019-20 taxable income at the 12444 basic rate limit has no tax at 21 percent + period: 2019 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 24_944 + region: SCOTLAND + output: + # gov.scot: basic rate "Over £14,549-£24,944". + # 389.31 + 10,395 x 20% = 389.31 + 2,079 = 2,468.31. + earned_taxable_income: 12_444 + income_tax: 2_468.31 + +- name: Scottish 2019-20 pay of 35000 reaches the intermediate rate + period: 2019 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 35_000 + region: SCOTLAND + output: + # 2,468.31 + 10,056 x 21% = 2,468.31 + 2,111.76 = 4,580.07. + earned_taxable_income: 22_500 + income_tax: 4_580.07 + +- name: Scottish 2019-20 taxable income at the 30930 higher rate limit has no tax at 41 percent + period: 2019 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 43_430 + region: SCOTLAND + output: + # gov.scot: intermediate rate "Over £24,944-£43,430". + # 2,468.31 + 18,486 x 21% = 2,468.31 + 3,882.06 = 6,350.37. + earned_taxable_income: 30_930 + income_tax: 6_350.37 + +- name: Scottish 2019-20 pay of 50000 reaches the 41 percent higher rate + period: 2019 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 50_000 + region: SCOTLAND + output: + # 6,350.37 + 6,570 x 41% = 6,350.37 + 2,693.70 = 9,044.07. + earned_taxable_income: 37_500 + income_tax: 9_044.07 + +- name: Scottish 2019-20 pay of 160000 reaches the 46 percent top rate + period: 2019 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 160_000 + region: SCOTLAND + output: + # 6,350.37 + 119,070 x 41% + 10,000 x 46% + # = 6,350.37 + 48,818.70 + 4,600 = 59,769.07. + earned_taxable_income: 160_000 + income_tax: 59_769.07 + +# 2020-21, S5M-21090: 19% to £2,085, 20% to £12,658, 21% to £30,930, +# 41% to £150,000, 46% above. + +- name: Scottish 2020-21 pay of 13500 is taxed at the starter rate + period: 2020 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 13_500 + region: SCOTLAND + output: + # 1,000 x 19% = 190. + earned_taxable_income: 1_000 + income_tax: 190 + +- name: Scottish 2020-21 taxable income at the 2085 starter rate limit is all at 19 percent + period: 2020 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 14_585 + region: SCOTLAND + output: + # gov.scot: starter rate "Over £12,500 - £14,585". 2,085 x 19% = 396.15. + earned_taxable_income: 2_085 + income_tax: 396.15 + +- name: Scottish 2020-21 pay of 20000 reaches the basic rate + period: 2020 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 20_000 + region: SCOTLAND + output: + # 396.15 + 5,415 x 20% = 396.15 + 1,083 = 1,479.15. + earned_taxable_income: 7_500 + income_tax: 1_479.15 + +- name: Scottish 2020-21 taxable income at the 12658 basic rate limit has no tax at 21 percent + period: 2020 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 25_158 + region: SCOTLAND + output: + # gov.scot: basic rate "Over £14,585 - £25,158". + # 396.15 + 10,573 x 20% = 396.15 + 2,114.60 = 2,510.75. + earned_taxable_income: 12_658 + income_tax: 2_510.75 + +- name: Scottish 2020-21 pay of 35000 reaches the intermediate rate + period: 2020 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 35_000 + region: SCOTLAND + output: + # 2,510.75 + 9,842 x 21% = 2,510.75 + 2,066.82 = 4,577.57. + earned_taxable_income: 22_500 + income_tax: 4_577.57 + +- name: Scottish 2020-21 taxable income at the 30930 higher rate limit has no tax at 41 percent + period: 2020 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 43_430 + region: SCOTLAND + output: + # gov.scot: intermediate rate "Over £25,158 - £43,430". + # 2,510.75 + 18,272 x 21% = 2,510.75 + 3,837.12 = 6,347.87. + earned_taxable_income: 30_930 + income_tax: 6_347.87 + +- name: Scottish 2020-21 pay of 50000 reaches the 41 percent higher rate + period: 2020 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 50_000 + region: SCOTLAND + output: + # 6,347.87 + 6,570 x 41% = 6,347.87 + 2,693.70 = 9,041.57. + earned_taxable_income: 37_500 + income_tax: 9_041.57 + +- name: Scottish 2020-21 pay of 160000 reaches the 46 percent top rate + period: 2020 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 160_000 + region: SCOTLAND + output: + # 6,347.87 + 119,070 x 41% + 10,000 x 46% + # = 6,347.87 + 48,818.70 + 4,600 = 59,766.57. + earned_taxable_income: 160_000 + income_tax: 59_766.57 + +# 2021-22, S5M-24225: 19% to £2,097, 20% to £12,726, 21% to £31,092, +# 41% to £150,000, 46% above. + +- name: Scottish 2021-22 pay of 13570 is taxed at the starter rate + period: 2021 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 13_570 + region: SCOTLAND + output: + # 1,000 x 19% = 190. + earned_taxable_income: 1_000 + income_tax: 190 + +- name: Scottish 2021-22 taxable income at the 2097 starter rate limit is all at 19 percent + period: 2021 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 14_667 + region: SCOTLAND + output: + # gov.scot: starter rate "Over £12,570* - £14,667". 2,097 x 19% = 398.43. + earned_taxable_income: 2_097 + income_tax: 398.43 + +- name: Scottish 2021-22 pay of 20000 reaches the basic rate + period: 2021 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 20_000 + region: SCOTLAND + output: + # 398.43 + 5,333 x 20% = 398.43 + 1,066.60 = 1,465.03. + earned_taxable_income: 7_430 + income_tax: 1_465.03 + +- name: Scottish 2021-22 taxable income at the 12726 basic rate limit has no tax at 21 percent + period: 2021 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 25_296 + region: SCOTLAND + output: + # gov.scot: basic rate "Over £14,667 - £25,296". + # 398.43 + 10,629 x 20% = 398.43 + 2,125.80 = 2,524.23. + earned_taxable_income: 12_726 + income_tax: 2_524.23 + +- name: Scottish 2021-22 pay of 35000 reaches the intermediate rate + period: 2021 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 35_000 + region: SCOTLAND + output: + # 2,524.23 + 9,704 x 21% = 2,524.23 + 2,037.84 = 4,562.07. + earned_taxable_income: 22_430 + income_tax: 4_562.07 + +- name: Scottish 2021-22 pay of 50000 reaches the 41 percent higher rate + period: 2021 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 50_000 + region: SCOTLAND + output: + # 2,524.23 + 18,366 x 21% + 6,338 x 41% + # = 2,524.23 + 3,856.86 + 2,598.58 = 8,979.67. + earned_taxable_income: 37_430 + income_tax: 8_979.67 + +- name: Scottish 2021-22 pay of 160000 reaches the 46 percent top rate + period: 2021 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 160_000 + region: SCOTLAND + output: + # 6,381.09 + 118,908 x 41% + 10,000 x 46% + # = 6,381.09 + 48,752.28 + 4,600 = 59,733.37. + earned_taxable_income: 160_000 + income_tax: 59_733.37 diff --git a/policyengine_uk/tests/test_scottish_income_tax_rates.py b/policyengine_uk/tests/test_scottish_income_tax_rates.py index 88621ba922..60c394e7ed 100644 --- a/policyengine_uk/tests/test_scottish_income_tax_rates.py +++ b/policyengine_uk/tests/test_scottish_income_tax_rates.py @@ -1,6 +1,109 @@ +import numpy as np import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st +from policyengine_uk import Simulation from policyengine_uk.system import system +from policyengine_uk.tax_benefit_system import statutory_parameters + +# Each year's Scottish rate resolution, restated paragraph by paragraph from +# the motion at +# https://www.parliament.scot/chamber-and-committees/votes-and-motions/: +# the rate, and the limit of taxable income it is charged up to (None for the +# last rate, which has no limit). The limits are above the personal allowance. +SCOTTISH_RATE_RESOLUTIONS = { + 2017: ("S5M-03912", [(0.20, 31_500), (0.40, 150_000), (0.45, None)]), + 2018: ( + "S5M-10397", + [(0.19, 2_000), (0.20, 12_150), (0.21, 31_580), (0.41, 150_000), (0.46, None)], + ), + 2019: ( + "S5M-15879", + [(0.19, 2_049), (0.20, 12_444), (0.21, 30_930), (0.41, 150_000), (0.46, None)], + ), + 2020: ( + "S5M-21090", + [(0.19, 2_085), (0.20, 12_658), (0.21, 30_930), (0.41, 150_000), (0.46, None)], + ), + 2021: ( + "S5M-24225", + [(0.19, 2_097), (0.20, 12_726), (0.21, 31_092), (0.41, 150_000), (0.46, None)], + ), + 2022: ( + "S6M-03019", + [(0.19, 2_162), (0.20, 13_118), (0.21, 31_092), (0.41, 150_000), (0.46, None)], + ), + 2023: ( + "S6M-07853", + [(0.19, 2_162), (0.20, 13_118), (0.21, 31_092), (0.42, 125_140), (0.47, None)], + ), + 2024: ( + "S6M-12252", + [ + (0.19, 2_306), + (0.20, 13_991), + (0.21, 31_092), + (0.42, 62_430), + (0.45, 125_140), + (0.48, None), + ], + ), + 2025: ( + "S6M-16531", + [ + (0.19, 2_827), + (0.20, 14_921), + (0.21, 31_092), + (0.42, 62_430), + (0.45, 125_140), + (0.48, None), + ], + ), + 2026: ( + "S6M-20844", + [ + (0.19, 3_967), + (0.20, 16_956), + (0.21, 31_092), + (0.42, 62_430), + (0.45, 125_140), + (0.48, None), + ], + ), +} + +# gov.scot's table for each year: the standard personal allowance it assumes +# and the top of each band but the last, as income including that allowance. +# 2017-18: https://www.gov.scot/news/income-tax-rates-set/ +# 2018-19: https://www.gov.scot/publications/scottish-income-tax-2018-2019/ +# 2019-20 to 2021-22: https://www.gov.scot/publications/scottish-income-tax-2019-2020/ +# and the 2020-2021 and 2021-2022 pages, now in the National Records of +# Scotland web archive. +# 2022-23 onwards: https://www.gov.scot/publications/scottish-income-tax-rates-and-bands/ +GOV_SCOT_TABLES = { + 2017: (11_500, [43_000, 150_000]), + 2018: (11_850, [13_850, 24_000, 43_430, 150_000]), + 2019: (12_500, [14_549, 24_944, 43_430, 150_000]), + 2020: (12_500, [14_585, 25_158, 43_430, 150_000]), + 2021: (12_570, [14_667, 25_296, 43_662, 150_000]), + 2022: (12_570, [14_732, 25_688, 43_662, 150_000]), + 2023: (12_570, [14_732, 25_688, 43_662, 125_140]), + 2024: (12_570, [14_876, 26_561, 43_662, 75_000, 125_140]), + 2025: (12_570, [15_397, 27_491, 43_662, 75_000, 125_140]), + 2026: (12_570, [16_537, 29_526, 43_662, 75_000, 125_140]), +} +# ITA 2007 s. 35(2): the allowance falls by half the income above £100,000. +ALLOWANCE_TAPER_START = 100_000 + +YEARS = sorted(SCOTTISH_RATE_RESOLUTIONS) + + +def resolution_scale(year): + """The marginal rate schedule a resolution sets: thresholds and rates.""" + bands = SCOTTISH_RATE_RESOLUTIONS[year][1] + thresholds = [0] + [limit for _, limit in bands[:-1]] + return thresholds, [rate for rate, _ in bands] @pytest.mark.parametrize( @@ -37,3 +140,148 @@ def test_scottish_announced_threshold_freeze_then_cpi_projection(year): abs=1e-6, ) assert rates.rates == [0.19, 0.20, 0.21, 0.42, 0.45, 0.48] + + +@pytest.mark.parametrize("year", YEARS) +def test_scottish_rates_and_limits_match_each_resolution(year): + """The model year's schedule is the one that year's resolution sets. + + The model reads each tax year's parameters at 30 April, so the year + label 2019 carries the 2019-20 resolution. + """ + thresholds, rates = resolution_scale(year) + scale = system.parameters(year).gov.hmrc.income_tax.rates.scotland.rates + + assert list(scale.thresholds) == pytest.approx(thresholds, abs=0) + assert list(scale.rates) == pytest.approx(rates, abs=0) + + +@pytest.fixture(scope="module") +def statutory_scottish_rates(): + return statutory_parameters().gov.hmrc.income_tax.rates.scotland.rates + + +@pytest.mark.parametrize("year", YEARS) +def test_each_resolution_holds_for_its_whole_tax_year(year, statutory_scottish_rates): + """A resolution applies for the whole of one tax year (SA 1998 s. 80C(3)).""" + thresholds, rates = resolution_scale(year) + for instant in (f"{year}-04-06", f"{year + 1}-04-05"): + scale = statutory_scottish_rates(instant) + assert list(scale.thresholds) == pytest.approx(thresholds, abs=0), instant + assert list(scale.rates) == pytest.approx(rates, abs=0), instant + + +@pytest.mark.parametrize("year", YEARS) +def test_scottish_limits_plus_personal_allowance_match_gov_scot_tables(year): + """The resolution's limits of taxable income are gov.scot's bands less the + standard personal allowance. Above the point where the allowance is + withdrawn in full, taxable income and income are the same.""" + allowance, band_tops = GOV_SCOT_TABLES[year] + parameters = system.parameters(year).gov.hmrc.income_tax + scale = parameters.rates.scotland.rates + assert parameters.allowances.personal_allowance.amount == allowance + + assert len(scale.thresholds) == len(band_tops) + 1 + for limit, top in zip(scale.thresholds[1:], band_tops): + if top <= ALLOWANCE_TAPER_START: + assert limit + allowance == top + else: + assert top >= ALLOWANCE_TAPER_START + 2 * allowance + assert limit == top + + +# Hand-built Scottish taxpayers with pay alone, in every year from 2017-18. +# Each example draws many people, as a calculation costs about the same for +# one person as for many. +PEOPLE = 48 +PROPERTY_SETTINGS = settings( + max_examples=4, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow], +) +# Above £100,000 the draws are even, so the allowance taper is in whole pounds. +pay = st.one_of( + st.integers(0, 300_000), + st.sampled_from( + sorted( + { + top + for allowance, tops in GOV_SCOT_TABLES.values() + for top in [allowance, *tops] + } + | {ALLOWANCE_TAPER_START, 160_000} + ) + ), +).map(lambda amount: amount - amount % 2 if amount > ALLOWANCE_TAPER_START else amount) +pays = st.lists(pay, min_size=PEOPLE // 2, max_size=PEOPLE // 2) +raises = st.lists(st.integers(0, 20_000), min_size=PEOPLE // 2, max_size=PEOPLE // 2) + + +def reference_tax(year, amount): + """Income tax on pay alone, from the resolution and gov.scot's allowance.""" + allowance = max( + 0, GOV_SCOT_TABLES[year][0] - max(0, amount - ALLOWANCE_TAPER_START) / 2 + ) + taxable = max(0, amount - allowance) + thresholds, rates = resolution_scale(year) + tops = thresholds[1:] + [np.inf] + return sum( + rate * max(0, min(taxable, top) - bottom) + for bottom, top, rate in zip(thresholds, tops, rates) + ) + + +@pytest.fixture(scope="module") +def scottish_sim(): + situation = { + "people": { + f"p{i}": { + "age": {year: 40 for year in YEARS}, + "employment_income": {year: 0 for year in YEARS}, + } + for i in range(PEOPLE) + }, + "benunits": {f"b{i}": {"members": [f"p{i}"]} for i in range(PEOPLE)}, + "households": { + f"h{i}": { + "members": [f"p{i}"], + "region": {year: "SCOTLAND" for year in YEARS}, + } + for i in range(PEOPLE) + }, + } + return Simulation(situation=situation) + + +def income_tax_by_year(sim, amounts): + for year in YEARS: + # The simulation moves pay to the source of its labour-supply formula. + sim.set_input("employment_income_before_lsr", year, amounts) + sim.reset_calculations() + for year in YEARS: + np.testing.assert_array_equal(sim.calculate("employment_income", year), amounts) + assert sim.calculate("pays_scottish_income_tax", year).all() + return {year: sim.calculate("income_tax", year).astype(float) for year in YEARS} + + +def tolerance(*amounts): + """A penny plus rounding of the model's float32 monetary values.""" + return 0.01 + 4e-7 * sum(np.abs(amount) for amount in amounts) + + +@PROPERTY_SETTINGS +@given(pays, raises) +def test_scottish_pay_is_taxed_as_each_resolution_sets(scottish_sim, drawn, extra): + """Every year's income tax on pay equals the resolution's bands applied to + pay less the allowance, and it never falls as pay rises.""" + lower = np.array(drawn, dtype=float) + upper = lower + np.array(extra) * 2 + upper = np.where(upper > ALLOWANCE_TAPER_START, upper - upper % 2, upper) + amounts = np.concatenate([lower, upper]) + taxes = income_tax_by_year(scottish_sim, amounts) + for year, tax in taxes.items(): + expected = np.array([reference_tax(year, amount) for amount in amounts]) + assert (np.abs(tax - expected) <= tolerance(tax, expected)).all(), year + below, above = np.split(tax, 2) + assert (above >= below - tolerance(below, above)).all(), year From 2be5a1da2aa6a06149a4a3012954bd067e74ced6 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 01:39:16 -0400 Subject: [PATCH 03/14] Add the changelog fragment for #2783 Co-Authored-By: Claude Opus 5.5 --- changelog.d/2783.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2783.fixed.md diff --git a/changelog.d/2783.fixed.md b/changelog.d/2783.fixed.md new file mode 100644 index 0000000000..cc398f8a6d --- /dev/null +++ b/changelog.d/2783.fixed.md @@ -0,0 +1 @@ +Scottish income tax now uses the rates and limits each year's Scottish rate resolution set for 2018-19 to 2021-22: the 41% higher rate from 2018-19, the £31,580 higher rate limit in 2018-19, the 2019-20 and 2020-21 limits, and the £2,097 and £12,726 limits in 2021-22. From eff166f4674d35ae97c835c0339df3442641f666 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 03:25:45 -0500 Subject: [PATCH 04/14] Name the Scottish starter-rate cases and table comment in active voice Co-Authored-By: Claude Opus 5.5 --- .../finance/tax/income_tax/scottish_rate_resolutions.yaml | 8 ++++---- policyengine_uk/tests/test_scottish_income_tax_rates.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml index a44cbe718a..7f3a6497de 100644 --- a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml @@ -10,7 +10,7 @@ # 2018-19, S5M-10397: 19% to £2,000, 20% to £12,150, 21% to £31,580, # 41% to £150,000, 46% above. -- name: Scottish 2018-19 pay of 13000 is taxed at the starter rate +- name: Scottish 2018-19 pay of 13000 bears only the starter rate period: 2018 absolute_error_margin: 0.01 input: @@ -87,7 +87,7 @@ # 2019-20, S5M-15879: 19% to £2,049, 20% to £12,444, 21% to £30,930, # 41% to £150,000, 46% above. -- name: Scottish 2019-20 pay of 13500 is taxed at the starter rate +- name: Scottish 2019-20 pay of 13500 bears only the starter rate period: 2019 absolute_error_margin: 0.01 input: @@ -189,7 +189,7 @@ # 2020-21, S5M-21090: 19% to £2,085, 20% to £12,658, 21% to £30,930, # 41% to £150,000, 46% above. -- name: Scottish 2020-21 pay of 13500 is taxed at the starter rate +- name: Scottish 2020-21 pay of 13500 bears only the starter rate period: 2020 absolute_error_margin: 0.01 input: @@ -291,7 +291,7 @@ # 2021-22, S5M-24225: 19% to £2,097, 20% to £12,726, 21% to £31,092, # 41% to £150,000, 46% above. -- name: Scottish 2021-22 pay of 13570 is taxed at the starter rate +- name: Scottish 2021-22 pay of 13570 bears only the starter rate period: 2021 absolute_error_margin: 0.01 input: diff --git a/policyengine_uk/tests/test_scottish_income_tax_rates.py b/policyengine_uk/tests/test_scottish_income_tax_rates.py index 60c394e7ed..2ec142aaed 100644 --- a/policyengine_uk/tests/test_scottish_income_tax_rates.py +++ b/policyengine_uk/tests/test_scottish_income_tax_rates.py @@ -10,8 +10,8 @@ # Each year's Scottish rate resolution, restated paragraph by paragraph from # the motion at # https://www.parliament.scot/chamber-and-committees/votes-and-motions/: -# the rate, and the limit of taxable income it is charged up to (None for the -# last rate, which has no limit). The limits are above the personal allowance. +# the rate, and the limit of taxable income where it stops (None for the last +# rate, which has no limit). Taxable income excludes the personal allowance. SCOTTISH_RATE_RESOLUTIONS = { 2017: ("S5M-03912", [(0.20, 31_500), (0.40, 150_000), (0.45, None)]), 2018: ( From 797204f184720d87c966df5e93e0a60cffd59276 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 07:08:42 -0500 Subject: [PATCH 05/14] Test the Marriage Allowance for Scottish couples at the corrected limits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Married Scottish couples in 2018-19, 2019-20 and 2020-21: an earner at the intermediate rate limit can receive the allowance, one pound above it cannot, and pay of £14,000 with savings of £29,500 can. Twin couples who make no election check the tax at each rate, worked by hand from S5M-10397, S5M-15879, S5M-21090 and ITA 2007 ss. 12, 12A, 12B, 55B. The header now cites s. 23 for applying the limits after the allowance. Co-Authored-By: Claude Opus 5.5 --- .../income_tax/scottish_rate_resolutions.yaml | 394 +++++++++++++++++- 1 file changed, 384 insertions(+), 10 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml index 7f3a6497de..3e802d7da5 100644 --- a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml @@ -1,11 +1,14 @@ -# Scottish income tax on pay alone, in the tax years whose rates and limits -# PolicyEngine/policyengine-uk#2783 corrects. Each motion sets the rates and -# limits on taxable income, above the personal allowance: +# Scottish income tax for 2018-19 through 2021-22: pay alone, and married +# couples at the intermediate rate limit. The Scottish Parliament set each +# year's rates and limits by motion: S5M-10397, S5M-15879, S5M-21090 and +# S5M-24225, at # https://www.parliament.scot/chamber-and-committees/votes-and-motions/ -# Personal allowance: £11,850 (2018-19), £12,500 (2019-20 and 2020-21) and -# £12,570 (2021-22), withdrawn by £1 for every £2 of income above £100,000 -# (ITA 2007 s. 35), so it is nil at £160,000. gov.scot's tables for each year -# give the same bands with that allowance added. +# The motions charge each rate on "income" up to a limit. ITA 2007 s. 23 +# deducts the personal allowance at Step 3 and charges the rates at Step 4, so +# the limits apply to income after the allowance. The allowance is £11,850 in +# 2018-19, £12,500 in 2019-20 and 2020-21 and £12,570 in 2021-22; s. 35(2) +# withdraws £1 of it for every £2 of income above £100,000, leaving none at +# £160,000. gov.scot's table for each year adds the allowance to the limits. # 2018-19, S5M-10397: 19% to £2,000, 20% to £12,150, 21% to £31,580, # 41% to £150,000, 46% above. @@ -46,7 +49,7 @@ earned_taxable_income: 18_150 income_tax: 3_670 -- name: Scottish 2018-19 taxable income at the 31580 higher rate limit has no tax at 41 percent +- name: Scottish 2018-19 taxable income at the 31580 intermediate rate limit has no tax at 41 percent period: 2018 absolute_error_margin: 0.01 input: @@ -148,7 +151,7 @@ earned_taxable_income: 22_500 income_tax: 4_580.07 -- name: Scottish 2019-20 taxable income at the 30930 higher rate limit has no tax at 41 percent +- name: Scottish 2019-20 taxable income at the 30930 intermediate rate limit has no tax at 41 percent period: 2019 absolute_error_margin: 0.01 input: @@ -250,7 +253,7 @@ earned_taxable_income: 22_500 income_tax: 4_577.57 -- name: Scottish 2020-21 taxable income at the 30930 higher rate limit has no tax at 41 percent +- name: Scottish 2020-21 taxable income at the 30930 intermediate rate limit has no tax at 41 percent period: 2020 absolute_error_margin: 0.01 input: @@ -377,3 +380,374 @@ # = 6,381.09 + 48,752.28 + 4,600 = 59,733.37. earned_taxable_income: 160_000 income_tax: 59_733.37 + +# Married Scottish couples at the intermediate rate limit in 2018-19 to +# 2020-21. The spouse's £5,000 of pay stays below the allowance left after the +# election (ITA 2007 s. 55C(1)(c)), so the earner can receive the Marriage +# Allowance if they pay tax only at the rates s. 55B(2)(b) lists: the Scottish +# starter, basic and intermediate rates, and the starting, nil and savings +# basic rates for savings (FA 2016 s. 6(15)(a), from 2017-18). The +# transferable amount is 10% of the personal allowance, rounded up to £10 +# (s. 55B(4)(b), (5)). The earner's tax falls by 20% of it after tax is worked +# out at each rate (s. 55A(2), s. 55B(1) and (3), Step 6 of s. 23). +# +# The model takes the transferable amount off the earner's income instead +# (#1947), so its income tax for a claiming couple differs from the law's. +# These cases check the claim and the amount transferred, and check the tax +# at each rate on a twin couple that makes no election. + +# 2018-19, S5M-10397: 21% to £31,580, then 41%. Allowance £11,850, so the +# transferable amount is £1,190 and the spouse keeps £10,660. + +- name: Scottish 2018-19 earner at the 31580 limit can receive the Marriage Allowance + period: 2018 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 43_430 + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 43,430 - 11,850 = 31,580, none of it above the intermediate rate + # limit. Without the election the earner pays 6,490.30, the single + # case above; with it, the law gives 6,490.30 - 1,190 x 20% = 6,252.30. + non_savings_income_after_allowances: [31_580, 0] + tax_band: [INTERMEDIATE, NONE] + meets_marriage_allowance_income_conditions: [true, true] + marriage_allowance: [1_190, 0] + +- name: Scottish 2018-19 earner 1 pound above the 31580 limit cannot receive the Marriage Allowance + period: 2018 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 43_431 + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 31,581 of taxable income puts 1 at the 41% higher rate, which + # s. 55B(2)(b) does not list. 6,490.30 + 1 x 41% = 6,490.71. + tax_band: [HIGHER, NONE] + meets_marriage_allowance_income_conditions: [false, true] + marriage_allowance: [0, 0] + income_tax: [6_490.71, 0] + +# 2019-20, S5M-15879: 19% to £2,049, 20% to £12,444, 21% to £30,930, +# 41% to £150,000, 46% above. Allowance £12,500, so the transferable amount +# is £1,250 and the spouse keeps £11,250. Savings: £5,000 starting rate limit +# (s. 12(3)), £1,000 savings allowance (s. 12B(4)), £37,500 basic rate limit +# (s. 10(5)), 20% savings basic rate. + +- name: Scottish 2019-20 earner at the 30930 limit can receive the Marriage Allowance + period: 2019 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 43_430 + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 43,430 - 12,500 = 30,930, all at or below the intermediate rate limit, + # so none at the 41% higher rate. + non_savings_income_after_allowances: [30_930, 0] + tax_band: [INTERMEDIATE, NONE] + meets_marriage_allowance_income_conditions: [true, true] + marriage_allowance: [1_250, 0] + +- name: Scottish 2019-20 earner at the 30930 limit without the election pays the intermediate rate on the last pound + period: 2019 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 43_430 + would_claim_marriage_allowance: false + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 2,049 x 19% + 10,395 x 20% + 18,486 x 21% + # = 389.31 + 2,079 + 3,882.06 = 6,350.37. + # With the election, the law gives 6,350.37 - 250. + earned_income_tax: [6_350.37, 0] + income_tax: [6_350.37, 0] + marriage_allowance: [0, 0] + +- name: Scottish 2019-20 earner 1 pound above the 30930 limit cannot receive the Marriage Allowance + period: 2019 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 43_431 + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 30,931 of taxable income puts 1 at the 41% higher rate, which + # s. 55B(2)(b) does not list. 6,350.37 + 1 x 41% = 6,350.78. + tax_band: [HIGHER, NONE] + meets_marriage_allowance_income_conditions: [false, true] + marriage_allowance: [0, 0] + income_tax: [6_350.78, 0] + +- name: Scottish 2019-20 earner with pay of 14000 and savings of 29500 can receive the Marriage Allowance + period: 2019 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 14_000 + savings_interest_income: 29_500 + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 1,500 of pay above the allowance bears the starter rate. Savings sit + # on top (s. 16) and take the rest-of-UK bands (s. 11D(6)): 31,000 of + # taxable income stays below the 37,500 basic rate limit, though it + # passes the 30,930 Scottish limit, so nothing bears a higher rate. + non_savings_income_after_allowances: [1_500, 0] + tax_band: [BASIC, NONE] + meets_marriage_allowance_income_conditions: [true, true] + marriage_allowance: [1_250, 0] + +- name: Scottish 2019-20 earner with pay of 14000 and savings of 29500 without the election pays the starter and savings basic rates + period: 2019 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 14_000 + savings_interest_income: 29_500 + would_claim_marriage_allowance: false + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # Pay: 1,500 x 19% = 285. Savings: 5,000 - 1,500 = 3,500 at the 0% + # starting rate (s. 12), 1,000 at the savings nil rate (s. 12A, 12B(4)), + # and 29,500 - 3,500 - 1,000 = 25,000 x 20% = 5,000. + # With the election, the law gives 5,285 - 250 = 5,035. + earned_income_tax: [285, 0] + savings_income_tax: [5_000, 0] + income_tax: [5_285, 0] + marriage_allowance: [0, 0] + +# 2020-21, S5M-21090: 19% to £2,085, 20% to £12,658, 21% to £30,930, +# 41% to £150,000, 46% above. Allowance £12,500, so the transferable amount +# is £1,250 and the spouse keeps £11,250. Savings: £5,000 starting rate limit +# (s. 12(3)), £1,000 savings allowance (s. 12B(4)), £37,500 basic rate limit +# (s. 10(5)), 20% savings basic rate. + +- name: Scottish 2020-21 earner at the 30930 limit can receive the Marriage Allowance + period: 2020 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 43_430 + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 43,430 - 12,500 = 30,930, all at or below the intermediate rate limit, + # so none at the 41% higher rate. + non_savings_income_after_allowances: [30_930, 0] + tax_band: [INTERMEDIATE, NONE] + meets_marriage_allowance_income_conditions: [true, true] + marriage_allowance: [1_250, 0] + +- name: Scottish 2020-21 earner at the 30930 limit without the election pays the intermediate rate on the last pound + period: 2020 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 43_430 + would_claim_marriage_allowance: false + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 2,085 x 19% + 10,573 x 20% + 18,272 x 21% + # = 396.15 + 2,114.60 + 3,837.12 = 6,347.87. + # With the election, the law gives 6,347.87 - 250. + earned_income_tax: [6_347.87, 0] + income_tax: [6_347.87, 0] + marriage_allowance: [0, 0] + +- name: Scottish 2020-21 earner 1 pound above the 30930 limit cannot receive the Marriage Allowance + period: 2020 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 43_431 + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 30,931 of taxable income puts 1 at the 41% higher rate, which + # s. 55B(2)(b) does not list. 6,347.87 + 1 x 41% = 6,348.28. + tax_band: [HIGHER, NONE] + meets_marriage_allowance_income_conditions: [false, true] + marriage_allowance: [0, 0] + income_tax: [6_348.28, 0] + +- name: Scottish 2020-21 earner with pay of 14000 and savings of 29500 can receive the Marriage Allowance + period: 2020 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 14_000 + savings_interest_income: 29_500 + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # 1,500 of pay above the allowance bears the starter rate. Savings sit + # on top (s. 16) and take the rest-of-UK bands (s. 11D(6)): 31,000 of + # taxable income stays below the 37,500 basic rate limit, though it + # passes the 30,930 Scottish limit, so nothing bears a higher rate. + non_savings_income_after_allowances: [1_500, 0] + tax_band: [BASIC, NONE] + meets_marriage_allowance_income_conditions: [true, true] + marriage_allowance: [1_250, 0] + +- name: Scottish 2020-21 earner with pay of 14000 and savings of 29500 without the election pays the starter and savings basic rates + period: 2020 + absolute_error_margin: 0.01 + input: + people: + earner: + age: 40 + employment_income: 14_000 + savings_interest_income: 29_500 + would_claim_marriage_allowance: false + spouse: + age: 40 + employment_income: 5_000 + benunits: + couple: + members: [earner, spouse] + is_married: true + households: + home: + members: [earner, spouse] + region: SCOTLAND + output: + # Pay: 1,500 x 19% = 285. Savings: 5,000 - 1,500 = 3,500 at the 0% + # starting rate (s. 12), 1,000 at the savings nil rate (s. 12A, 12B(4)), + # and 29,500 - 3,500 - 1,000 = 25,000 x 20% = 5,000. + # With the election, the law gives 5,285 - 250 = 5,035. + earned_income_tax: [285, 0] + savings_income_tax: [5_000, 0] + income_tax: [5_285, 0] + marriage_allowance: [0, 0] From 91ca7909772c20b65641c04b9eceb90d09de61bd Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 07:37:46 -0500 Subject: [PATCH 06/14] Check every dated change within each Scottish tax year MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The whole-year test now reads the scale on 6 April, on every date its YAML gives within the tax year, and on 5 April, so a change and its reversal inside one year fail it. A new test checks that no rate or limit takes effect before 6 April 2017, the start of S5M-03912's tax year. The Hypothesis reference rounds the tapered allowance up to a whole pound (ITA 2007 s. 35(3)), so it now draws odd pay above £100,000 too. Co-Authored-By: Claude Opus 5.5 --- .../tests/test_scottish_income_tax_rates.py | 48 +++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/policyengine_uk/tests/test_scottish_income_tax_rates.py b/policyengine_uk/tests/test_scottish_income_tax_rates.py index 2ec142aaed..17a31f4653 100644 --- a/policyengine_uk/tests/test_scottish_income_tax_rates.py +++ b/policyengine_uk/tests/test_scottish_income_tax_rates.py @@ -1,7 +1,10 @@ +import math + import numpy as np import pytest from hypothesis import HealthCheck, given, settings from hypothesis import strategies as st +from policyengine_core.parameters import Parameter from policyengine_uk import Simulation from policyengine_uk.system import system @@ -100,7 +103,7 @@ def resolution_scale(year): - """The marginal rate schedule a resolution sets: thresholds and rates.""" + """Build thresholds and rates from Parliament's schedule for the year.""" bands = SCOTTISH_RATE_RESOLUTIONS[year][1] thresholds = [0] + [limit for _, limit in bands[:-1]] return thresholds, [rate for rate, _ in bands] @@ -161,16 +164,43 @@ def statutory_scottish_rates(): return statutory_parameters().gov.hmrc.income_tax.rates.scotland.rates +def dated_values(scale): + """Every rate and limit the scale's YAML dates, as (date, value) pairs.""" + return [ + (value.instant_str, value.value) + for parameter in scale.get_descendants() + if isinstance(parameter, Parameter) + for value in parameter.values_list + ] + + @pytest.mark.parametrize("year", YEARS) def test_each_resolution_holds_for_its_whole_tax_year(year, statutory_scottish_rates): - """A resolution applies for the whole of one tax year (SA 1998 s. 80C(3)).""" + """A resolution applies for the whole of one tax year (SA 1998 s. 80C(3)), + 6 April to the following 5 April (ITA 2007 s. 4). The scale changes only on + the dates its YAML gives, so read it on 6 April, on every such date within + the year and on 5 April.""" thresholds, rates = resolution_scale(year) - for instant in (f"{year}-04-06", f"{year + 1}-04-05"): + start, end = f"{year}-04-06", f"{year + 1}-04-05" + changes = {date for date, _ in dated_values(statutory_scottish_rates)} + for instant in sorted({start, end} | {d for d in changes if start < d <= end}): scale = statutory_scottish_rates(instant) assert list(scale.thresholds) == pytest.approx(thresholds, abs=0), instant assert list(scale.rates) == pytest.approx(rates, abs=0), instant +def test_scottish_rates_take_effect_on_6_april_2017(statutory_scottish_rates): + """Parliament set the first Scottish rates and limits, S5M-03912, for + 2017-18, which starts on 6 April 2017. The scale dates no rate or limit + earlier.""" + numeric = [ + date + for date, value in dated_values(statutory_scottish_rates) + if value is not None + ] + assert min(numeric) == f"{YEARS[0]}-04-06" + + @pytest.mark.parametrize("year", YEARS) def test_scottish_limits_plus_personal_allowance_match_gov_scot_tables(year): """The resolution's limits of taxable income are gov.scot's bands less the @@ -200,7 +230,6 @@ def test_scottish_limits_plus_personal_allowance_match_gov_scot_tables(year): derandomize=True, suppress_health_check=[HealthCheck.too_slow], ) -# Above £100,000 the draws are even, so the allowance taper is in whole pounds. pay = st.one_of( st.integers(0, 300_000), st.sampled_from( @@ -213,15 +242,19 @@ def test_scottish_limits_plus_personal_allowance_match_gov_scot_tables(year): | {ALLOWANCE_TAPER_START, 160_000} ) ), -).map(lambda amount: amount - amount % 2 if amount > ALLOWANCE_TAPER_START else amount) +) pays = st.lists(pay, min_size=PEOPLE // 2, max_size=PEOPLE // 2) raises = st.lists(st.integers(0, 20_000), min_size=PEOPLE // 2, max_size=PEOPLE // 2) def reference_tax(year, amount): """Income tax on pay alone, from the resolution and gov.scot's allowance.""" + # s. 35(3) rounds the tapered allowance up to a whole pound. allowance = max( - 0, GOV_SCOT_TABLES[year][0] - max(0, amount - ALLOWANCE_TAPER_START) / 2 + 0, + math.ceil( + GOV_SCOT_TABLES[year][0] - max(0, amount - ALLOWANCE_TAPER_START) / 2 + ), ) taxable = max(0, amount - allowance) thresholds, rates = resolution_scale(year) @@ -276,8 +309,7 @@ def test_scottish_pay_is_taxed_as_each_resolution_sets(scottish_sim, drawn, extr """Every year's income tax on pay equals the resolution's bands applied to pay less the allowance, and it never falls as pay rises.""" lower = np.array(drawn, dtype=float) - upper = lower + np.array(extra) * 2 - upper = np.where(upper > ALLOWANCE_TAPER_START, upper - upper % 2, upper) + upper = lower + np.array(extra) amounts = np.concatenate([lower, upper]) taxes = income_tax_by_year(scottish_sim, amounts) for year, tax in taxes.items(): From 98d86957b68bf6a9ed63b138157d06c33a35a7af Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 08:45:11 -0500 Subject: [PATCH 07/14] Say who sets the Scottish rates and what the motions say MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The header now names the Scottish Parliament, quotes the motions' "income", cites ITA 2007 s. 23 for applying the limits after the personal allowance, and keeps the £150,000 and £125,140 tops apart from the gov.scot allowance gloss. The changelog names Parliament's resolutions. Co-Authored-By: Claude Opus 5.5 --- changelog.d/2783.fixed.md | 2 +- .../hmrc/income_tax/rates/scotland/rates.yaml | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/changelog.d/2783.fixed.md b/changelog.d/2783.fixed.md index cc398f8a6d..09a43a987e 100644 --- a/changelog.d/2783.fixed.md +++ b/changelog.d/2783.fixed.md @@ -1 +1 @@ -Scottish income tax now uses the rates and limits each year's Scottish rate resolution set for 2018-19 to 2021-22: the 41% higher rate from 2018-19, the £31,580 higher rate limit in 2018-19, the 2019-20 and 2020-21 limits, and the £2,097 and £12,726 limits in 2021-22. +Corrected Scottish income tax rates and limits for 2018-19 to 2021-22 to match Parliament's annual resolutions, including the 41% higher rate from 2018-19. diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml index 4967126118..18198a8589 100644 --- a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml @@ -1,9 +1,13 @@ description: Rates for Scottish Income Tax. -# Each year's Scottish rate resolution sets these rates and limits for that -# tax year only (Scotland Act 1998 s. 80C(3)). The comment on each dated value -# names the motion and paragraph. The resolutions state the limits as taxable -# income, above the personal allowance, and this file holds them as stated. -# gov.scot's tables add the standard personal allowance to the same limits. +# The Scottish Parliament sets these rates and limits by resolution, for one +# tax year at a time (Scotland Act 1998 s. 80C(3)). Beside each dated value a +# comment cites the motion and paragraph. The motions charge each rate on +# "income" up to a limit, and ITA 2007 s. 23 deducts the personal allowance at +# Step 3 before it charges the rates at Step 4, so this file holds limits of +# income after the allowance. From 2024-25 the motions add that s. 11A +# charges this income "above the personal allowance". gov.scot's tables add +# the standard personal allowance to each limit, except at the £150,000 and +# £125,140 tops, where s. 35(2) leaves no allowance. # The Scottish Budget 2026-27 announces higher, advanced and top threshold # freezes through 2028-29. These future values model announced policy; # Scottish rates and bands are still subject to annual rate resolutions. @@ -12,7 +16,7 @@ description: Rates for Scottish Income Tax. brackets: - threshold: values: - 2017-04-06: null # S5M-03912 sets no starter rate + 2017-04-06: null # Parliament adopted no starter rate in S5M-03912 2018-04-06: 0 # S5M-10397 (a) and paragraph (a) of each later motion 2021-04-06: 0 metadata: @@ -38,7 +42,7 @@ brackets: 2017-04-06: 0.2 # Basic rate: S5M-03912 (a), then paragraph (b) - threshold: values: - 2017-04-06: null # S5M-03912 sets no intermediate rate + 2017-04-06: null # Parliament adopted no intermediate rate in S5M-03912 2018-04-06: 12_150 # S5M-10397 (b) 2019-04-06: 12_444 # S5M-15879 (b) 2020-04-06: 12_658 # S5M-21090 (b) From ccb90665b0b5709c8ebab72a92435fe1400c8bfa Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 08:46:04 -0500 Subject: [PATCH 08/14] Verify Scottish income tax from 2017-18 The rates, limits and dates now match every resolution from S5M-03912 for 2017-18, which the rate tests and the 2017-18 tax band and Marriage Allowance cases check. The model holds no separate 2016-17 Scottish rates. Co-Authored-By: Claude Opus 5.5 --- policyengine_uk/programs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policyengine_uk/programs.yaml b/policyengine_uk/programs.yaml index c1a8bd6c76..d9710be65e 100644 --- a/policyengine_uk/programs.yaml +++ b/policyengine_uk/programs.yaml @@ -671,7 +671,7 @@ programs: agency: Revenue Scotland status: complete coverage: Scotland - verified_start_year: 2019 + verified_start_year: 2017 notes: Devolved tax bands applied via income tax system - id: lbtt From 22adb2ed1a3e2c6453e97aa1cc20cd6958eefca8 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 09:57:39 -0500 Subject: [PATCH 09/14] Name who acts in the couple notes and the first-date test The YAML notes now say which sections set the transferable amount and give the tax reduction, and the first-date docstring states only what the scale holds. Co-Authored-By: Claude Opus 5.5 --- .../income_tax/scottish_rate_resolutions.yaml | 21 ++++++++++--------- .../tests/test_scottish_income_tax_rates.py | 6 +++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml index 3e802d7da5..24f47cd9b5 100644 --- a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml @@ -386,18 +386,19 @@ # election (ITA 2007 s. 55C(1)(c)), so the earner can receive the Marriage # Allowance if they pay tax only at the rates s. 55B(2)(b) lists: the Scottish # starter, basic and intermediate rates, and the starting, nil and savings -# basic rates for savings (FA 2016 s. 6(15)(a), from 2017-18). The -# transferable amount is 10% of the personal allowance, rounded up to £10 -# (s. 55B(4)(b), (5)). The earner's tax falls by 20% of it after tax is worked -# out at each rate (s. 55A(2), s. 55B(1) and (3), Step 6 of s. 23). +# basic rates for savings (FA 2016 s. 6(15)(a), from 2017-18). s. 55B(4)(b) +# and (5) set the transferable amount at 10% of the personal allowance, +# rounded up to £10. s. 55B(1) and (3) give the earner a tax reduction of 20% +# of it, which s. 55A(2) applies at Step 6 of s. 23, after Step 4 charges tax +# at each rate. # # The model takes the transferable amount off the earner's income instead # (#1947), so its income tax for a claiming couple differs from the law's. # These cases check the claim and the amount transferred, and check the tax # at each rate on a twin couple that makes no election. -# 2018-19, S5M-10397: 21% to £31,580, then 41%. Allowance £11,850, so the -# transferable amount is £1,190 and the spouse keeps £10,660. +# 2018-19, S5M-10397: 21% to £31,580, then 41%. Allowance £11,850: the +# spouse transfers £1,190 and keeps £10,660. - name: Scottish 2018-19 earner at the 31580 limit can receive the Marriage Allowance period: 2018 @@ -455,8 +456,8 @@ income_tax: [6_490.71, 0] # 2019-20, S5M-15879: 19% to £2,049, 20% to £12,444, 21% to £30,930, -# 41% to £150,000, 46% above. Allowance £12,500, so the transferable amount -# is £1,250 and the spouse keeps £11,250. Savings: £5,000 starting rate limit +# 41% to £150,000, 46% above. Allowance £12,500: the spouse transfers £1,250 +# and keeps £11,250. Savings: £5,000 starting rate limit # (s. 12(3)), £1,000 savings allowance (s. 12B(4)), £37,500 basic rate limit # (s. 10(5)), 20% savings basic rate. @@ -604,8 +605,8 @@ marriage_allowance: [0, 0] # 2020-21, S5M-21090: 19% to £2,085, 20% to £12,658, 21% to £30,930, -# 41% to £150,000, 46% above. Allowance £12,500, so the transferable amount -# is £1,250 and the spouse keeps £11,250. Savings: £5,000 starting rate limit +# 41% to £150,000, 46% above. Allowance £12,500: the spouse transfers £1,250 +# and keeps £11,250. Savings: £5,000 starting rate limit # (s. 12(3)), £1,000 savings allowance (s. 12B(4)), £37,500 basic rate limit # (s. 10(5)), 20% savings basic rate. diff --git a/policyengine_uk/tests/test_scottish_income_tax_rates.py b/policyengine_uk/tests/test_scottish_income_tax_rates.py index 17a31f4653..5d9af153a5 100644 --- a/policyengine_uk/tests/test_scottish_income_tax_rates.py +++ b/policyengine_uk/tests/test_scottish_income_tax_rates.py @@ -190,9 +190,9 @@ def test_each_resolution_holds_for_its_whole_tax_year(year, statutory_scottish_r def test_scottish_rates_take_effect_on_6_april_2017(statutory_scottish_rates): - """Parliament set the first Scottish rates and limits, S5M-03912, for - 2017-18, which starts on 6 April 2017. The scale dates no rate or limit - earlier.""" + """The scale starts with S5M-03912, Parliament's resolution for 2017-18, + and that tax year starts on 6 April 2017 (ITA 2007 s. 4(3)). The scale + dates no rate or limit earlier.""" numeric = [ date for date, value in dated_values(statutory_scottish_rates) From 9aa5ee4c9f3319eaa1eaa579ffdca8f69e70ae36 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 1 Nov 2026 10:50:23 -0500 Subject: [PATCH 10/14] Give Parliament the verbs in the Scottish notes The YAML headers and two test docstrings now name who acts: Parliament charges the rates, s. 35(1) sets the allowance and gov.scot adds it to each limit. Comments and docstrings only. Co-Authored-By: Claude Opus 5.5 --- .../gov/hmrc/income_tax/rates/scotland/rates.yaml | 14 +++++++------- .../tax/income_tax/scottish_rate_resolutions.yaml | 13 +++++++------ .../tests/test_scottish_income_tax_rates.py | 8 ++++---- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml index 18198a8589..ab239b7b2b 100644 --- a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml @@ -1,13 +1,13 @@ description: Rates for Scottish Income Tax. # The Scottish Parliament sets these rates and limits by resolution, for one # tax year at a time (Scotland Act 1998 s. 80C(3)). Beside each dated value a -# comment cites the motion and paragraph. The motions charge each rate on -# "income" up to a limit, and ITA 2007 s. 23 deducts the personal allowance at -# Step 3 before it charges the rates at Step 4, so this file holds limits of -# income after the allowance. From 2024-25 the motions add that s. 11A -# charges this income "above the personal allowance". gov.scot's tables add -# the standard personal allowance to each limit, except at the £150,000 and -# £125,140 tops, where s. 35(2) leaves no allowance. +# comment cites the motion and paragraph. In the motions Parliament charges +# each rate on "income" up to a limit, and ITA 2007 s. 23 deducts the personal +# allowance at Step 3 before it charges the rates at Step 4, so this file holds +# limits of income after the allowance. From 2024-25 Parliament adds in the +# motions that s. 11A charges this income "above the personal allowance". +# gov.scot's tables add the standard personal allowance to each limit, except +# at the £150,000 and £125,140 tops, where s. 35(2) leaves no allowance. # The Scottish Budget 2026-27 announces higher, advanced and top threshold # freezes through 2028-29. These future values model announced policy; # Scottish rates and bands are still subject to annual rate resolutions. diff --git a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml index 24f47cd9b5..31256743a6 100644 --- a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml @@ -3,12 +3,13 @@ # year's rates and limits by motion: S5M-10397, S5M-15879, S5M-21090 and # S5M-24225, at # https://www.parliament.scot/chamber-and-committees/votes-and-motions/ -# The motions charge each rate on "income" up to a limit. ITA 2007 s. 23 -# deducts the personal allowance at Step 3 and charges the rates at Step 4, so -# the limits apply to income after the allowance. The allowance is £11,850 in -# 2018-19, £12,500 in 2019-20 and 2020-21 and £12,570 in 2021-22; s. 35(2) -# withdraws £1 of it for every £2 of income above £100,000, leaving none at -# £160,000. gov.scot's table for each year adds the allowance to the limits. +# In the motions Parliament charges each rate on "income" up to a limit. ITA +# 2007 s. 23 deducts the personal allowance at Step 3 and charges the rates at +# Step 4, so the limits apply to income after the allowance. s. 35(1) sets the +# allowance at £11,850 in 2018-19, £12,500 in 2019-20 and 2020-21 and £12,570 +# in 2021-22; s. 35(2) withdraws £1 of it for every £2 of income above +# £100,000, leaving none at £160,000. gov.scot's table for each year adds the +# allowance to the limits. # 2018-19, S5M-10397: 19% to £2,000, 20% to £12,150, 21% to £31,580, # 41% to £150,000, 46% above. diff --git a/policyengine_uk/tests/test_scottish_income_tax_rates.py b/policyengine_uk/tests/test_scottish_income_tax_rates.py index 5d9af153a5..7d7966730f 100644 --- a/policyengine_uk/tests/test_scottish_income_tax_rates.py +++ b/policyengine_uk/tests/test_scottish_income_tax_rates.py @@ -147,7 +147,7 @@ def test_scottish_announced_threshold_freeze_then_cpi_projection(year): @pytest.mark.parametrize("year", YEARS) def test_scottish_rates_and_limits_match_each_resolution(year): - """The model year's schedule is the one that year's resolution sets. + """Each model year carries the schedule its year's resolution sets. The model reads each tax year's parameters at 30 April, so the year label 2019 carries the 2019-20 resolution. @@ -203,9 +203,9 @@ def test_scottish_rates_take_effect_on_6_april_2017(statutory_scottish_rates): @pytest.mark.parametrize("year", YEARS) def test_scottish_limits_plus_personal_allowance_match_gov_scot_tables(year): - """The resolution's limits of taxable income are gov.scot's bands less the - standard personal allowance. Above the point where the allowance is - withdrawn in full, taxable income and income are the same.""" + """gov.scot adds the standard personal allowance to each limit of taxable + income in its table. Above the point where s. 35(2) withdraws the + allowance in full, taxable income equals income.""" allowance, band_tops = GOV_SCOT_TABLES[year] parameters = system.parameters(year).gov.hmrc.income_tax scale = parameters.rates.scotland.rates From 9f2863f4573735df82847c341db8d590d510d448 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 19:05:00 +0000 Subject: [PATCH 11/14] Name the actors in the Scottish rate comments and qualify the gov.scot top limit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LwQq6GUMZ7gG6HM75shUVi --- .../hmrc/income_tax/rates/scotland/rates.yaml | 21 +++++++++++-------- .../income_tax/scottish_rate_resolutions.yaml | 5 +++-- .../tests/test_scottish_income_tax_rates.py | 19 +++++++++-------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml index ab239b7b2b..12c9da61e6 100644 --- a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml @@ -8,11 +8,11 @@ description: Rates for Scottish Income Tax. # motions that s. 11A charges this income "above the personal allowance". # gov.scot's tables add the standard personal allowance to each limit, except # at the £150,000 and £125,140 tops, where s. 35(2) leaves no allowance. -# The Scottish Budget 2026-27 announces higher, advanced and top threshold -# freezes through 2028-29. These future values model announced policy; -# Scottish rates and bands are still subject to annual rate resolutions. -# CPI uprating after 2028-29 is the existing model projection, not a Budget -# commitment to subsequent indexation. +# The Scottish Government announced higher, advanced and top threshold +# freezes through 2028-29 in the Scottish Budget 2026-27. Parliament sets +# Scottish rates and bands by annual resolutions. The model projects CPI +# uprating after 2028-29; the government has made no commitment to subsequent +# indexation. brackets: - threshold: values: @@ -68,7 +68,8 @@ brackets: 2023-04-06: 31_092 # S6M-07853 (c) 2024-04-06: 31_092 # S6M-12252 (c) 2025-04-06: 31_092 # S6M-16531 (c) - # Scottish Budget 2026-27 announced freeze through 2028-29. + # The Scottish Government announced this freeze through 2028-29 in + # the Scottish Budget 2026-27. 2026-04-06: 31_092 # S6M-20844 (c) 2027-04-06: 31_092 2028-04-06: 31_092 @@ -89,7 +90,8 @@ brackets: 2023-04-06: 125_140 # S6M-07853 (d) 2024-04-06: 62_430 # S6M-12252 (d) 2025-04-06: 62_430 # S6M-16531 (d) - # Scottish Budget 2026-27 announced freeze through 2028-29. + # The Scottish Government announced this freeze through 2028-29 in + # the Scottish Budget 2026-27. 2026-04-06: 62_430 # S6M-20844 (d) 2027-04-06: 62_430 2028-04-06: 62_430 @@ -103,8 +105,9 @@ brackets: - threshold: values: 2017-04-06: null - # The personal allowance is fully withdrawn at £125,140, so the - # taxable-income top limit equals total income: do not subtract PA. + # At income of £125,140, no personal allowance remains under + # s. 35(2), so the taxable-income top limit equals total income: do + # not subtract PA. 2024-04-06: 125_140 # S6M-12252 (e) 2025-04-06: 125_140 # S6M-16531 (e) 2026-04-06: 125_140 # S6M-20844 (e) diff --git a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml index 31256743a6..9c148fc2b8 100644 --- a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml @@ -8,8 +8,9 @@ # Step 4, so the limits apply to income after the allowance. s. 35(1) sets the # allowance at £11,850 in 2018-19, £12,500 in 2019-20 and 2020-21 and £12,570 # in 2021-22; s. 35(2) withdraws £1 of it for every £2 of income above -# £100,000, leaving none at £160,000. gov.scot's table for each year adds the -# allowance to the limits. +# £100,000, leaving none at £160,000. gov.scot adds the standard allowance to +# the lower limits. At the £150,000 top, s. 35(2) leaves no allowance, so +# gov.scot's figure equals the limit. # 2018-19, S5M-10397: 19% to £2,000, 20% to £12,150, 21% to £31,580, # 41% to £150,000, 46% above. diff --git a/policyengine_uk/tests/test_scottish_income_tax_rates.py b/policyengine_uk/tests/test_scottish_income_tax_rates.py index 7d7966730f..eae0a2498b 100644 --- a/policyengine_uk/tests/test_scottish_income_tax_rates.py +++ b/policyengine_uk/tests/test_scottish_income_tax_rates.py @@ -10,11 +10,11 @@ from policyengine_uk.system import system from policyengine_uk.tax_benefit_system import statutory_parameters -# Each year's Scottish rate resolution, restated paragraph by paragraph from -# the motion at -# https://www.parliament.scot/chamber-and-committees/votes-and-motions/: -# the rate, and the limit of taxable income where it stops (None for the last -# rate, which has no limit). Taxable income excludes the personal allowance. +# We transcribe the Scottish Parliament's annual rates and limits paragraph by +# paragraph from each motion at +# https://www.parliament.scot/chamber-and-committees/votes-and-motions/. +# Each pair gives the rate and the upper taxable-income limit; `None` marks the +# final rate. Taxable income excludes the personal allowance. SCOTTISH_RATE_RESOLUTIONS = { 2017: ("S5M-03912", [(0.20, 31_500), (0.40, 150_000), (0.45, None)]), 2018: ( @@ -126,9 +126,10 @@ def test_scottish_income_tax_thresholds_match_the_resolution(year, thresholds): @pytest.mark.parametrize("year", [2026, 2027, 2028, 2029, 2030]) def test_scottish_announced_threshold_freeze_then_cpi_projection(year): - # Scottish Budget 2026-27, Income Tax Policy: the higher, advanced and - # top cash thresholds stay fixed through 2028-29. Future CPI uprating - # is the model's existing projection, not a Budget commitment. + # The Scottish Government announced fixed higher, advanced and top cash + # thresholds through 2028-29 in the Scottish Budget 2026-27. The model + # projects CPI uprating afterwards; the government has made no commitment + # to it. # https://www.gov.scot/publications/scottish-budget-2026-2027/pages/4/ rates = system.parameters.gov.hmrc.income_tax.rates.scotland.rates(year) cpi = system.parameters.gov.economic_assumptions.indices.obr.consumer_price_index @@ -147,7 +148,7 @@ def test_scottish_announced_threshold_freeze_then_cpi_projection(year): @pytest.mark.parametrize("year", YEARS) def test_scottish_rates_and_limits_match_each_resolution(year): - """Each model year carries the schedule its year's resolution sets. + """Check each model year against the schedule the Scottish Parliament set for that year. The model reads each tax year's parameters at 30 April, so the year label 2019 carries the 2019-20 resolution. From 4bae9d1dfe2416c88cd753d9ad4c17df127a20ea Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 2 Nov 2026 15:00:27 -0500 Subject: [PATCH 12/14] Name the Scottish Government and the taxpayer as actors in the rate comments The gov.scot tables, ITA 2007 s. 23 and s. 35 no longer act in the comments of rates.yaml and scottish_rate_resolutions.yaml, and the test's resolutions comment no longer describes how the data was produced. Comments only: the YAML data and the Python AST are unchanged. Co-Authored-By: Claude Opus 5.5 --- .../hmrc/income_tax/rates/scotland/rates.yaml | 14 ++++++++------ .../income_tax/scottish_rate_resolutions.yaml | 17 +++++++++-------- .../tests/test_scottish_income_tax_rates.py | 4 ++-- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml index 12c9da61e6..09df4d2f2f 100644 --- a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/rates.yaml @@ -2,12 +2,14 @@ description: Rates for Scottish Income Tax. # The Scottish Parliament sets these rates and limits by resolution, for one # tax year at a time (Scotland Act 1998 s. 80C(3)). Beside each dated value a # comment cites the motion and paragraph. In the motions Parliament charges -# each rate on "income" up to a limit, and ITA 2007 s. 23 deducts the personal -# allowance at Step 3 before it charges the rates at Step 4, so this file holds -# limits of income after the allowance. From 2024-25 Parliament adds in the -# motions that s. 11A charges this income "above the personal allowance". -# gov.scot's tables add the standard personal allowance to each limit, except -# at the £150,000 and £125,140 tops, where s. 35(2) leaves no allowance. +# each rate on "income" up to a limit. The taxpayer deducts the personal +# allowance at Step 3 and works out the tax at Step 4 on the income that +# remains (ITA 2007 s. 23), so this file holds limits of income after the +# allowance. From 2024-25 Parliament adds in the motions that s. 11A charges +# this income "above the personal allowance". +# The Scottish Government adds the standard personal allowance to each limit +# in its tables (gov.scot), except at the £150,000 and £125,140 tops, where no +# allowance remains (s. 35(2)). # The Scottish Government announced higher, advanced and top threshold # freezes through 2028-29 in the Scottish Budget 2026-27. Parliament sets # Scottish rates and bands by annual resolutions. The model projects CPI diff --git a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml index 9c148fc2b8..62eea9398a 100644 --- a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml @@ -3,14 +3,15 @@ # year's rates and limits by motion: S5M-10397, S5M-15879, S5M-21090 and # S5M-24225, at # https://www.parliament.scot/chamber-and-committees/votes-and-motions/ -# In the motions Parliament charges each rate on "income" up to a limit. ITA -# 2007 s. 23 deducts the personal allowance at Step 3 and charges the rates at -# Step 4, so the limits apply to income after the allowance. s. 35(1) sets the -# allowance at £11,850 in 2018-19, £12,500 in 2019-20 and 2020-21 and £12,570 -# in 2021-22; s. 35(2) withdraws £1 of it for every £2 of income above -# £100,000, leaving none at £160,000. gov.scot adds the standard allowance to -# the lower limits. At the £150,000 top, s. 35(2) leaves no allowance, so -# gov.scot's figure equals the limit. +# In the motions Parliament charges each rate on "income" up to a limit. The +# taxpayer deducts the personal allowance at Step 3 and works out the tax at +# Step 4 on the income that remains (ITA 2007 s. 23), so the limits apply to +# income after the allowance. The allowance was £11,850 in 2018-19, £12,500 in +# 2019-20 and 2020-21 and £12,570 in 2021-22 (s. 35(1)). It falls by £1 for +# every £2 of income above £100,000, leaving none at £160,000 (s. 35(2)). The +# Scottish Government adds the standard allowance to the lower limits in its +# tables (gov.scot). No allowance remains at the £150,000 top (s. 35(2)), so +# its tables give the limit itself. # 2018-19, S5M-10397: 19% to £2,000, 20% to £12,150, 21% to £31,580, # 41% to £150,000, 46% above. diff --git a/policyengine_uk/tests/test_scottish_income_tax_rates.py b/policyengine_uk/tests/test_scottish_income_tax_rates.py index eae0a2498b..b349fb7fb2 100644 --- a/policyengine_uk/tests/test_scottish_income_tax_rates.py +++ b/policyengine_uk/tests/test_scottish_income_tax_rates.py @@ -10,8 +10,8 @@ from policyengine_uk.system import system from policyengine_uk.tax_benefit_system import statutory_parameters -# We transcribe the Scottish Parliament's annual rates and limits paragraph by -# paragraph from each motion at +# The Scottish Parliament's rates and limits for each year, paragraph by +# paragraph, from each motion at # https://www.parliament.scot/chamber-and-committees/votes-and-motions/. # Each pair gives the rate and the upper taxable-income limit; `None` marks the # final rate. Taxable income excludes the personal allowance. From e70a40a555686fe2053d3ff0e8b8b5bb891df5a6 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 9 Nov 2026 20:00:09 -0500 Subject: [PATCH 13/14] Check the claiming couples' Step 6 reduction and income tax Main now gives the Marriage Allowance as a Step 6 tax reduction, so the five claiming cases also check the reduction and the earner's income tax against the hand-worked law, and the comment no longer describes the old subtraction from income. Co-Authored-By: Claude Opus 5.5 --- .../income_tax/scottish_rate_resolutions.yaml | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml index 62eea9398a..79a9874b3a 100644 --- a/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/tax/income_tax/scottish_rate_resolutions.yaml @@ -395,10 +395,9 @@ # of it, which s. 55A(2) applies at Step 6 of s. 23, after Step 4 charges tax # at each rate. # -# The model takes the transferable amount off the earner's income instead -# (#1947), so its income tax for a claiming couple differs from the law's. -# These cases check the claim and the amount transferred, and check the tax -# at each rate on a twin couple that makes no election. +# These cases check the claim, the amount transferred, the reduction and the +# earner's income tax, and check the tax at each rate on a twin couple that +# makes no election. # 2018-19, S5M-10397: 21% to £31,580, then 41%. Allowance £11,850: the # spouse transfers £1,190 and keeps £10,660. @@ -430,6 +429,8 @@ tax_band: [INTERMEDIATE, NONE] meets_marriage_allowance_income_conditions: [true, true] marriage_allowance: [1_190, 0] + marriage_allowance_tax_reduction: [238, 0] + income_tax: [6_252.30, 0] - name: Scottish 2018-19 earner 1 pound above the 31580 limit cannot receive the Marriage Allowance period: 2018 @@ -485,11 +486,14 @@ region: SCOTLAND output: # 43,430 - 12,500 = 30,930, all at or below the intermediate rate limit, - # so none at the 41% higher rate. + # so none at the 41% higher rate. Without the election the earner pays + # 6,350.37, the next case; with it, 6,350.37 - 1,250 x 20% = 6,100.37. non_savings_income_after_allowances: [30_930, 0] tax_band: [INTERMEDIATE, NONE] meets_marriage_allowance_income_conditions: [true, true] marriage_allowance: [1_250, 0] + marriage_allowance_tax_reduction: [250, 0] + income_tax: [6_100.37, 0] - name: Scottish 2019-20 earner at the 30930 limit without the election pays the intermediate rate on the last pound period: 2019 @@ -571,10 +575,14 @@ # on top (s. 16) and take the rest-of-UK bands (s. 11D(6)): 31,000 of # taxable income stays below the 37,500 basic rate limit, though it # passes the 30,930 Scottish limit, so nothing bears a higher rate. + # Without the election the earner pays 5,285, the next case; with it, + # 5,285 - 1,250 x 20% = 5,035. non_savings_income_after_allowances: [1_500, 0] tax_band: [BASIC, NONE] meets_marriage_allowance_income_conditions: [true, true] marriage_allowance: [1_250, 0] + marriage_allowance_tax_reduction: [250, 0] + income_tax: [5_035, 0] - name: Scottish 2019-20 earner with pay of 14000 and savings of 29500 without the election pays the starter and savings basic rates period: 2019 @@ -634,11 +642,14 @@ region: SCOTLAND output: # 43,430 - 12,500 = 30,930, all at or below the intermediate rate limit, - # so none at the 41% higher rate. + # so none at the 41% higher rate. Without the election the earner pays + # 6,347.87, the next case; with it, 6,347.87 - 1,250 x 20% = 6,097.87. non_savings_income_after_allowances: [30_930, 0] tax_band: [INTERMEDIATE, NONE] meets_marriage_allowance_income_conditions: [true, true] marriage_allowance: [1_250, 0] + marriage_allowance_tax_reduction: [250, 0] + income_tax: [6_097.87, 0] - name: Scottish 2020-21 earner at the 30930 limit without the election pays the intermediate rate on the last pound period: 2020 @@ -720,10 +731,14 @@ # on top (s. 16) and take the rest-of-UK bands (s. 11D(6)): 31,000 of # taxable income stays below the 37,500 basic rate limit, though it # passes the 30,930 Scottish limit, so nothing bears a higher rate. + # Without the election the earner pays 5,285, the next case; with it, + # 5,285 - 1,250 x 20% = 5,035. non_savings_income_after_allowances: [1_500, 0] tax_band: [BASIC, NONE] meets_marriage_allowance_income_conditions: [true, true] marriage_allowance: [1_250, 0] + marriage_allowance_tax_reduction: [250, 0] + income_tax: [5_035, 0] - name: Scottish 2020-21 earner with pay of 14000 and savings of 29500 without the election pays the starter and savings basic rates period: 2020 From c1d55699d962994f54fef4ccb9fb436d11b47e3a Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 9 Nov 2026 22:14:09 -0500 Subject: [PATCH 14/14] Pin 2019-20's Scottish limits in the pensioner CTR snapshot test_matches_origin_main_on_unchanged_households compares 23 households with values computed on main at 9dd44e142, which used 2018-19's Scottish starter and basic rate limits (2,000 and 12,150) in 2019-20. At S5M-15879's 2,049 and 12,444, the snapshot's three Scottish taxpayers pay 0.49, 0.49 and 3.43 less tax. Their applicable income rises by those amounts, and their awards fall by 20% of each. Set those three rows to the new values and rewrite the notes beside them. Co-Authored-By: Claude Opus 5.5 --- ...on_pensioner_children_tariff_properties.py | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/policyengine_uk/tests/test_council_tax_reduction_pensioner_children_tariff_properties.py b/policyengine_uk/tests/test_council_tax_reduction_pensioner_children_tariff_properties.py index fcfd1a8dff..338bb6133c 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_pensioner_children_tariff_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_pensioner_children_tariff_properties.py @@ -350,6 +350,9 @@ def test_northern_ireland_gets_no_new_amounts(): # tariff income, over the personal allowance and child amounts. For example, the # Welsh family with savings of 8,000 in 2026 has 9,000 - 5 * 52 + 416 = 9,156 # against 101.85 * 52 = 5,296.20, so an award of 1,228.04. +# +# Three 2019 Scottish rows use 2019-20's Scottish limits, which main lacked; +# the notes beside them give the arithmetic. ORIGIN_MAIN = { 2019: [ (9_412, 12_000, 1_482.4), @@ -359,15 +362,22 @@ def test_northern_ireland_gets_no_new_amounts(): (5_972.2, 22_574.64, 0), (3_801.2, 8_955.84, 0), (9_412, 12_000, 1_482.4), - (14_071.2, 17_170, 1_380.24), + # Scottish taxpayers pay 19% on the first 2,049 of taxable income in + # 2019-20 and 20% up to 12,444 (S5M-15879), where main used 2018-19's + # 2,000 and 12,150. This couple's 5,500 of taxable income pays 19% + # rather than 20% on 49 more, so the tax falls by 0.49 and the award + # by 20% of that. + (14_071.2, 17_170.49, 1_380.14), (9_412, 9_592.34, 1_963.93), - (3_801.2, 16_080.24, 889.22), + # The same 0.49 on this parent's 2,500 of taxable income. + (3_801.2, 16_080.73, 889.13), # The Scottish couple on 25,000 of pay. The Marriage Allowance comes # off the tax at Step 6, so taxable income stays 12,500 and its last - # 350 reach the 21% band from 12,150: 380 + 2,030 + 73.50 - 250 = - # 2,233.50 of tax. With the allowance off taxable income the tax was - # 2,230, so income falls by 3.50 and the award rises by 20% of that. - (5_972.2, 24_671.14, 461.48), + # 56 reach the 21% band from 12,444: 389.31 + 2,079 + 11.76 - 250 = + # 2,230.07 of tax. At 2018-19's limits the tax was 2,233.50, so income + # rises by 3.43 and the award falls by 20% of that. With the allowance + # off taxable income the tax would be 2,229.51. + (5_972.2, 24_674.57, 460.79), (3_801.2, 9_371.84, 937.87), (9_412, 12_000, 1_482.4), (14_071.2, 17_150, 1_384.24),