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 <[email protected]>
- 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 <[email protected]>
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 <[email protected]>
|
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
|
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 <[email protected]>
£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 <[email protected]>
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 <[email protected]>
|
Merge-order note from #1974's owner. #1974 (head 6600477, main a8b2848 merged) is being finished for the Budget cut. If it lands first, this PR's next merge of main needs the following, or the 10% sale-expense deduction silently stops applying to shares. #1974 renames the share-like source in all six capital Rename in this PR.
Tests.
If this PR lands first instead, #1974 does the same reconciliation when it merges main. #2131 is then rebuilt on whichever head results. 🤖 Generated with Claude Code |
Reg 77 holdings are shares with sale expenses, so HOLDINGS_SOURCE is share_like_capital_with_sale_expenses: the holdings budget and the 90% counted share both read it, where #1969 read corporate_wealth. The test file keeps the round-3 fixes (projected years, the 16,000 overshoot, the power-of-two precondition, the grouping example, the exempt list's start). Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sol review v5 at b3f6f60: - exact_amount raised an underflow warning on zero inputs, failing test_warning_filters. Errors are now ignored inside np.errstate, and twice the gap is compared with the spacing. - IS, JSA and ESA read household values through benunit.max, which is float64, so exact_amount used float64 spacing and never removed float32 storage error: 16,000.01 of savings floored to 16,000.00, at the limit. A value equal to its float32 is now judged at float32 spacing. - From 131,072 float32 cannot hold every penny, so no penny is identified and the stored value is kept; rounding down then never goes against the claimant. - The Lifetime ISA's 75% and UC company capital are worked in float64 from the stored amounts; company capital is rounded under reg. 6(1). - test_uc_capital_allocation expected exact conservation; each share is now its own nearest-penny amount (1.00 three ways is 0.33 each). - Docstrings: the guard's intended tolerance; no report leaves a holding in the pool. Tests: a model-level property that every programme counts whole-penny savings, shares and Lifetime ISA balances to the penny; widened-input and above-131,072 helper checks; YAML for 16,000.01 of savings under IS, JSA and ESA and a 1,000.04 Lifetime ISA. Co-Authored-By: Claude Opus 5.5 <[email protected]>
#1974 renamed the share-like capital source from corporate_wealth to share_like_capital. The six sale-expense lists, the three holding valuations (counted_share) and the two holding budgets now name it through HOLDINGS_SOURCE, so shares keep the reg. 49(1)(a) deduction. The sale-list guard now also requires share_like_capital in each list, the differential's original lists rename the sale-expense lists too, and a components-only household counts 1,000 + 90% of 12,000 = 11,800 under UC. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…s rule The engine stores lifetime_isa_countable_capital as float32, so 75% of a whole-penny balance that ends in half a penny (75% of 0.26 is 0.195) was read back just below it and rounded the wrong way under UC and HB: 0.26 of LISA and 15,999.81 of savings gave UC capital of 16,000.00, eligible, instead of 16,000.01. valued_person_capital now works a LISA's surrender value out in float64 from the balance and rounds each person's to the penny under the programme's rule, like any other valuation, in all six means tests. The whole-penny property draws any whole-penny balance, with the half-penny cases as examples, and two YAML cases pin the limit case and per-partner rounding. exact_amount's docstring no longer claims that rounding down never goes against the claimant above 131,072: a figure built from a stored value there can be a penny either way. The float32 cast moves inside errstate. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
UK hub: adopting this PR to finish it. Its owner session (CLI 8279ead2) stopped on 25 Oct at 00:02Z, after a weekly-limit stop, and can't be reached. Its last plan was to push, refresh the impact from CI and hand the PR to the hub. What the owner left. None of it was pushed. On 27 Oct at 19:50Z the hub took a snapshot of the work; the owner's worktree is untouched.
Next. A Subfleet build commits those edits and merges current main. It also ports #2688's oracle correction (1193614), which this PR needs once main's couple-role change lands. It then reruns the capital, company and property suites and pushes fast-forward to this branch. After that, an independent review of the delta from 9b9ef66 runs, and the PR lands on the usual gates. #2131, #2688 and #1995 follow it. 🤖 Generated with Claude Code |
Reconstruct the baseline surrender value in float64 only when the active formula is the baseline function and no input was supplied for this period and visible branch. Numeric equality with a float32 formula result cannot establish provenance: it can discard a supplied whole penny. Read the active variable from the tax-benefit system, since an existing holder can retain a definition from before a reform. Reuse supplied-input tracking and cover explicit inputs, float32 collisions, replacement and parameter reforms, late inputs, periods and branches. Reuse the existing independent-clone test fixture for the capital property suite. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Retain main's claimant and partner role corrections alongside the programme-specific capital valuations and penny rounding. Resolve the supplied-input registry hunk by retaining both the Lifetime ISA entry and main's monthly domestic energy consumption entry. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Port of #2688's 1193614. Model stored-input precision, the raw holdings budget scale, separately rounded share and holding valuations, each owner's company capital and each benefit unit's final capital. Sum the rounded benefit units for the household expectation under UC regulation 6(1). Pin the original CI witness and the holdings-budget precision boundary, while preserving main's explicit claimant and partner roles. Production calculations and comparison tolerances are unchanged by this port. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
UK hub: pushed d5c2a57, a fast-forward from 9b9ef66. These are the owner's two unpushed commits plus three from the hub's adoption build:
Validation so far:
🤖 Generated with Claude Code |
Main's ISA fix (feb50e4, merged here in 6467438) added cash_isa to every means test's capital sources. The property file's households had no cash_isa input, so the differential and the fixed Housing Benefit units raised KeyError: 'cash_isa' when they read each source. Households now draw a cash ISA balance. The cash-only property holds savings and a cash ISA, both deposit balances (ADM H1675), and checks each programme counts the two in full, so a source list that drops cash_isa fails it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
The float64 recompute called the baseline LISA formula directly, so a reform that only adds a defined_for mask (keeping the baseline formula) still counted the ISA where Core stores the default. A masked 0.26 ISA then added 0.20 to Universal Credit capital, and with 15,999.81 of savings made the claimant ineligible (v7 review, P2-1). Apply the mask the way Core does: where the defined_for variable, mapped to the person, is above zero, keep the float64 value; elsewhere keep the stored value, which is Core's default. New tests cover a mixed masked/counted pair across the six means tests and the UC eligibility case at the limit; both fail on the previous helper. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Core computes a variable's defined_for mask first and, when it applies to nobody, stores the default without running the formula. The exact float64 valuation ran the formula before masking, so under a reform that masks everyone it calculated dependencies Core never needs, and could fail where Core returns zero. It now works out the mask first and skips the formula when nobody is applicable. A regression gives the balance a formula that raises and checks every programme's capital. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
Pushed
Local runs, each under a 4 GB RSS cap at
Next: a v9 delta review (GPT-6.1 Sol) reruns v8's nine mask probes and its provenance probe at this head, runs three mutations, and drafts the final body. Merging waits: on 28 October Vahid asked for no automatic agent merging, and the hub holds every merge until that is resolved. 🤖 Generated with Claude Code |
Brings in main through 2d437eb, including #2710's per-person ISA balances (3d5e7cc). The merge has no conflicts. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…pital Main's test_isa_balances expected Universal Credit capital to count a stored stocks-and-shares ISA at its full projected value. This branch values share_like_capital, which carries that ISA, less UC's 10% sale-expense rate until the data separate ISAs from shares (see the sale_expenses.sources description), so the merged test failed with £6,218.99 against £6,433.44: £5,800 rather than £6,000 times growth. The test now reads the rate from the parameters. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
UK hub: merged main and fixed one test it brought in. Head CI at Why: the test counts £1,000 savings, a £3,000 cash ISA and a £2,000 stocks-and-shares ISA, all projected by the same growth (1.07224 in 2027). This PR values Commits:
Local runs on the merged tree:
A delta review is running. The merge into 🤖 Generated with Claude Code |
Co-Authored-By: Claude Opus 5.5 <[email protected]>
UC lists no land among its capital sources, so the land-debt input changes the five legacy means tests only. Co-Authored-By: Claude Opus 5.5 <[email protected]>
#2131 last merged #1969 at b3f6f60. The merge brings in #1969's float64, penny-rounded valuation, Lifetime ISA surrender values, cash ISAs in every capital list, the land secured-debt input and main at 2da212a. Conflicts and how they were resolved: - Six sale-expense lists: #1969 renamed corporate_wealth to share_like_capital; this branch names share_like_capital_with_sale_expenses. Kept this branch's lists (land, both property sources and the part with sale expenses) and descriptions, and restored #1969's note that an unitemised corporate_wealth still folds in unit trusts, ISAs and, on older datasets, pension wealth. Savings and cash ISAs stay out of every list. - UC capital/sources.yaml: savings, cash_isa (from #1969) and both share-like parts. - household_uc_pool_company_holdings, household_uc_reported_financial_capital and uc_assessable_capital: #1969's code (exact_amount, valued_person_capital, penny rounding, the recorded-total consumption rule) with this branch's wording: a reg. 77 holding sits in, and is budgeted against, the part with sale expenses (HOLDINGS_SOURCE). - test_capital_share_components.py: this branch's version, which already carries #1969's 11,800 and 27,000 expectations and replaces each #1974 test #1969 adapted with its split equivalent. - test_capital_valuation_properties.py: #1969's oracle (asset() lookup, cash ISAs generated, per-person LISA rounding) with the split mapped into it: the part with sale expenses reads corporate_wealth, the part without is nil. - growthfactors.md: #1969's text and savings-income section, with the per-capita GDP row as the union of both sides less other_investment_income and savings_interest_income, which main moved to per_capita.savings_income. Long description lines in five legacy capital lists are wrapped, and Pension Credit's list description names the two parts. Co-Authored-By: Claude Opus 5.5 <[email protected]>
#1969's fc066bd made main's test_isa_balances.py expect UC's 10% on a stored stocks-and-shares ISA total, because the ISA then reached capital through share_like_capital, which #1969 values less 10%. With the split, an itemised ISA sits in share_like_capital_without_sale_expenses and counts at its withdrawal value (ADM H1656), so UC capital is (1,000 + 3,000 + 2,000) x growth: 6,000 x 1.07224 = 6,433.44 in 2027. A new parametrised test pins the person-balance route in all six means tests: a £1,000 saver with a £3,000 cash ISA and a £2,000 stocks-and-shares ISA has £6,000 of capital, the ISA wholly in the part without sale expenses. The changelog fragment loses its leading list marker, which towncrier would render as a double bullet. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Fixes #1960.
Apply the statutory 10% sale-expense deduction and secured debt when valuing capital for Universal Credit, Housing Benefit, Income Support, income-based JSA, income-related ESA and Pension Credit. Savings and cash ISAs remain at face value. The helper floors each encumbered source at nil so negative equity in one source cannot 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). Parameters start with each programme's existing capital-source list. Each programme uses 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 cannot recover arbitrary precision 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 exposes a source omitted by the oracle as aKeyError; 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.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.Which sources take the 10%
share_like_capitalReview 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. #2131 then values itemised ISAs without the 10%.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 as property components, and count UK land once in household land #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 is £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.Validation
An independent Opus 5.5 review of the merge and a separate run of the changed tests covered
30d48c01b, one file at a time. 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 independent review (v10, Opus 5.5) ran these checks against
fc066bd318f2e059623ab30df56985e3605e24d0, one file at a time. 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 ran four scratch mutations on the edited test, made each in place, and restored it byte for byte, checking SHA-256 before and after:
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.The review ran model commands one at a time under a 4 GB and 1,500-second cap, ran mutations under 2 GB, and loaded no survey data.
CI at
3a3241cf6passed: both required checks, all six Python shards and the YAML job.Impact on the certified data
The aggregate-impact comment, updated at 2026-10-31T14:10:13Z, compares main
2da212abcwith2eb144a64, which merges3a3241cf6into that main. The workflow run reports3a3241cf6as its head, and both sides useenhanced_frs_2024_25.h5(policyengine-uk-data 1.58.1). The job passed: no check broke,sign:vatfails on both sides, and none got fixed.† The report rebuilds these totals without the suppressed Disabled Students' Allowance figure.
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