Repository navigation
Model the ISA subscription limits, with per-person ISA subscriptions and balances - #2712
Conversation
Add gov.hmrc.isa.annual_subscription_limit (£20,000, reg 4ZA(1)), gov.hmrc.isa.cash.subscription_limit (no limit of its own until 6 April 2027, then £12,000 under reg 4ZA(1ZA)) and gov.hmrc.isa.cash.full_limit_age (65 at the end of the tax year, from the date of birth). Add per-person cash_isa_subscriptions and stocks_and_shares_isa_subscriptions inputs, isa_subscriptions (with lifetime_isa_payments), the person's cash_isa_subscription_limit, and cash_isa_subscriptions_above_limit and isa_subscriptions_above_limit. Inputs are not capped, so data collected under a higher limit shows what a lower one leaves out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gov.contrib.behavioral_responses.cash_isa_excess splits cash ISA subscriptions above the person's cash limit between stocks-and-shares ISAs (within the room the annual limit leaves), taxable savings and other uses, with an interest rate for the taxable part (default: Bank of England effective rate on individuals' outstanding time deposits, June 2026). Both shares default to zero, so no result moves until a reform sets them. cash_isa_excess_savings_interest enters taxable_savings_interest_income and not income: the interest is earned either way, so a cash limit changes tax, not gross income. Shares that are negative or sum above one raise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add person inputs cash_isa_balance and stocks_and_shares_isa_balance, uprated with savings and corporate_wealth, and make the household cash_isa and stocks_and_shares_isa their sums, as household_lifetime_isa_balance sums lifetime_isa_balance. The household totals stay in uprating_indices.yaml, so datasets that store only the totals keep them, projected as before, until Microcosm exports the person balances. Core does not combine a sum with uprating, so a household total given in a situation for one year no longer carries into later years; the person balances carry the uprating instead. test_wealth_components now checks the class uprating on the summed inputs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ISA assumptions page gains a subscription limits section (inputs, the age test, the two excesses and how a reform scores, the opt-in response and its static-model limits) and describes the per-person balances under capital stocks. The dataset-sources guide tells producers how to export the balances and subscriptions; the growth factor list names the new balances. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Budget 2026 retains the £20,000 cash ISA limit from April 2027 (OOTLAR para 2.5, legislation in November 2026), so gov.hmrc.isa.cash.subscription_limit no longer steps to £12,000. SI 2026/1018 reg 6's limit for people 64 or under becomes a reform setting, kept as a lever with the full-limit age; the limit tests run it as one. Section 4 of #2710 is decided as option (b): the model reports the amounts above each limit and no more. Remove the opt-in gov.contrib.behavioral_responses.cash_isa_excess block, its three variables and tests, and its term in taxable_savings_interest_income. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SI 2026/1130 substitutes Schedule paragraph 5 and inserts paragraph 6A: from 29 October 2026, a withdrawal that would be a first-time residential purchase but for the £450,000 price cap in paragraph 6(3) pays 20%, and other withdrawals that are not exempt still pay 25%. Add gov.hmrc.isa.lifetime.above_cap_purchase (in_effect from 29 October 2026, withdrawal_charge 0.2). lifetime_isa_withdrawal_charge charges the home payment of such a purchase at that rate and the rest at withdrawal_charge. Parameters are read on 30 April, so the model applies the rate from fiscal 2027-28; the parameter documentation says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The subscription limits section now says cash has no limit of its own, with £12,000 as a reform setting, and that the model reports the amounts above each limit and no more, without the opt-in response. The Lifetime ISA section describes the 20% charge above the price cap and its fiscal-year timing, the coverage note names the First Time Buyer ISA, and the dataset-sources guide points producers to microcosm#1415. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aggregate impact on certified data: passBase Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 0 (thresholds in Notes
Moves flagged for reviewNone. Spending by benefit and service
Caseloads
Standard reform costings (change in gov_balance)
Standard reforms: change in each reform's target
Household net income by decileNo household's net income changes in any year. No change in any year: receipts by tax head; government balance, each component counted once; model totals; household income totals; population; poverty rates; people in poverty; inequality; mean household net income in each side's own deciles. Checks failing on both base and head (1)
Counted-once checkEach of 91 components was raised by £1 per unit in 2026-27, and every head of its totals was read household by household: its own head must rise by exactly £1, no other tax head may move, no other benefit may rise, and the model's own total must move by what its heads moved. A head that breaks a rule is measured again twice: with every other head held at its baseline value, and with every other head held at its value after the first £1 while the component rises again. It fails where either still shows the response. 0 failed; 0 were skipped.
Provenance
Dataset: Receipts by tax head: head levels
Spending by benefit and service: head levels
Caseloads: head levels
Government balance, each component counted once: head levels
Model totals: head levels
Household income totals: head levels
Population: head levels
Poverty rates: head levels
People in poverty: head levels
Inequality: head levels
Mean household net income in each side's own deciles: head levels
Standard reform costings (change in gov_balance): head levels
Standard reforms: change in each reform's target: head levels
|
Vahid's review of microcosm#1415 (finding 5): cash, stocks-and-shares and Lifetime ISA subscriptions share the £20,000 annual limit, and HMRC's Table 9.7 leaves Lifetime ISAs out. The dataset-sources guide now asks for a joint draw, so no one is above the limit in the baseline. The subscription inputs say they sum over all of a person's accounts of a type, since a person can pay into more than one in a year (his finding 3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Review of #2712 at 18aa2a4. I checked each parameter against legislation.gov.uk and the Budget 2026 OOTLAR, read the formulas, hand-checked every new YAML expected value, checked the household-total change against the means tests, and ran the touched tests locally.
Must fix
None found.
Should fix
-
Track the November instrument for the baseline cash limit. SI 2026/1018 reg 6 is made law. It inserts reg 4ZA(1ZA), "£12,000" for a person "64 or under at the end of that year", in force 6 April 2027 (reg 1). The
.infbaseline from 2027 rests only on OOTLAR para 2.5 ("retain the cash ISA limit at £20,000 for all savers over 18 years old from April 2027"), with legislation "to be laid before parliament in November 2026". Putting an announced Budget measure in the baseline matches #2719. But nothing ties the parameter to the instrument that will make it law.- Fix: open a tracking issue and link it from
cash/subscription_limit.yaml. When the November SI is laid, replace the OOTLAR reference with it, and check that it revokes (1ZA) rather than changing it. The same check covers the reg 15 cash-interest charge, as the PR body says.
- Fix: open a tracking issue and link it from
-
Holding subscriptions flat in projection biases later-year reform scores.
cash_isa_subscriptions,stocks_and_shares_isa_subscriptionsanddataset-sources.mdsay amounts are not uprated "as the limits are fixed in cash terms". That is why the limit stays flat, not the inputs. Nominal subscriptions grow: Vahid's review of microcosm#1415 reports cash subscriptions of £41.6bn in 2022-23 and £69.5bn in 2023-24 (HMRC ISA Table 9.4). So on a 2023-24 base, flat inputs understate the amount above a lowered limit in 2027-28 and later years. The real reason for flat inputs looks like a different one: growing them would push people at exactly £20,000 above the annual limit in the baseline.- Fix: give that reason in the docstrings and the dataset guide, and say that flat inputs understate the amount above a lowered limit in later years. Another option is for the producer to grow the amounts and cap them at the limit in force, as microcosm#1415 now plans ("capped at £20,000").
Nice to have
-
The annual limit before 2017-18. Core returns the first value for earlier years, so
annual_subscription_limitgives £20,000 for 2014-15 to 2016-17. The law gave £15,000 from 1 July 2014 (SI 2014/1450 reg 6(a)(i)) and £15,240 before 6 April 2017 (the sum that SI 2017/186 reg 5 replaced). The PR keeps this out of scope, and no dataset year is that early. Two dated values would remove the trap for back-dated household runs. -
Reference for the
.infcash limit. The description says that cash has had no limit of its own since 1 July 2014. No reference cites the instrument that did it: SI 2014/1450 reg 6(a)(ii) omitted reg 4ZA(1)(a) and (b) (legislation.gov.uk footnote F3 on reg 4ZA). Add it. -
The consolidated Schedule link shows the old rate.
above_cap_purchase/withdrawal_charge.yamlcitesuksi/1998/1870/schedulefirst. That page still shows paragraph 5 as "25%" and has no paragraph 6A, so it does not support 0.2 yet. Put SI 2026/1130 reg 5 first, or title the first link "as amended by SI 2026/1130". -
The 20% rate in 2026-27, the current tax year. Today a household-calculator run for 2026 charges 25% on a purchase above the cap that completes from November 2026 to March 2027. About 159 of the 365 days in 2026-27 fall on or after 29 October. The 30 April convention is the repo's rule, and the PR documents the result, so this is a choice for the reviewers. One option is to accept it and also name it in the
programs.yamlnote (done). Another is a per-year override for the current year. -
Restored charges under paragraph 10A. SI 2026/1130 regs 3 and 4 say that a charge restored under paragraph 10A is not a subscription for reg 4ZA(1) and not a Lifetime ISA payment.
isa_subscriptionsnow feedslifetime_isa_paymentsinto the annual limit. Add "repayments of a withdrawal charge under paragraph 10A" to the exclusions in thelifetime_isa_paymentsdocstring. -
Other subscriptions that do not count. The subscription docstrings exclude transfers between ISAs, interest and growth, and flexible-ISA replacements. HMRC's guidance also excludes transfers from a matured Child Trust Fund and some defaulted-account subscriptions. It also says that a withdrawal of current-year subscriptions from a flexible ISA "automatically reduces the net subscription". A phrase such as "net of current-year withdrawals from flexible ISAs, and excluding other subscriptions that reg 5D disregards" would cover these cases.
-
Duplicate index entries.
cash_isaandstocks_and_shares_isaare already in theobr.per_capita.gdplist twice on main (new lines 147 and 152). The PR adds a comment on the firstcash_isa. Remove the second copies at the same time. Also note that #2638 and #2723 both edit the lines next to the newstocks_and_shares_isa_balanceentry, so expect a small merge conflict. -
Follow-up issue for capital attribution. Now that the balances are per person, a follow-up can attribute them to the holder's benefit unit, as #1983 did for the Lifetime ISA. For example, a lodger's cash ISA would then no longer be pooled with the main family's capital. The PR already says this is left for later. An issue would make sure that it is not lost.
Verified as correct
- Annual limit. Reg 4ZA(1) says £20,000 for "the aggregate of the qualifying individual's subscriptions to all accounts that are not junior ISA accounts". SI 2017/186 reg 5 substituted "£20,000" for "£15,240" from 6 April 2017. The Lifetime ISA's £4,000 is reg 4ZA(1A) and counts within the £20,000, as HMRC's guidance confirms.
- Cash limit history. Reg 4ZA(1)(a) and (b) were omitted on 1 July 2014 by SI 2014/1450, so no cash sub-limit applies from 2017.
- SI 2026/1018. The quoted text of reg 6 and the 6 April 2027 commencement (reg 1) are correct.
full_limit_age65 with "reached by 5 April" is the same test as "64 or under at the end of that year". - Age test.
born_before = (Y + 1 - 65) * 10000 + 406puts a 5 April 1963 birth at 65 on 5 April 2028, and a 6 April 1963 birth under 65. That matches Family Law Reform Act 1969 s 9, whichgrid_months_to_yyyymmdduses. With nodate_of_birth, the defaultmonths_since_last_birthdayof 6 puts the birthday on 6 April. So a person aged 64 on 6 October is limited, and a person aged 65 is not. Leap-day births cannot meet the 5/6 April boundary. The formula is vectorised. - Read date.
convert_to_fiscal_year_parametersinutils/parameters.pysays ordinary leaves "take their 30 April value". Soin_effectis false for 2026 and true for 2027, as the docs say. A reform that sets a cash limit for 2026 readsfull_limit_ageas 65 (Core uses the first value). I checked this locally. - SI 2026/1130. It is in force on 29 October 2026, with effect for withdrawals "made on or after 29th October 2026" (reg 1(2) and (3)). New para 5 sets "(a) 20% in relation to a withdrawal to which paragraph 6A applies; (b) 25% in relation to any other withdrawal". Para 6A applies where a withdrawal "would fall within paragraph 6 but for the fact that the requirement in paragraph 6(3) is not met". Para 6(3) is "The purchase price must not exceed £450,000". The formula drops only the price test from
first_home, charges the home payment at 20% and the rest atwithdrawal_charge, and keeps the age 60 and terminal-illness exemptions. OOTLAR para 2.4 agrees. - Household totals. The UC, HB, Pension Credit, IS, JSA and ESA capital
sources.yamllists andshare_like_capitalread the household totals, so a person's balance reaches each means test, as the newcash_isa_capital.yamlcase shows.test_isa_balances.pyshows that a stored total, with no person balances, is projected by the savings growth factor. The index on the person balances equals the index on the stored totals, so nothing is uprated twice. - Aggregate impact. The bot ran at
00adbd1e7. The only later commit (18aa2a46c) changes docstrings anddataset-sources.md. The bot reports no change in any year on enhanced FRS 2024-25. - YAML arithmetic. I checked every new expected value. For example: 12,000 + 4,001 + 4,000 = 20,001, so £1 above the limit. 25,000 is £13,000 above £12,000 and £5,000 above £20,000. Under a £15,000 annual limit, 12,000 + 8,000 is £5,000 above it. Above the cap, 10,000 × 20% + 2,000 × 25% = 2,500. The 2026 cases are 10,000 × 25% = 2,500.
- References. Every href returns 200: reg 4ZA, SI 2017/186 reg 5, SI 2026/1018 reg 6, SI 2026/1130 regs 1 and 5, the Schedule, OOTLAR, and the HMRC guidance.
- Scope. Leaving the savings rates out is fine. #2719 (open) raises
gov.hmrc.income_tax.rates.savingsto 24/44/49% from 2027-28, andisa_cash_interest_flat_rate_chargefollows it throughsavings.basic. You could link #2719 in the "Not in this PR" section. No open PR touches the ISA limits or the Lifetime ISA charge.
Tests run locally
In a uv venv on the PR head (uv venv && uv pip install -e ".[dev]", Python 3.13):
policyengine-core test policyengine_uk/tests/policy/baseline/gov/hmrc/isa -c policyengine_uk: 30 passed.policyengine-core test policyengine_uk/tests/policy/baseline/household/wealth/isa_balances.yaml policyengine_uk/tests/policy/baseline/gov/dwp/cash_isa_capital.yaml -c policyengine_uk: 10 passed.pytest policyengine_uk/tests/test_isa_balances.py policyengine_uk/tests/test_wealth_components.py policyengine_uk/tests/code_health/test_uprating_declarations.py: 13 passed.- An ad hoc check of parameter reads for 2016, 2020, 2026 and 2027, and of a £12,000 cash-limit reform for 2025 to 2030 (ages 64 and 66). The results were as expected.
The CI YAML and Python suites had not finished at 18aa2a4 when I checked.
🤖 Generated with Claude Code
| 2026, so cash keeps no limit of its own here. Set this to 12,000 to model the | ||
| lower limit. | ||
| values: | ||
| 2017-04-06: .inf |
There was a problem hiding this comment.
Should fix 1. SI 2026/1018 reg 6 is made law from 6 April 2027. Only OOTLAR para 2.5 supports .inf from that date. Please link a tracking issue here, so the reference changes to the November instrument when it is laid. At that time, check that the instrument revokes (1ZA) rather than changes it.
There was a problem hiding this comment.
Still open at 1915a91. The reference list is unchanged, and I found no tracking issue for the November instrument. A one-line issue linked from this file is enough.
| period: year | ||
| unit: currency-GBP | ||
| reference: | ||
| - title: Individual Savings Account Regulations 1998 regulation 4ZA |
There was a problem hiding this comment.
Nice to have 4. The description relies on 'no limit of its own since 1 July 2014'. Add SI 2014/1450 reg 6(a)(ii) as a reference: https://www.legislation.gov.uk/uksi/2014/1450/regulation/6/made. It omitted reg 4ZA(1)(a) and (b) (footnote F3 on reg 4ZA).
There was a problem hiding this comment.
Fixed in 1915a91. The value now starts on 1 July 2014, and SI 2014/1450 reg 6(a)(ii) is cited.
| Junior ISAs: cash, stocks-and-shares, innovative finance and new Lifetime ISA | ||
| payments together. | ||
| values: | ||
| 2017-04-06: 20000 |
There was a problem hiding this comment.
Nice to have 3. Core gives this value for every earlier year, so 2014-15 to 2016-17 read £20,000. Consider 2014-07-01: 15000 (SI 2014/1450 reg 6(a)(i)) and 2015-04-06: 15240. SI 2017/186 reg 5 replaced the sum £15,240.
There was a problem hiding this comment.
Fixed in 1915a91. I checked SI 2015/608 reg 3(1): it substitutes £15,240 for £15,000 in reg 4ZA(1). The two new 2015 and 2016 cases pass locally.
| period: year | ||
| unit: /1 | ||
| reference: | ||
| - title: Individual Savings Account Regulations 1998, Schedule paragraphs 5 and 6A |
There was a problem hiding this comment.
Nice to have 5. The consolidated Schedule page still shows paragraph 5 as 25% and has no paragraph 6A, so this link does not support 0.2 yet. Put SI 2026/1130 reg 5 first, or title this link 'as amended by SI 2026/1130 reg 5'.
There was a problem hiding this comment.
Fixed in 1915a91. SI 2026/1130 reg 5 is now first, and the consolidated link is titled 'as amended'.
| October 2026 to 5 April 2027 pays the withdrawal charge. | ||
| values: | ||
| 2000-01-01: false | ||
| 2026-10-29: true |
There was a problem hiding this comment.
Nice to have 6. The 30 April read is correct (convert_to_fiscal_year_parameters). But 2026-27 is the current year, and about 159 of its 365 days fall from 29 October. A household-calculator run for 2026 shows 25% for a purchase above the cap in the rest of this tax year. Should we accept this as documented, or add a per-year override?
There was a problem hiding this comment.
No change at 1915a91. This is a choice for the human reviewers, so I leave it open for them.
There was a problem hiding this comment.
Decided: we keep the 30 April convention.
- A 2026-27 run charges 25% on an above-cap purchase withdrawn from 29 October 2026 to 5 April 2027, and the 20% applies from 2027-28.
- This is the same treatment as paragraph 5A's 20% from March 2020, which the model picks up from 2020-21.
- Population runs aren't affected: the data has no Lifetime ISA withdrawals towards a home.
The caveat is recorded in 04895b0:
lifetime_isa_withdrawal_charge's docstring now gives the 2026-27 consequence;- the assumptions page's "Annual resolution and coverage" section gives it next to the March 2020 case.
It was already in this parameter's description, the Lifetime ISA section of that page, programs.yaml and the changelog fragment.
There was a problem hiding this comment.
Thanks. Keeping the 30 April convention is consistent with the paragraph 5A case in 2020. 04895b0 states the 2026-27 effect in the variable's docstring and on the assumptions page. I have nothing more on this item.
| "not count towards the limits. The model compares this amount with the limits in force " | ||
| "and does not cap it: under a lower limit, such as a reform that " | ||
| "brings in a £12,000 cash limit, cash_isa_subscriptions_above_limit " | ||
| "reports the part that cannot be paid in. Amounts are not uprated, as " |
There was a problem hiding this comment.
Should fix 2. A fixed limit is the reason the limit stays flat, not the subscriptions. Nominal subscriptions grow (HMRC Table 9.4: cash £41.6bn in 2022-23 and £69.5bn in 2023-24), so flat inputs understate the amount above a lowered limit in later years. If the real reason is to keep people at £20,000 within the limit in the baseline, give that reason and the bias here, in stocks_and_shares_isa_subscriptions and in dataset-sources.md. Nice to have 8: also say 'net of current-year withdrawals from flexible ISAs' and exclude the other subscriptions that reg 5D disregards, for example matured Child Trust Fund transfers.
There was a problem hiding this comment.
Fixed in 1915a91. The docstrings, the assumptions page and dataset-sources.md now give the real reason and the bias. Nice to have 8 is also fixed (net of flexible-ISA withdrawals, reg 5D disregards).
| adds = [ | ||
| "cash_isa_subscriptions", | ||
| "stocks_and_shares_isa_subscriptions", | ||
| "lifetime_isa_payments", |
There was a problem hiding this comment.
Nice to have 7. SI 2026/1130 regs 3 and 4: a withdrawal charge restored under Schedule paragraph 10A is not a subscription for reg 4ZA(1) and not a Lifetime ISA payment. Add it to the exclusions in the lifetime_isa_payments docstring, because this total now uses that input for the annual limit.
There was a problem hiding this comment.
Fixed in 1915a91. The lifetime_isa_payments docstring now excludes paragraph 10A repayments.
| - capital_gains_carried_interest | ||
| gov.economic_assumptions.yoy_growth.obr.per_capita.gdp: | ||
| - benunit_reported_capital | ||
| # cash_isa and stocks_and_shares_isa sum the person balances listed with |
There was a problem hiding this comment.
There was a problem hiding this comment.
Fixed in 1915a91. The second copies are removed.
- Give the real reason the subscription inputs are held flat in projection (growing them would put people who pay in exactly the limit above it), and say that this understates a lowered limit's excess in later years. - Count subscriptions net of current-year flexible-ISA withdrawals and exclude what regulation 5D disregards; exclude paragraph 10A charge repayments from lifetime_isa_payments (SI 2026/1130 regs 3 and 4). - Date the annual limit's earlier sums: £15,000 from 1 July 2014 (SI 2014/1450 reg 6(a)(i)) and £15,240 from 6 April 2015 (SI 2015/608 reg 3(1)), so 2015-16 and 2016-17 no longer read £20,000. The fiscal-year conversion writes annual values from 2015, so earlier years are not read. - Start the cash limit's infinity on 1 July 2014 and cite SI 2014/1450 reg 6(a)(ii), which omitted the cash sub-limits. - Put SI 2026/1130 reg 5 first for the above-cap charge. - Remove the duplicate cash_isa and stocks_and_shares_isa entries from the uprating map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Follow-up review of #2712 at 1915a91bc (new since 18aa2a46c: one commit, "Address Pavel's review of the ISA limits").
Must fix
None.
Should fix
- Still open: track the November instrument for the baseline cash limit. The
.inffrom 6 April 2027 still rests only on OOTLAR para 2.5, and I found no tracking issue. Please open one and link it fromcash/subscription_limit.yaml. - Fixed: the reason that subscriptions are held flat, and the bias that it causes, are now stated in both docstrings, the assumptions page and
dataset-sources.md.
Nice to have
- Still open: 6 (the 20% rate in the rest of 2026-27) is a choice for the human reviewers. 10 (a follow-up issue for per-person capital attribution) has no issue yet.
- Fixed in 1915a91: 3, 4, 5, 7, 8 and 9.
Verified as correct
- Earlier limits. SI 2015/608 reg 3(1) substitutes "£15,240" for "£15,000" in reg 4ZA(1). SI 2014/1450 reg 6(a)(i) gives £15,000 from 1 July 2014. The new cases check 15,240 and 15,241 in 2015-16, and cash at the annual limit in 2016-17, which is correct because cash has no limit of its own.
- Cash limit. It now starts as
.infon 1 July 2014, the date that SI 2014/1450 reg 6(a)(ii) took effect. - Docs and changelog. They match the code.
verified_start_year: 2015matches the first year that the model reads. - Uprating map. The duplicate
cash_isaandstocks_and_shares_isalines are removed, and each variable is listed once.
Tests run locally
At 1915a91bc, uv venv with .[dev]:
policyengine-core teston the ISA folder,isa_balances.yamlandcash_isa_capital.yaml: 42 passed.pytestontest_isa_balances.py,test_wealth_components.pyandcode_health/test_uprating_declarations.py: 13 passed.
🤖 Generated with Claude Code
Pavel's should fix 1: from 6 April 2027 the cash limit rests on Budget 2026 until the November 2026 instrument is laid, which policyengine-uk#2728 tracks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pavel's nice to have 6, decided with María: keep the 30 April convention. SI 2026/1130's 20% has effect for withdrawals from 29 October 2026, but fiscal 2026 samples 30 April 2026, so a 2026-27 run charges 25% on such a withdrawal made from 29 October 2026 to 5 April 2027. The withdrawal charge's docstring and the assumptions page's annual resolution section now say so, alongside the parameter description, the Lifetime ISA section, programs.yaml and the changelog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Follow-up review of #2712 at 04895b0ac (two commits since 1915a91bc: 52b09bc and 04895b0).
Must fix
None.
Should fix
None. Should fix 1 is fixed: #2728 tracks the November instrument, and cash/subscription_limit.yaml links it (52b09bc).
Nice to have
None open.
- 6: closed by decision. The model keeps the 30 April convention, and 04895b0 records the 2026-27 effect (25% from 29 October 2026 to 5 April 2027, 20% from 2027-28).
- 10: #2729 tracks the per-person capital attribution.
Verified as correct
- The two commits change only a YAML comment, a docstring and the assumptions page. No values or formulas change.
- The 159-of-365-days figure on the assumptions page is correct for 29 October 2026 to 5 April 2027.
I have no open findings on this PR. I did not re-run tests, because the two commits change no code or values. The last run (at 1915a91bc) passed: 42 YAML and 13 pytest.
🤖 Generated with Claude Code
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Approving at 04895b0ac. All findings from my reviews are closed. CI passes at this head. The November instrument is tracked in #2728 and the per-person capital attribution in #2729.
🤖 Generated with Claude Code
Fixes #2710
What and why
policyengine-uk had no ISA subscription limits and no subscription inputs, so a change to an ISA limit left every household unchanged. This PR adds:
It follows the Budget 2026 update on the issue. Current law keeps the £20,000 cash limit, and the model reports the amount above each limit and no more (option (b)).
There are eleven commits:
Subscription limits (5aaf6da, 677d767)
gov.hmrc.isa.annual_subscription_limit: £20,000 from 6 April 2017 (ISA Regulations 1998 reg 4ZA(1), sum substituted by SI 2017/186 reg 5).gov.hmrc.isa.cash.subscription_limit: no limit of its own (.inf). Cash has had none since SI 2014/1450 omitted reg 4ZA(1)(a) and (b) on 1 July 2014.gov.hmrc.isa.cash.full_limit_age: 65.cash_isa_subscription_limitreads the age at the end of the year (5 April) from the date of birth (birth_day). So a person aged 64 on 6 October whose 65th birthday falls by 5 April has the annual limit. The age matters only when a reform sets a cash limit.cash_isa_subscriptionsandstocks_and_shares_isa_subscriptions: new money paid in during the tax year.isa_subscriptionsadds them tolifetime_isa_payments. That input includes transfers into a Lifetime ISA, which count towards the £4,000 limit but not the annual one, so the total is too high where it includes them. The variable's documentation says so.cash_isa_subscriptions_above_limitandisa_subscriptions_above_limit: how far the inputs exceed the limits in force.isa_subscription_limitsentry inprograms.yaml.Per-person cash and stocks-and-shares ISA balances (3d5e7cc)
cash_isa_balanceandstocks_and_shares_isa_balance, uprated with savings andcorporate_wealth.cash_isaandstocks_and_shares_isanow sum them, ashousehold_lifetime_isa_balancesumslifetime_isa_balance.uprating_indices.yaml, so a dataset that stores only the household totals (all of Microcosm's today) keeps them, projected as before.test_wealth_components.pynow checks the uprating on the summed inputs.Lifetime ISA charge for homes above the price cap (da16986)
gov.hmrc.isa.lifetime.above_cap_purchase.in_effect(from 29 October 2026) and.withdrawal_charge(0.2).lifetime_isa_withdrawal_chargecharges the home payment of such a purchase at 20% and the rest of the withdrawal atwithdrawal_charge.lifetime_isa_withdrawals_towards_first_homenow says to include a purchase above the cap.Review fixes (1915a91, 52b09bc, 04895b0)
verified_start_yearis 2015..infstarts on 1 July 2014, citing SI 2014/1450 reg 6(a)(ii). A comment links Update the ISA cash limit and the non-cash ISA charge when the November 2026 ISA instrument is laid #2728, which tracks the November instrument.lifetime_isa_paymentsexcludes paragraph 10A charge repayments.Documentation (020f230, 00adbd1, 18aa2a4)
docs/book/assumptions/isa-inputs-and-capital-flows.md:docs/engineering/skills/dataset-sources.md: how producers should export the balances and subscriptions, pointing to UK: impute ISA subscriptions per adult by type, calibrated to HMRC's ISA tables microcosm#1415.docs/book/assumptions/growthfactors.mdlists the new balances.Not in this PR
lifetime_isa_payments, andnon_cash_isa_cash_interestif the 2027 charge survives. Until then, every ISA limit reform scores £0 on population data.gov.hmrc.income_tax.rates.savingsstill holds 22%, 42% and 47%, which needs its own update.isa_cash_interest_flat_rate_chargereadssavings.basic, so it would follow. Autumn Budget 2026 measures in current law #2719 makes that update.Downstream
Apps that list input variables will show
cash_isa_balanceandstocks_and_shares_isa_balanceas person inputs. The householdcash_isaandstocks_and_shares_isaare now computed, but still accept a direct input.Test plan
isa_subscription_limits.yaml(10 cases):lifetime_isa_withdrawal_charge.yaml, 4 new cases:household/wealth/isa_balances.yaml, acash_isa_capital.yamlcase, andtest_isa_balances.py:test_isa_balances.py,test_wealth_components.pyandcode_health/test_uprating_declarations.py(13);test_isa_accounting.pywith the parameter, registry, variable and changelog checks (247);ruff format --checkandruff checkon the whole repository.code_health/withtest_build_metadata.pyandtest_parameter_cache_apis.py(3,070 passed, 1 skipped), and the ISA income and capital share tests.changelog.d/2710.added.md,changelog.d/2710.changed.mdandchangelog.d/2710-lisa-above-cap.added.md.axiom: TheAxiomFoundation/rulespec-uk#487 queued (extension: ISA Regulations 1998 reg 4ZA(1) and (1ZA); follow-up: (1ZA) held for the November instrument, and SI 2026/1130 Schedule paragraphs 5, 6A and 10A; addendum: reg 4ZA(1)'s earlier sums). The reporting variables carry no law of their own.
🤖 Generated with Claude Code