Repository navigation
Conversation
UC Regs 2013 reg. 49(1) and its legacy equivalents (HB Regs 2006 reg. 47, HB (SPC) Regs 2006 reg. 45, IS Regs 1987 reg. 49, JSA Regs 1996 reg. 111, ESA Regs 2008 reg. 113, SPC Regs 2002 reg. 19) calculate capital at market or surrender value less 10% where a sale would incur expenses and less any encumbrance secured on it. The model summed every capital source at full value. Each programme gets a capital.sale_expenses node (rate 0.1 and the sources whose sale incurs expenses: land, property and corporate_wealth, not cash savings). A shared helper applies the 10% before the encumbrance and never values an encumbered asset below nil. New household inputs carry debt secured on other residential property, non-residential property and land; the Enhanced FRS has none, so they default to zero. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Each programme's sale-expense parameters now cite its GB and NI regulations, the guidance paragraph that orders the 10% before the encumbrance, and per-asset guidance with exact PDF page anchors (DMG ch 52 for ESA, HBGM Annex F for HB savings, H1656/H1665/H1673-H1675 for UC). - The source-list descriptions and changelog say plainly that corporate_wealth also holds unit trusts, ISAs, employee share options and, in datasets built before the pension split, non-DB pension wealth. - The helper and secured-debt docs say debts net within a source category. - The property-test oracle fixes the sale-expense assets and the 10% itself instead of reading the parameters, checks pension-age HB, and runs on larger populations. New hand-computed cases cover HB second homes and premises, per-source flooring between two encumbered sources, pension-age HB, and a monthly secured debt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HBGM W1.430 states only the general 10% rule; the rule that real property always has costs of sale comes from R(IS) 21/93, as DMG 29622 applies it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Coordination note from #1950 (UC capital income). If this PR lands after #1950, please update the "reg 49 is #1960" notes #1950 adds:
Those cases enter £10,000 of property as capital. At 90% that is 12 tariff steps, not 16, so either update the expected values or restate the input as a property value of £11,111.11. If #1950 lands second, I'll do it on rebase. #1950's merge is waiting on a decision from Max (over the £1bn/yr line). 🤖 Generated with Claude Code |
|
#1950 merged (770bc06), so this PR is second. Please update the "reg 49 is #1960" notes:
At 90% valuation, £10,000 of property is 12 tariff steps, not 16, so either update the expected values or enter £11,111.11. 🤖 Generated with Claude Code |
Resolve the capital variables onto main's claimant/partner allocation and person-level sources, valuing household sources through valued_capital. Update the let-property tests #1950 added: £10,000 of property is now £9,000 of capital under reg. 49(1), so 12 tariff steps, not 16. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two tests main added after this branch's earlier base assumed full-value capital: - The CTR savings-credit-only case holds savings 10,000 and a 7,000 second property: capital is 10,000 + 90% of 7,000 = 16,300 (SPC Regs 2002 reg. 19(a)), still over the 16,000 limit, so CTR stays nil. Deemed income is 13 steps x 52 = 676, Pension Credit income 13,314 + 676 = 13,990, and savings credit 60% of (12,376 - 208.07 x 52) less 40% of (13,990 - 12,376) = 288.22. - The reported-capital property test's proxy oracle now values land, property and shares at 90% and savings at face value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The six capital sources lists (UC, HB, IS, JSA, ESA, PC) name directly_held_shares, unit_and_investment_trusts and stocks_and_shares_isa in place of corporate_wealth, plus a new formula variable, unitemised_corporate_wealth = max(0, corporate_wealth - components), for whatever a dataset does not itemise. Datasets without the components keep counting corporate_wealth in full; datasets that build corporate_wealth as the components' exact sum count the same total, now itemised, so each component can carry its own valuation rule (the sale-expense deduction stacked on #1969 exempts unit trusts and ISAs). No dataset's capital changes: a differential property test checks that every programme's assessable capital equals the same holdings entered as one corporate_wealth. Review nits: the growth-factor sentence now matches uprating_indices.yaml exactly; the variable docs cite the DMG for the legacy benefits, the expert valuation of unquoted shares and the quoted-share rule for investment trusts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Stacked follow-up: #2131 lists only 🤖 Generated with Claude Code |
vahid-ahmadi
left a comment
There was a problem hiding this comment.
Thanks Max. Reviewed at head 22274cad.
The law is right in every programme. I re-fetched each provision from legislation.gov.uk:
-
UC Regs 2013 reg 49(1): "Capital is to be calculated at its current market value or surrender value less— (a) where there would be expenses attributable to sale, 10%; and (b) the amount of any encumbrances secured on it."
-
The same rule appears, in older wording ("10 per cent", "encumbrance/incumbrance"), in:
- SPC Regs 2002 reg 19;
- HB Regs 2006 reg 47 and HB (SPC) Regs 2006 reg 45;
- IS Regs 1987 reg 49;
- JSA Regs 1996 reg 111;
- ESA Regs 2008 reg 113.
The regulation numbers are right (JSA 111 and ESA 113).
-
CTR Prescribed Requirements SI 2012/2885 Sch 1 para 32 has the same 10% rule for pension-age CTR.
-
SPC Sch V has no disregard that touches share, unit trust or ISA valuation. Para 9 is business assets only.
The helper follows the guidance. valued_capital takes the 10% off gross value before the debt (ADM H1608) and floors each encumbered source on its own (H1615-H1616).
Probes all match hand arithmetic:
- savings £5,000 +
corporate_wealth£12,000 gives £15,800 for UC, HB and IS, and £15,800 for PC at 70 (main: £17,000); - a £100,000 second home with £95,000 debt plus £3,000 savings gives £3,000;
- a second home of £20,000 with £25,000 debt plus premises of £10,000 gives £9,000.
Tests:
- At the head: properties, PC reported capital and stock periods, 9 passed. DWP, family and CTR YAML, 967 passed.
- Merged into current main
b5b09231(the merge is clean; the branch is 280 commits behind): the same YAML set, 1,274 passed. But two of the new property tests fail; see finding 1. The green CI is from the stale merge ref.
Findings:
-
Blocking (rebase). On main + this branch,
test_valuation_matches_the_regulation_and_never_adds_capitalandtest_cash_only_households_have_no_deductionfail (2 failed, 8 passed). The valuation isn't the problem; the test's oracle is out of date.- Main now sets HB capital to nil for anyone on UC, IS, income-based JSA or income-related ESA (HB Regs Sch 6 para 5,
housing_benefit_on_passporting_benefit). It also switches the pension-age rules onhousing_benefit_pension_age_regulations_applyrather than age 67. - So a working-age single person with £2,441.62 of cash now has HB capital of nil (on main too), while
applies()attests/test_capital_valuation_properties.py:127still expects their savings. - I reproduced the cash-only failure directly. The other failing test uses the same
applies()predicate, so it is most likely the same cause. - Fix: rebase and key the pension-age branch on
housing_benefit_pension_age_regulations_apply. Then either skip units wherehousing_benefit_on_passporting_benefitis true, or give the generated units enough earnings to stay off UC. Skipping alone would hollow out the working-age HB branch, because the strategy's no-income singles are nearly all on UC.
- Main now sets HB capital to nil for anyone on UC, IS, income-based JSA or income-related ESA (HB Regs Sch 6 para 5,
-
Blocking (merge order with #1974). Git merges this branch and #1974 cleanly, but together they undo this PR:
- #1974 takes
corporate_wealthout of everycapital.sourceslist, while this PR'ssale_expenses.sourcesstill names it. So the 10% on shares silently stops. - On a 1969 + 1974 tree, the probe above goes back to £17,000. Seven YAML cases fail: 3 in
capital_valuation.yaml, and 2 each in the IS and ESA capital files. - #2131 fixes this. So either merge #1974 first and then this PR and #2131 together, or merge this PR and then #2131 retargeted to main (it carries #1974).
- A cheap guard in
tests/test_capital_valuation_properties.py: assertset(sale_expenses.sources) <= set(capital.sources)for each programme. The existing check at line 160 intersects both sides withcounted, so it can't see a stale name.
- #1974 takes
-
Should fix (body, disclosure). In "A few records carry each figure", the UC, PC and HB bullets, and the poverty bullet, attribute most of each year's change to one or a handful of records, with percentages and counts. Read against the impact table, that is effectively a record-level weighted amount. Keep the caveat ("driven by a handful of records; not an estimate") and drop the percentages, record counts and the median gain.
-
Nit.
parameters/gov/dwp/income_support/means_test/capital/sale_expenses/rate.yaml:9. This starts on 2010-01-01, to matchsources. IS reg 49 has applied the 10% since 11.4.1988. Add a sentence saying the date follows the sources list, as the HB and PC files already explain their own dates. -
Nit.
utils/capital_valuation.py:18-19. Netting debt across assets within a category is documented. H1616 actually allows it where one debt is secured on several assets. You could cite that, so the approximation reads as partly lawful rather than purely a data limitation. -
Coordination with #1965. Merged with #1965 there is no textual conflict, but the holding comes off at 100% while it is counted at 90%: savings £5,000 + a £10,000 holding gives £4,000 instead of £5,000. I've put the fix on #1965, since it rebases second.
Keep main's recorded benefit-unit capital (benunit_reported_capital), which replaces the valued household sources as recorded, and register the secured-debt inputs beside main's uprating entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
£20,000 of shares is £18,000 of Pension Credit capital (SPC Regs 2002 reg. 19(a)), still over the CTR limit: deemed income 16 x 52 = 832, Pension Credit income 14,146, savings credit 933.816 - 0.4 x 1,770 = 225.82. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's Housing Benefit passport (#1927 and the Universal Credit limb) gives a family on a passporting benefit nil HB capital, so the property's independent reg 47 valuation applies only to non-passported families. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
We've moved this back to draft. Since #2781 landed on main today, this PR fails main's #2765 conflicts with this PR in |
|
Picking this up for the UK hub. Reply here if you're mid-change and I'll stop. Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Kxyq1frfihPSQorLM
…ls test The household's stocks-and-shares ISA reaches Universal Credit capital through share_like_capital, which UC values less its sale-expense rate (UC Regulations 2013 reg. 49(1)(a)). Build the expected capital from savings, the cash ISA and the ISA less that rate, read from the parameters, and keep the check that capital keeps one ratio to savings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6Kxyq1frfihPSQorLM
|
Generated by Claude Code |
|
Generated by Claude Code |
|
Ready for hub review Head Commits:
Findings1. Cause of the #2781 failure: confirmed. The model is right and the test was out of date.
2. Reproduced. At 3. Test fix (
4. Other tests #1969 might move. 5. Mutation check. In a scratch worktree I set 6. #2765 (juaristi22, head
Resolution that keeps both (the set is a #2765's other additions to the same set ( 7. #2131: a follow-on the hub should know about. #2131 (head Tests at
|
| Command | Result |
|---|---|
pytest -n 4 policyengine_uk/tests/test_stored_household_totals.py |
42 passed, 161 s |
pytest …/test_capital_share_components.py::test_capital_matches_the_original_lists (alone, 45-min cap) |
1 passed, 1,837 s (wall 1,846 s), alongside the YAML and other Python runs on 4 cores |
pytest -n 4 …/test_capital_share_components.py without that node |
13 passed, 226 s |
test_capital_valuation_properties.py |
18 passed, 296 s |
test_isa_balances.py |
2 passed |
test_pension_credit_reported_capital_properties.py |
4 passed, 234 s |
test_savings_credit_only_receipt_properties.py |
6 passed, 195 s |
test_stock_capital_periods.py |
2 passed |
test_uc_company_override_properties.py |
11 passed |
test_uc_company_owner_properties.py |
7 passed, 225 s |
test_uc_property_capital.py |
65 passed, 263 s |
test_uc_property_capital_mock.py |
26 passed |
policy/…/universal_credit/test_uc_capital_allocation.py |
1 passed |
| YAML (each file alone): esa_income_capital 10, esa legacy_capital 3, housing_benefit_capital 13, housing_benefit_residential_capital 7, HB legacy_capital 2, income_support_capital 10, IS legacy_capital 3, jsa_income_capital 9, JSA legacy_capital 3, uc_company_analogous_business 26, uc_income_from_capital 7, is_UC_eligible 17, uc_assessable_capital 6, capital_valuation 26, cash_isa_capital 8, lifetime_isa_capital 24, pension_credit_deemed_income 7, pension_credit_income 10, pension_credit_reported_capital 9, uc_property_capital 9, council_tax_reduction_pension_credit 23, benunit_reported_capital 6 | 238 passed, 0 failed |
pytest -n 4 policyengine_uk/tests/code_health |
3,108 passed |
.github/check_fix_pr.py on the final title and body, with the change list from merge-base 0080274d7 to the head, as pr_fix_evidence.yaml builds it |
PASS: "Fix PR has valid reproducer evidence. Changed executable tests: 23." |
uvx ruff@0.17.2 format --check . / check . / check --select F811,F821 policyengine_uk |
clean |
git diff --check 3a3241cf6..HEAD |
clean |
Incident, and what I reran
A scratch command whose cd into a worktree failed fell through to a git checkout --detach in the main checkout. That left the working tree on the scratch merge of this head with #2131. During that window, one YAML run (housing_benefit_residential_capital.yaml: 2 failed) and an earlier start of the long node ran against the wrong tree, and the formatting amend briefly produced a local commit called tmp on that tree. That commit was never pushed. I restored the branch at d5efa536, reapplied the format fix as c11d7c1d9, and reran every reported result on the correct tree: all 22 YAML files, the long node, the Python files, code_health, the stored-totals file, ruff and diff --check. The table above holds only those reruns. housing_benefit_residential_capital.yaml passes 7 of 7 at the correct head. The mutation check ran in its own worktree before the incident.
Not done, and judgement calls
- I left the title as it is: 102 characters, over the 70 the guidance names. The brief says to keep each document's first lines.
- I left the aggregate impact table unchanged and added no changelog fragment.
- I did not move
uc-capital-sale-expenses. The hub moves it after reviewing. - The
Existing tests whose expected values movesubsection is new, so I also puttest_isa_balances.py(fromfc066bd31) in it, to keep the list complete. - I posted both hub documents above this comment.
Generated by Claude Code
|
Ready for hub review Verdict: APPROVE WITH NITS at Scope: FindingsNo P1. P2. The body describes
|
| Mutant | Result |
|---|---|
sale_expenses/rate.yaml 2013-04-29: 0 |
killed: assert np.float64(6000.0) < (np.float64(6000.0) - 0.01), year 2025 |
drop "stocks_and_shares_isa" from share_like_capital's itemised list |
killed: assert np.float64(4000.0) == 5800.0 ± 0.058, year 2025 |
UC sale_expenses/sources.yaml set to [] |
killed: assert np.float64(6000.0) == 5800.0 ± 0.058, year 2025 |
nil rate, with test_isa_balances.py and the ba4de95d6 version of the test |
3 passed (survives, as the body says) |
The ratio assertion holds only by construction in DATA_YEAR, and it can fail only if the parts grow at different rates. That is its purpose, so I mutated nothing for it.
- Value share-like capital by asset type for the sale-expense deduction #2131 (open, base
uc-capital-sale-expenses, head6a0d26d618e018d673e23adaaf777cbd2a498d35) contains3a3241cf6.git merge-tree --write-treeagainstc11d7c1d9is clean (treef6ec327e1, as the hand-off says), and so is the merge againstb4e872273(tree44bb07144). - On a scratch commit of the latter merge,
test_stored_household_totals_grow_past_the_projection_horizonfails withassert np.float64(6000.0) == 5800.0 ± 0.058(2025).test_isa_balances.pypasses there (8 passed). Value share-like capital by asset type for the sale-expense deduction #2131 rewrites that file to expect(1_000.0 + 3_000.0 + 2_000.0) * growth. - The body's instruction for Value share-like capital by asset type for the sale-expense deduction #2131 is right: expect the three parts at face value (6 × savings) and drop the below-face-value assertion. Value share-like capital by asset type for the sale-expense deduction #2131 should also drop the rate read and change the comment's "less its sale-expense rate … 5.8 for this household".
- Add a trading allowance claim status, so allowance reforms reach claimants without turnover data #2765 (head
edda47ea2a0d99ca2c0e727b32120ef417c9e3e6) is an ancestor of52b30809, sob4e872273carries the resolution, which keeps both names.
Body and title.
- Title: "Value means-tested capital less 10% sale expenses and secured debt", 66 characters.
- I read the hub's body against
PR_BODY.author.mdline by line. Apart from theexact_amountsentence (P3), the edits change wording, not facts. One edit swaps "strictly below" for "more than a penny below", which matches the code:capital < face_value - 0.01. The voice pass also drops three things: the review's memory and time caps, the SHA-256 detail, and the closing rulespec-uk bullet. None of these is a claim about the code. - I checked the new sections against what I reran: the £5,800 and £6,000 figures, the failure line, the Value share-like capital by asset type for the sale-expense deduction #2131 failure, the Add a trading allowance claim status, so allowance reforms reach claimants without turnover data #2765 hunk and the three names,
uprating_indices.yaml, and the test's assertions. - "Main's other test changes since
2da212abcread no means-tested capital variable" holds. Of the 19 test pathsmainchanged from2da212abcto0080274d7, onlytest_stored_household_totals.pynames one. - Every backticked name in the live body exists at the head. That covers files, variables, parameters and the test node. Every SHA resolves, including
1193614a6and2eb144a64through the REST API.
Local runs at b4e872273.
| Command | Result |
|---|---|
uv run pytest -n 4 policyengine_uk/tests/test_stored_household_totals.py |
42 passed (214 s) |
uv run pytest -n 4 policyengine_uk/tests/test_isa_balances.py |
2 passed (19 s) |
uv run pytest -n 4 policyengine_uk/tests/test_capital_valuation_properties.py |
18 passed (328 s) |
uv run policyengine-core test policyengine_uk/tests/policy/baseline/gov/dwp/capital_valuation.yaml -c policyengine_uk |
26 passed |
uv run pytest -n 4 policyengine_uk/tests/code_health |
3,110 passed (287 s) |
.github/check_fix_pr.py on the live title, body and labels, with changes from merge-base(52b30809, b4e872273) to the head, as pr_fix_evidence.yaml builds them |
Fix evidence: PASS — "Fix PR has valid reproducer evidence. Changed executable tests: 23." |
uvx ruff@0.17.2 format --check . / check . / check --select F811,F821 policyengine_uk |
2,177 files already formatted / All checks passed / All checks passed |
git diff --check 3a3241cf6..b4e872273 |
clean |
CI at b4e872273 (commits/b4e872273…/check-runs, read at 07:23Z on 3 Nov):
Every finished job passed. That covers all seven Python shards (the last finished at 07:23:12Z), Test / Result, Test / YAML, Lint, Changes, Changelog fragments, Fix evidence, Documentation build, Release build and the four install smoke-imports. Nothing failed or was cancelled. Pending: Aggregate impact (job 125760423375), in progress since 06:16:00Z. The body's impact table still describes 3a3241cf6, and the hub replaces it from that job's comment.
At c11d7c1d9, Fix evidence shows one cancelled run (125569655066, 21:41:34Z to 21:41:35Z). A second run started 6 s later (125569671160) and passed, so the cancelled one was superseded and was not a failure. Every other job there passed, including Test / Result.
What I couldn't check
- I did not rerun
test_capital_share_components.py::test_capital_matches_the_original_lists(about 30 min), the rest of that file, the other Python files in the body's table, or the 22 YAML capital files other thancapital_valuation.yamlatb4e872273. CI's shards cover them; all seven shards and the YAML job passed at the head. - I did not rerun anything that rests only on the hub's machine: v10's ISA probes, the Keep Tax-Free Childcare over a smaller UC award, and take no deductions from awards only a reform creates #2754 Tax-Free Childcare cases, or the aggregate-impact table, which the hub replaces from the CI comment.
- I didn't diff the two bodies with a tool, because the author's body exists only in the brief, so I compared them by reading. I counted the edits but did not reconcile them against the hub's figure of 21.
Generated by Claude Code
|
Picking this up for the UK hub. Reply here if you're mid-change and I'll stop. Generated by Claude Code |
Resolve the six assessable-capital formulas so each values every household source through valued_capital after subtracting the ISA balances main's person-capital pool moves to their holders, and values each moved stocks and shares ISA balance as its household source. Rework main's ISA and savings-credit cases by hand for the 10% sale-expense deduction, and deduct the debt secured on land in council tax reduction's own household capital. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6K8DguS6nS1jwFZ8Zi
The pound-counts-once and worked-example checks in test_person_isa_capital.py now value share_like_capital, and each stocks and shares ISA balance moved out of it, less the programme's sale-expense rate, and allow for each unit's penny rounding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6K8DguS6nS1jwFZ8Zi
|
Picking this up for the UK hub. Reply here if you're mid-change and I'll stop. Generated by Claude Code |
Git merged main without conflict. Since af93611, main's #2744, #2760, #2763, #2768, #2769, #2786, #2787, #2788, #2794, #2809 and #2810 change no file this branch changes, no capital source list and no assessable-capital formula. #2788's legacy tariff tests set assessable capital directly, so the sale-expense valuation leaves them unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3DAwvyhPgY7sU1r3AiycF
uprating_indices.yaml grows owned_land_secured_debt with per capita GDP, but the growth factors page left it out of that list. The page's list now matches the index file's per capita GDP entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3DAwvyhPgY7sU1r3AiycF
|
Generated by Claude Code |
|
Ready for hub review Head:
Late writerBefore I started (03:23Z), at each push, and again before posting, Review of brief 1031's commitsI read every resolution in
Task 1's benefit unitOne person aged 70 with a £4,000 cash ISA, £3,000 of savings and a £100,000 second home carrying a £60,000 mortgage. By hand: the cash ISA moves to its holder at face value (4,000), savings count 3,000, and the home counts 100,000 − 10,000 − 60,000 = 30,000, so 37,000 in UC, HB, IS, JSA, ESA and PC. The merge's case in Council tax reduction's household route against #1969's valuationRun on hand-built households at the head (
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #1960.
The model now takes the statutory 10% for sale expenses, and any secured debt, off capital in Universal Credit, Housing Benefit, Income Support, income-based JSA, income-related ESA and Pension Credit. It counts savings and cash ISAs at face value. The helper floors each encumbered source at nil, so negative equity in one source can't reduce another.
Reproducer:
policyengine_uk/tests/policy/baseline/gov/dwp/capital_valuation.yaml::UC values a mortgaged holiday home as in ADM H1602,policyengine_uk/tests/policy/baseline/gov/dwp/capital_valuation.yaml::UC shares valued less sale expenses bring capital within the limit,policyengine_uk/tests/test_capital_valuation_properties.py::test_valuation_matches_the_regulation_and_never_adds_capital,policyengine_uk/tests/policy/baseline/gov/dwp/capital_valuation.yaml::A Lifetime ISA value given as an input is counted as given,policyengine_uk/tests/test_capital_valuation_properties.py::test_lifetime_isa_reformed_value_is_kept_as_storedThe law
The decision maker takes the 10% from gross value before debt, only where sale incurs expenses, and real property always has sale costs (ADM H1604–H1608). The decision maker then deducts only debt secured on that source (H1615–H1616). Each programme's parameters start from its existing capital-source list and cite the provision in its own instrument, including the later UC and ESA instruments.
What changes
capital.sale_expenses.rate: 0.1, an explicit list of sources, and its owncapital.round_downrule.valued_capitalapplies the deduction before secured debt, with float64 arithmetic.exact_amountrecovers an unambiguous whole penny from float32 storage below £131,072. It preserves other stored amounts. Above that boundary, original pennies can be ambiguous; the result can differ by a penny in either direction. This PR can't recover every digit that float32 storage lost before valuation.defined_formask through Core's entity mapping. It keeps the stored result outside the mask. Regressions cover mixed masked/counted people across all six means tests and UC eligibility at the £16,000 capital limit. Commitdbc0c587fcalculates the Lifetime ISA mask before its high-precision recomputation. It runs the formula only when at least one person applies and keeps Core's stored value outside the mask. The regression makeslifetime_isa_balanceraise when a reform masks everyone and checks capital for all six programmes against a run without a Lifetime ISA.cash_isaas well assavings. Its cash-only property checks their sum at face value. Direct source lookup still raises aKeyErrorfor a source the oracle omits; cash ISAs stay outside both the sale-expense and secured-debt mappings.share_like_capitalas the sale-expense source, andcorporate_wealthstays its backing household input. UC company-holding deductions useHOLDINGS_SOURCEconsistently, including pool and reported-capital budgets read throughexact_amount. Property oracles map the renamed source to the backing input.cash_isa_countable_capital,stocks_and_shares_isa_countable_capital) and subtract it from the household source that holds it (cash_isa,share_like_capital) before they allocate the rest. Each of the six formulas passesvalued_capitaleach household source less those balances (pooled_person_capital), so it values the remainder as before: less 10% wheresale_expenses.sourceslists the source, then less any debt secured on it.valued_person_capitalcounts the claimant's and partner's balances in their own unit and values each asvalued_capitalvalues its household source: a stocks and shares ISA balance less 10%, because all six lists nameshare_like_capital, and a cash ISA balance at face value. A pound of a stocks and shares ISA therefore counts at 90% whether it stays in the pool or moves to its holder.uc_assessable_capitalkeeps main's~coveredmask, so a reporting unit's claimant's and partner's ISAs stay in the pool, valued with it, and the formula subtracts the report.uc_assessable_capitaltakes a disregarded company holding off at its counted value. In its place, it adds the claimant's or partner's share of the company's capital (reg 77(2)), outside the sale-expense helper. Recorded financial totals and complete reported-capital overrides keep their existing distinct meanings.owned_land_secured_debtand deducts all three in every programme that counts the asset. UC counts no land, so the land input changes the five legacy means tests only. Each defaults to zero, anduprating_indices.yamllists each once.council_tax_reduction_assessable_capitalformula takes its own household route, on which it counts savings at face value and land and property other than the home less 10% and less the debt secured on them. This PR addsowned_land_secured_debtto that route'sSECURED_DEBT, so the formula deducts the debt secured on land, as councils do under SI 2012/2885 Sch 1 para 32(b) and its equivalents. The route floors a negative source or debt at nil, works in float32 and keeps fractions of a penny, wherevalued_capitaluses a negative savings, cash ISA or share-like source, or a negative debt, as given, works in float64 and rounds each valuation to the penny; both take the 10% before the debt and floor each encumbered source at nil. No test shows a wrong result from those differences, so this PR leaves them.Which sources take the 10%
share_like_capitalstocks_and_shares_isa_countable_capital)share_like_capitaland value it as that source, so the same limitation applies. Under #2131, the formulas value itemised ISAs without the 10%.Existing tests whose expected values move
test_isa_balances.py(main's Model the ISA subscription limits, with per-person ISA subscriptions and balances #2712): UC capital for a household with £1,000 of savings, a £3,000 cash ISA and a £2,000 stocks-and-shares ISA moves from £6,000 × growth to (1,000 + 3,000 + 2,000 × (1 − rate)) × growth, £5,800 × growth. The ISA reaches capital throughshare_like_capital, which UC values less its sale-expense rate.fc066bd31made this change.test_stored_household_totals.py::test_stored_household_totals_grow_past_the_projection_horizon(main's Keep stored household ISA totals after 2032 #2781): the same household, stored as household ISA totals. UC capital moves from 6 × savings (£6,000 in 2025) to savings + cash ISA + stocks-and-shares ISA × (1 − rate), 5.8 × savings (£5,800 in 2025), in every year from 2025 to 2040, for the same reason (UC Regulations 2013 reg. 49(1)(a)). The test reads each part and the rate from the simulation, checks that capital stays more than a penny below the three parts at face value, and still checks that capital keeps one ratio to savings in every year.person_isa_capital.yaml(main's Count each person's ISAs in their own benefit unit's capital #2839): seven cases count each stocks and shares ISA balance, and theshare_like_capitalleft in the pool, less 10%. For example, Case 3's adult child holds a £6,000 ISA inside £9,000 ofcorporate_wealth: the pool's £3,000 counts as £2,700, split £1,800 to the parents and £900 to the child's unit, which adds the ISA at £5,400, so UC capital moves from [2,000, 7,000] to [1,800, 6,300]. Cases 14 and 15 raise the household stocks and shares ISA totals to £17,777.78 and £6,666.67, so that 90% of each, rounded to the nearest penny, still lands on the £16,000 limit and the £6,000 threshold.test_person_isa_capital.py(main's Count each person's ISAs in their own benefit unit's capital #2839): the pound-counts-once checks valueshare_like_capital, and each stocks and shares ISA moved out of it, at each programme's sale-expense share, and allow each programme's penny rounding. The worked examples move with them: intest_person_balances_without_household_totals_count_with_their_holders, UC capital moves from [11,000, 9,000, 14,000, 11,000] to [10,666.67, 8,833.33, 13,800, 10,300] and Pension Credit's from 19,000 to 18,700. Intest_both_forms_in_one_dataset_add_up_to_the_stored_total, UC and Housing Benefit round each unit's capital to the nearest penny, so savings of £1,268.69 in 2032 split between two units as £634.345 each and come to a penny over the household's total; the test allows that penny.pension_credit_income.yamlCase 4 (main's Treat income derived from capital as capital in the legacy means tests #1995): the £55,370 let property counts less 10%, so capital moves from £55,825 to £50,288, deemed income from £92 to £81 a week (£4,212 a year) and guarantee credit from £7,592 to (238 − 81) × 52 = £8,164. The case follows main's Treat income derived from capital as capital in the legacy means tests #1995, under which the formula doesn't count the rent as Pension Credit income (the case cites SPC Regs 2002 Sch IV para 18); this PR's earlier version of the case counted it.test_savings_credit_only_receipt_properties.py(main's Treat income derived from capital as capital in the legacy means tests #1995): main gave the owner with capital £12,000 of savings and £4,400 of property, so that Pension Credit's assessment (£16,400) exceeds the £16,000 limit while council tax reduction's own route (£12,000 + £3,960 = £15,960) doesn't. With this PR, Pension Credit counts the property at £3,960 too, so the test also gives the owner £500 of shares (corporate_wealth), which Pension Credit counts at £450 and council tax reduction's household route leaves out. Pension Credit's capital comes to £16,410, the route's to £15,960, and the savings credit stays £621.82 a year (13 a week of deemed income).Review responses and integration
errstatedefined_for696ae34ad). Add mixed-person and UC-limit regressions. The v8 follow-up below also preserves Core's all-masked short circuit.cash_isasourceb168dc509). Keep direct lookup and existing tolerances.dbc0c587fevaluates the mask first and runs the formula only when someone applies. The new raising-dependency regression checks all six programmes.dbc0c587f)dbc0c587f: main's newtest_isa_balances.pyexpected a stocks-and-shares ISA at full value in UC capitalfc066bd31expects UC's sale-expense deduction on it: the ISA reaches capital throughshare_like_capital, which UC values less 10% until the data separate ISAs from shares. Under #2131, the formulas then value itemised ISAs without the 10%.b4e872273: the description namedc11d7c1d9and an open #2765 conflict (P2), plus three wording points (P3)b4e872273's merge of #2765 and the runs at that head. Correct the sentence on whatexact_amountcan't recover, nametest_isa_balances.pyas the mutated test, and cite ADM H1675 and reg 77(2) in brackets.646743859merges main at41fa5ddb5. The supplied-input registry retains both this PR's LISA entry and main'smonthly_domestic_energy_consumptionentry.d5c2a57e8ports Add overseas and other real estate to property wealth and capital #2688's company-capital conservation oracle correction from1193614a6. The file matches that source revision byte for byte and keeps main's claimant/partner roles. The oracle reflects stored-input precision, holdings-budget scaling, separately rounded valuations and company capital, and the sum of rounded benefit units. The pinned example yields £25.28 + £25.28 = £50.56. The port changes no production code or tolerance. All seven company-owner properties passed in v7's CI.5efb62cefmerges main at2d437ebba. Of 3,660 paths, onlypolicyengine_uk/data/uprating_indices.yamlchanged on both sides since41fa5ddb, and the merge commit's combined diff shows no hand-resolved hunk in it. The merged file keeps main's newcash_isa_balanceandstocks_and_shares_isa_balance, drops main's duplicatecash_isaandstocks_and_shares_isaentries, and keeps all three secured-debt inputs. It lists each of its 124 variables once, under 14 distinct indices. The merge keeps every one-sided change: 59 files from this branch and 123 from main.fc066bd31changes onlytest_isa_balances.py. Main's Model the ISA subscription limits, with per-person ISA subscriptions and balances #2712 (issue Model ISA subscription limits and per-person cash and stocks-and-shares ISA subscriptions #2710) added the test; the edit makes it expect UC capital of (1,000 + 3,000 + 2,000 × (1 − rate)) × growth, which comes to £5,800 × 1.07224 = £6,218.99 in 2027. It reads the rate from the parameters. The test still checks first that the stored household totals grow with savings.41fa5ddbleave the valuation alone. Model the ISA subscription limits, with per-person ISA subscriptions and balances #2712 changes howcash_isaandstocks_and_shares_isaread their values but not which sources the means tests count, and its subscription limits move no balance. Update the economic assumptions to the October 2026 EFO #2717 changes growth rates, not sources or deductions. Compare property allowance routes on only the households with a choice #2732's household subsets slice every stored array and_model_valuesto the kept households, and its tests, which cover the ancestor walk thatsupplied_inputuses, pass here. Make Pension Credit and pension-age HB projections safe under reforms #2092, Limit Housing Benefit childcare to qualifying charges and earnings residuals #2229 and Build the module-release test's systems with automatic GC off #2716 touch no capital code.30d48c01bmerges main at2da212abc. Onlyuprating_indices.yamlconflicted. The merged file keeps main's move ofother_investment_income,savings_interest_incomeandnon_cash_isa_cash_interesttoper_capita.savings_incomeand main's new company-car andincome_not_otherwise_chargedentries. It addsowned_land_secured_debtunderper_capita.gdp, next toowned_land, and lists each of its 128 variables once, under 15 indices. Against main's file, the only added line isowned_land_secured_debt.corporate_wealth, had £588.70 of UC and no top-up on this PR's old base, £1,411.30 worse off. At the merge the family counts £15,300 of capital, gives up the award and takes the £2,000 top-up. In eight cases, UC, Tax-Free Childcare and Scottish Child Payment together never fall below main at the merge.3a3241cf6corrects theowned_land_secured_debtdocumentation, which named UC. It changes no calculation.30d48c01b54532603c0fad233a30935adab9280c, and that documentation commit follows it.ba4de95d6merges main at0080274d78e2b48e57682ac6a035fda6e11334e9, 86 commits after2da212abc, Keep stored household ISA totals after 2032 #2781 among them. Git merged it with no conflict. Onlypolicyengine_uk/data/uprating_indices.yamlchanged on both sides since2da212abc; against main's file, the merged file adds onlyowned_land_secured_debt.c11d7c1d9changes onlytest_stored_household_totals.py, which main's Keep stored household ISA totals after 2032 #2781 added: it now expects the stocks-and-shares ISA in UC capital less the sale-expense rate (see "Existing tests whose expected values move"). Main's other test changes since2da212abcread no means-tested capital variable.b4e872273merges main at52b30809ff5681ebfede4d559e72a44f4c893cd2, which includes Add a trading allowance claim status, so allowance reforms reach claimants without turnover data #2765. Git stopped on one hunk inSUPPLIED_INPUT_VARIABLES(policyengine_uk/utils/supplied_inputs.py), where both PRs added a name at the same place. The merge keeps this PR'slifetime_isa_countable_capitaland Add a trading allowance claim status, so allowance reforms reach claimants without turnover data #2765'smiscellaneous_income_trading_allowance_deduction. Main's other changes since0080274d7name no means-tested capital variable or parameter.154f92286merges main ataf9361114425a1457545503f2801c68fc6ed5d47, which includes Count each person's ISAs in their own benefit unit's capital #2839 (d3c06225d) and Treat income derived from capital as capital in the legacy means tests #1995 (8717d5a26). Git stopped on eight files: the six assessable-capital formulas,pension_credit_income.yamlandtest_savings_credit_only_receipt_properties.py. Each formula combines the two changes as "What changes" describes, and the sixcapital/sources.yamllists, which git merged, keep every entry from both sides. The two test files keep both sides' cases and work each moved value by hand (see "Existing tests whose expected values move"). The merge also values the stocks and shares ISA balances thatvalued_person_capitalcounts as their household source, moves main's person ISA tests to the 10%, addsowned_land_secured_debtto council tax reduction's household route, and adds two cases. Incapital_valuation.yaml, one benefit unit with a £4,000 cash ISA, £3,000 of savings and a £100,000 second home carrying a £60,000 mortgage counts £3,000 + £4,000 + (£100,000 − £10,000 − £60,000) = £37,000 in all six programmes. Incouncil_tax_reduction_capital_valuation.yaml, £50,000 of land carrying a £20,000 debt counts £50,000 − £5,000 − £20,000 = £25,000 on council tax reduction's household route; without theSECURED_DEBTentry the case gives £45,000 and fails.76242a05bchanges onlytest_person_isa_capital.py:test_both_forms_in_one_dataset_add_up_to_the_stored_totalallows the penny each unit's nearest-penny rounding adds.3c395c3e4merges main at95dfc62f818058007f28e42d7c550ad00578eaef. Git merged it without conflict. Main's Read a period after a quoted reproducer id as the sentence's end #2744, Gate supplied UC latent deduction rates on uc_has_deduction #2760, Classify the Budget helper variables in the fiscal partition #2763, Pay the 2022 £150 to Council Tax Reduction recipients in any band in Scotland and Wales #2768, Document why the model leaves out Great Britain's Alternative Fuel Payment #2769, Refuse unusable target changes when calibrating reforms #2786, Apply the 2020-21 SDLT relief dates and temporary lease bands #2787, Apply the £10,000 accommodation threshold to legacy tariff income #2788, Assess Oxford Universal Credit applicants on Appendix 3 income #2794, Build the budget totals from the programme registry #2809 and Read only the claimant's and partner's Working Tax Credit for reg 60A #2810 change no file this PR changes, no capital source list and no assessable-capital formula. Apply the £10,000 accommodation threshold to legacy tariff income #2788's legacy tariff tests set assessable capital directly.3dbdb0027addsowned_land_secured_debtto the per capita GDP list on the growth factors page, which now matchesuprating_indices.yaml's per capita GDP entry.59a1c4ad2rewords two sentences of the changelog fragment and changes nothing else.ce91e92ea) merges this PR atb4e872273and expects the stocks-and-shares ISA at face value in the stored-totals test.git merge-tree --write-tree --name-only ce91e92ea 59a1c4ad2stops ondocs/book/assumptions/growthfactors.mdand onuc_assessable_capital.py's documentation string. One more change won't show as a conflict. Value share-like capital by asset type for the sale-expense deduction #2131 replacesshare_like_capitalin every programme'ssourceswithshare_like_capital_with_sale_expensesandshare_like_capital_without_sale_expenses, and main'scounted_person_sourcescountsstocks_and_shares_isa_countable_capitalonly whilesourceslistsshare_like_capital(HOUSEHOLD_SOURCE_OF). On that merge the formulas stop counting stocks and shares ISA balances in their holders' units and leave them in the pool: with the two documentation conflicts resolved to this head's text,person_isa_capital.yamlfails 10 of 21 cases andtest_person_isa_capital.py24 of 32 tests. When Value share-like capital by asset type for the sale-expense deduction #2131 takes this head, it needs to count those balances against the source that holds them, for example by mappingstocks_and_shares_isa_countable_capitaltoshare_like_capital_without_sale_expenses, which holds the itemised stocks and shares ISAs, and to expect the balances at face value in main's person ISA tests.Validation
We ran each command below on its own at
3dbdb00276578089c68949b31658239386af9420, on a clean checkout afteruv sync --frozen --extra dev, and loaded no survey data. The current head,59a1c4ad217b3d054bab75dfa7388186ffd89f5b, changes only the changelog fragment from it.uv run --frozen policyengine-core test policyengine_uk/tests/policy/baseline/gov/dwp -c policyengine_ukuv run --frozen policyengine-core test policyengine_uk/tests/policy/baseline/finance/benefit/family -c policyengine_ukuv run --frozen policyengine-core test policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction -c policyengine_ukuv run --frozen pytest -n 4 policyengine_uk/tests/test_capital_valuation_properties.pyuv run --frozen pytest -n 4 policyengine_uk/tests/test_stock_capital_periods.pyuv run --frozen pytest -n 4 policyengine_uk/tests/test_uc_property_capital.pyuv run --frozen pytest -n 4 policyengine_uk/tests/test_uc_property_capital_mock.pyuv run --frozen pytest -n 4 policyengine_uk/tests/test_person_isa_capital.pyuv run --frozen pytest -n 4 policyengine_uk/tests/test_savings_credit_only_receipt_properties.pyuv run --frozen pytest -n 4 policyengine_uk/tests/test_stored_household_totals.pyuv run --frozen pytest -n 4 policyengine_uk/tests/code_health.github/check_fix_pr.pyon this title and body, aspr_fix_evidence.yamlruns it, with the diff from the merge base95dfc62f8uvx ruff@0.17.2 format --check .uvx ruff@0.17.2 check .anduvx ruff@0.17.2 check --select F811,F821 policyengine_ukgit diff --check b4e872273..3dbdb0027git merge-tree --write-tree --name-only 59a1c4ad2 origin/main, withmainat040e9a5f0Without
owned_land_secured_debtin council tax reduction'sSECURED_DEBT, the land case incouncil_tax_reduction_capital_valuation.yamlgives £45,000 against £25,000 and fails. CI at59a1c4ad2passed every job, including the seven Python shards, the YAML job andTest / Result.A review of
b4e872273c4695cf728d0d2811670b7300504ba4ran these checks afteruv sync --frozen --extra dev, one command at a time, with no survey data.uv run pytest -n 4 policyengine_uk/tests/test_stored_household_totals.pyuv run pytest -n 4 policyengine_uk/tests/test_isa_balances.pyuv run pytest -n 4 policyengine_uk/tests/test_capital_valuation_properties.pyuv run policyengine-core test policyengine_uk/tests/policy/baseline/gov/dwp/capital_valuation.yaml -c policyengine_ukuv run pytest -n 4 policyengine_uk/tests/code_health.github/check_fix_pr.py, aspr_fix_evidence.yamlruns ituvx ruff@0.17.2 format --check .,ruff check .,ruff check --select F811,F821 policyengine_ukgit diff --check 3a3241cf6..b4e872273CI at
b4e872273passed every job, including the seven Python shards, the YAML job andTest / Result.Local runs at
c11d7c1d92faeab80bf37a3019463f0b4ecbc103, afteruv sync --frozen --extra dev, one command at a time. We loaded no survey data and skipped no test.uv run pytest -n 4 policyengine_uk/tests/test_stored_household_totals.pyuv run pytest policyengine_uk/tests/test_capital_share_components.py::test_capital_matches_the_original_listsuv run pytest -n 4 policyengine_uk/tests/test_capital_share_components.py --deselect …::test_capital_matches_the_original_listsuv run pytest -n 4 policyengine_uk/tests/test_capital_valuation_properties.pyuv run pytest -n 4 policyengine_uk/tests/test_isa_balances.pyuv run pytest -n 4 policyengine_uk/tests/test_pension_credit_reported_capital_properties.pyuv run pytest -n 4 policyengine_uk/tests/test_savings_credit_only_receipt_properties.pyuv run pytest -n 4 policyengine_uk/tests/test_stock_capital_periods.pyuv run pytest -n 4 policyengine_uk/tests/test_uc_company_override_properties.pyuv run pytest -n 4 policyengine_uk/tests/test_uc_company_owner_properties.pyuv run pytest -n 4 policyengine_uk/tests/test_uc_property_capital.pyuv run pytest -n 4 policyengine_uk/tests/test_uc_property_capital_mock.pyuv run pytest -n 4 …/universal_credit/test_uc_capital_allocation.pyuv run policyengine-core test <file> -c policyengine_ukfor the 12 YAML files this PR adds or changes and every other*capital*.yamlfile under the UC, HB, IS, JSA, ESA and PC tests andhousehold/wealth(22 files)uv run pytest -n 4 policyengine_uk/tests/code_healthuvx ruff@0.17.2 format --check .,ruff check .,ruff check --select F811,F821 policyengine_ukgit diff --check 3a3241cf6..HEADAt the merge commit without the test change,
test_stored_household_totals_grow_past_the_projection_horizonfails at line 222 with £5,800.00 against £6,000.00 ± 0.06; it passes on main at0080274d7. When we set UC's sale-expense rate to 0 in a scratch copy, the edited test fails (capital of £6,000.00 doesn't fall below the £6,000.00 face value) and main's version passes; once we restore the rate, the edited test passes.A review of the merge at
30d48c01breran the changed tests one file at a time, and every test that finished passed.30d48c01btest_capital_valuation_properties.pytest_capital_share_components.pytest_uc_property_capital.pyandtest_uc_property_capital_mock.pytest_uc_company_owner_properties.pyandtest_uc_company_override_properties.pytest_lifetime_isa_capital.pyandlifetime_isa_capital.yamltest_uc_tax_free_childcare_choice.pyand the two Tax-Free Childcare YAML filestest_input_records.pytest_projection_horizon.pytest_fiscal_partition.pyandtest_aggregate_impact_partition.pyThree files hit local time caps under host load before finishing:
test_household_subset.py,test_housing_benefit_accommodation_dates.pyand the pairtest_isa_accounting.pyandtest_wealth_components.py. None of those that ran failed, and CI ran them all at3a3241cf6and passed.An earlier review (v10) ran these checks against
fc066bd318f2e059623ab30df56985e3605e24d0, one file at a time, and every unmutated test passed.test_isa_balances.pytest_wealth_components.pytest_capital_valuation_properties.pytest_lifetime_isa_capital.pytest_household_subset.py(main's #2732)git grep -lfinds namingcash_isa,stocks_and_shares_isa,share_like_capitalorcorporate_wealthlifetime_isa_capital.yamlshare_like_capitalto within 2.8p of penny roundingThe probes cover UC, HB, PC, IS, income-based JSA and income-related ESA in 2025, 2027, 2032 and 2033. They use four kinds of data: stored household ISA totals, person balances, person balances with a Lifetime ISA, and
corporate_wealththat already holds the ISA. Each programme counts savings and cash ISAs in full, takes 10% offshare_like_capital, and counts a Lifetime ISA once, throughvalued_person_capital. No source counts twice.The review made four mutations in place on
test_isa_balances.py, and restored the file after each:share_like_capitalfailed it at £4,288.96 (£4,000 × growth).share_like_capitalfrom UC's sale-expense sources failed it at £6,433.44 (£6,000 × growth).capital_valuation.yamlfailed 8 cases.cash_isaandstocks_and_shares_isasum person balances throughadds, so after the 2032 projection horizon main loses both on a dataset that stores only the household totals, and this PR leaves that as it stands. In the 2033 probe, main and this PR both count £1,310.81 of UC capital, the savings alone, where the stored totals give £7,602.69. policyengine-uk-data's Enhanced FRS writes neither total, but Microcosm's UK exports store both, so their runs for 2033 and later lose them. #2740 tracks it: #2712 replaced the totals'upratingattribute withadds.CI at
3a3241cf6passed: both required checks, all six Python shards and the YAML job.Impact on the certified data
The aggregate-impact job at
59a1c4ad2compared main47a2817e2with91591cf69, which merges59a1c4ad2into that main, both onenhanced_frs_2024_25.h5(policyengine-uk-data 1.58.1). The job passed: no check broke,sign:vatfails on both sides, and the head fixes no failing check.† The report rebuilds these totals without the Disabled Students' Allowance figure, which it withholds.
The model now assesses less capital, so it pays the same or more of each of the six benefits in every year. The report shows 0.0% of people losing over £1 in every year, and every base-run decile gains or holds. The moves the other way follow from higher awards:
council_tax_reduction/_legacy.py:50-53), so a larger award lowers it.universal_credit_pre_benefit_capabove nil (tax_free_childcare_program_eligible.py;disqualifying_benefits.yaml), unless the family gives up a smaller award throughforgoes_universal_credit_for_tax_free_childcare.tv_licence_free_licence_share.py).attends_private_school.py).The targeted childcare entitlement moves only in 2031-32: a UC award above nil gives a family one route to it (
meets_universal_credit_criteria_for_targeted_childcare_entitlement.py).share_like_capitalcan also hold unit trusts and stocks-and-shares ISAs, so these aggregates take 10% off some sources whose legal treatment differs.Coordination
share_like_capitalin programme lists and retaincorporate_wealthonly as the backing input or an explanation of it.1193614a6).axiom: TheAxiomFoundation/rulespec-uk#395 queued
🤖 Generated with Claude Code