Repository navigation
Port the uk-data wave to policyengine-uk 2.134.4: stamp duty, Move to UC, national home values (sixth #1095 PR) - #1308
juaristi22 wants to merge 18 commits into
Conversation
732131e to
306bc11
Compare
Independent adversarial review of this PR at 732131eRun with Claude Code on 16–17 October 2026 at 732131e: seven independent review lenses (correctness, method, generated artifacts, tests, claims against the diff, disclosure, a second fresh-eyes pass), then one to three skeptics per finding who tried to refute it; (k/n) is how many agreed. No builds and no feed-gated tests were run. The branch was force-pushed to 306bc11 during the review (policyengine-uk relocked to 2.134.4; the stage code is unchanged), so every finding below applies to 306bc11 except the 2.134.5 lock finding and the E1 nit; no tests were run at 306bc11. The force-push rewrote every commit from E1 on: the reviewed-head commits b355aad, e5bee83 and 21cb5e0 cited below are 34a5526, a6c9758 and 908f6a3 on the live head. Leave this PR in draft. The stages are faithful ports and the published-statistics arithmetic checks out exactly. What blocks it is in the code, not the method:
Separately, the frozen build will be refused by the release-blocking local compile-parity gate unless someone regenerates that receipt on the final head (X-s01, see Cross-PR). Blocking
Should fix
Minor
Cross-PR
Disclosure check
Tests and tools runAll runs were at 732131e unless noted. No tests were run at 306bc11.
Checked and found sound
Refuted during verification
Not covered
🤖 Generated with Claude Code |
On main after #1302: 25,327 compiled cells. The 18 Scottish BRMA rows are ledger-only by construction, and no signed value moves. The UC drift rationales now read their fixture/ours bands off the rows, and the support floor's deferred cells carry their own signed rationale. The release-blocking preflight gate uk_ledger_compile_parity_local_incumbent_2025 reads this receipt, so whichever of #1305, #1306, #1307 and #1308 lands last regenerates it on the combined tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
306bc11 to
8739557
Compare
…gets (#1095) Review of #1308: purchases_outside_sdlt_regions_weight was the raw weighted total of Scotland's and Wales's purchasers, and on the national spine the non-residential cell rests on fewer than ten source households; the fitted value, the shortfall, the event rate, the scale and the eligible owner weight were floats whatever their support. Every weighted field now goes through receipt_counts.small_cell_share on the distinct household_source_id values behind it, so one to nine sources read "<10"; the share at the stock cap appears only where neither the capped purchasers nor the rest rest on fewer than ten, and the capped support is an extreme_count band. Nothing was staged or uploaded with the old field. Tests: a cell of three outside sources and a fit region of five sources read "<10"; a capped side of two sources hides the share; the stage test now requires positive purchases and fitted transactions and value for both kinds (a nil target branch passed it before); and the packaged HMRC rows reproduce uk-data#573's household targets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1308: regional_home_values banded its capped cell on rows, and support copies from high_value_home_support repeat their source household, so a cell past ten rows could rest on fewer than ten sources. The cell is now counted on distinct household_source_id values (source_count, as the purchases stage counts them) and reported as sources_at_cap; the row totals go through receipt_counts.rounded_count. A test bands twelve copies of two households as "<10". No figure leaked: the cell is latent on the head spine, and the receipt is build output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…receipt (#1095) Review of #1308, with María's ruling of 2026-10-17: p, the share of a combination's drawn units that would claim anyway, pooled Great Britain and Northern Ireland, while DWP's Move to UC rates cover Great Britain only. p is now measured over Great Britain's units, and the probability applies to the combination's units in Northern Ireland too, as the Pension Credit take-up redraw does. Where p exceeds DWP's rate the probability is 0, and the receipt now flags the combination (rate_unreachable), never p itself, and only where ten or more source households carry it. Each combination's support is banded on distinct household_source_id values, not rows, since support copies repeat their source; the aggregates cover Great Britain only and go through receipt_counts.small_cell_share. The texts say that the share reaches DWP's rate in expectation where p is at most r, and declare the two limits uk-data#534 has: the drawn cohort includes units on the Pension Credit route, whose legacy benefits policyengine-uk does not close, and DWP's rates count every household sent a notice. The vendored resource now maps to the spine's 2024 build period. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1308: an operand that sums several cells was checked on its total match count only, so two facts for one listed member and none for another compiled, and a list of three members declared with a count of two passed when one was missing. An operand that sums cells now names them in exactly one list-valued selector field of expected_member_count distinct members, and each member must match exactly one fact. obr.sdlt compiles unchanged (each of its four HMRC record ids matches once in abf0921). Two tests cover the 2+0 case and the mismatched list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) Review of #1308, with María's ruling of 2026-10-17 to declare the HRAD allocation as uk-data#573 does: - "Receipts are checked against HMRC, never fitted" described a check that does not exist. The stage fits transactions and value only; households' SDLT is fitted at build level through obr.sdlt, and the texts now say so, and that uk-data#573's 30% higher-rates SDLT test is not carried over. - Households' HRAD is not published, so the allocation by individuals' shares of all Table 8a residential transactions is an assumption, as uk-data#573 says; its household lower bounds are 87,200 transactions and GBP 33.28bn. The texts declare that it probably overstates households' purchases, since nearly all receipts at or below the GBP 250,000 nil-rate band are surcharge and other buyers' receipts there imply more higher-rates transactions than their overall share. - obr.sdlt's notes declare two gaps it does not correct: Table 6b counts the higher rates before replacement-home refunds, which policyengine-uk never gives, while Tables 8a and 8b and the OBR line are net; and the engine's main-home purchase rate also counts the higher-rates transactions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1308: the engine freeze (María's ruling of 2026-10-16) was held by uv.lock alone; the UK extras accept any later release, and the spine build and the calibration only recorded the installed version. assert_installed_engine_is_pinned compares it with the version the engine pins were taken from and refuses a mismatch, at the spine build's engine and at the calibration's simulation factory. Tools that re-pin or regenerate reports keep their own engines, and an environment without policyengine-uk is left to the callers' own import errors. A test covers the match, a later release and the absent engine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Reply to the review. Thanks for it. It is addressed at Blocking
Should fix
Minor
Cross-PR
🤖 Generated with Claude Code |
Re-review of this PR at 8739557Run with Claude Code on 17–18 October 2026, after the rebase onto 1f1cfa6, the relock to policyengine-uk 2.134.4, the dropped N2, the six fix commits and the reply.
VerdictMost fixes hold, in code:
Tests: 1,244 engine-free and 214 engine tests pass. The engine run, on policyengine-uk 2.134.4, covers the whole engine-uk list including H2 parity. All the Two things block, and the savings-interest renewal is now time-critical. Blocking
Timeline: the savings-interest renewal (R0)
Low
Nits
First-round dispositions
Cross-PR
Disclosure checkNo figure in the 13 commit messages, the added lines, the body or the reply breaches the output rules. Every figure in the body is one of:
The "about 81%" non-residential fit rests on 30 or more source households. The body's disclosure line overstates the banding until the first Blocking item is fixed. Tests and tools run
🤖 Generated with Claude Code |
#866) The ons.savings_interest_income measure exclusion lapses on 2026-10-22. After that date no national calibration could run, since the window is checked when the exclusions are applied. The row stays a measured diagnostic and is never fitted, as ruling R3 of 2026-09-22 set: the ONS D.41 row is a national-accounts concept, while the model carries cash interest, and the SPI interest rows are the fitting anchor. Renewed by juaristi22 on 2026-10-16, folded into the sixth #1095 ports PR. The packaged-exclusions test pins the new window, the renewal note and the entries approved on 2026-10-16. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The UK lock moves from 2.132.6 to 2.134.4, and the three packages' UK extras require it. policyengine-core stays at 3.33.3 (UK) and 3.32.5 (US); 2.134.4 asks for core >=3.32.27. Nothing the build writes is renamed, removed or re-typed. Two inputs join the engine and stay uncovered here (coverage 300 to 302): 2.134.1 turns additional_residential_property_purchased and non_residential_property_purchased into inputs that default to nil (pe-uk#2241), which the stamp-duty commits of this PR supply. 2.134.3 starts Scotland's top rate at the statutory 125,140 of taxable income (pe-uk#2437), so the rate-class docstring and the salary-sacrifice fragment no longer say it files advanced-rate relief as additional. 2.134.0 makes a realisation elasticity of 1 the default response to a CGT reform (pe-uk#2419): the CGT taxable-income lockstep test inverts the tax under a measurement reform, so that reform now switches the response off. No build path runs a parameter reform, so the build is unaffected. The lock stops at 2.134.4 (María's ruling of 2026-10-16). 2.134.5 (pe-uk#2240) limits pension relief to relevant earnings and charges the annual allowance with a new unused-allowance input at nil; on the national spine it moves Universal Credit awards and income tax for households with pension contributions, and the solve fails the calibrated-seam weight-ratio gate. It waits for a follow-up that supplies the input. Re-derived: the uprating pins (version stamp only), the concept golden and report, the texts that cite the locked engine, the H2 fixture's dependency, the coverage manifest's source digests and the lock hash. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#1095) From policyengine-uk 2.134.1 (pe-uk#2241) both purchases are inputs that default to nil, so a purchasing household paid SDLT on its main home only. A new spine stage, property_purchases, after the support copies, ports uk-data#573 (a draft, at 07f6b460f) at the spine's design weights: a household whose stock of a kind is at least GBP 40,000 (the chargeable consideration HMRC's tables cover) can buy once a year, at a hazard proportional to its stock; the event-score threshold is the one whose weighted count of purchasers in England and Northern Ireland is closest to HMRC's transactions, and it applies everywhere; prices are band means at HMRC's band shares times one scale bisected to HMRC's value, never below the floor or above the stock. Draws are identity-keyed, so they differ from uk-data's positional streams. The targets are vendored from the pinned feed (hmrc_stamp_tax_facts.json, 110 rows): Table 6b's 2024-25 HRAD transactions and value allocated to households by individuals' shares of Table 8a, and Table 8b's 2024-25 individuals, which reproduce uk-data#573's figures exactly. The stage fits transactions and value only; households' SDLT is fitted at build level through obr.sdlt. The stage records support only as a band. The roster, kernel tables, operation vocabulary, schema, export allow-lists, coverage manifest, gate digests and H2 fixture move with it. The fixture sizes its own targets to its frame and leaves a kind whose synthetic stock is nil unimputed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…receipts (uk-data#564, #1095) obr.sdlt bound the whole OBR Stamp Duty Land Tax line, which every buyer pays; HMRC's other buyers (companies, partnerships and collective investment schemes) pay about a third of the receipts, and policyengine-uk charges households' stamp_duty_land_tax with corporate_sdlt beside it. The target is now the line's calendar-2025 window times individuals' share of HMRC's 2024-25 SDLT receipts, residential (Table 8a) and non-residential (Table 8b) together, from the pinned Chronicle feed. uk-data#569 (a draft, at 0544d692f) subtracts policyengine-uk's corporate SDLT statistic instead, which needs the unreleased pe-uk#2322. A new value operation, calendar_year_window_scaled_by_ratio, carries the rule: the calendar-year window of the reference's own series times the quotient of two operands that each pin their own period, may come from another publisher, and may each sum a declared number of cells. The regenerated target references, membership report and national compile parity move on obr.sdlt alone; the parity row's reason now names the payer basis. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the national spine, the non-residential purchasers' stock falls short of HMRC's Table 8b individuals' value, so the property purchases stage refused to build (uk-data#573 refuses any shortfall). Per María's ruling of 2026-10-16, where the purchasers' stock cannot carry the value target every purchaser buys at its stock, the most the cap allows, and the receipt records the fit (value_fit, value_shortfall_share); the stage still refuses below 80% of the value (minimum_value_share). The selection, its stock exponent and HMRC's transactions are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) The national release solves the bound spine, which has no area, so its main_residence_value stayed the WAS-imputed value after the regional uprating; only the dense line read values off the assigned constituency's Land Registry distribution (uk.full.property.value, microcosm#1240). A new spine stage, regional_home_values, after the high-value home support copies, gives every England-and-Wales owner household with a value the one its region's uprated Land Registry distribution holds at the household's weighted mid-rank among the owner households of its FRS region, at the spine's weights. It ranks as the dense value node does (ties broken by an identity-keyed draw; the support copies spread over the top stratum by their own draws), reads the region level of uk/high_value_home_value_knots.json (Wales is W92000004), and moves property_wealth by the value's change. Scotland, Northern Ireland, renters and owners without a value keep theirs, and the council-tax band is untouched. The stage keeps the value it replaced in main_residence_value_rank_basis. The dense value node receives that column through its slice and ranks on it, so the dense line's values, wealth and bands do not change; it refuses if a declared column is missing, and a run_graph test pins both. The release boundary drops the column on both lines. The value reaches three national rows: obr.sdlt, through the main-home purchase value, and ons.land.land_value and ons.land.household_land_value, through property_wealth; corporate land value does not move. The region knots' tails run up to each region's largest sale, as the dense line's do; they are to be fixed on both lines together (María's ruling of 2026-10-17). The roster pins move to 44 stages; the coverage manifest, the H2 fixture and the stage JSON are regenerated, and no gate digest moves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
policyengine-uk 2.128.0 (pe-uk#2119) moves a family off a legacy benefit DWP has closed and takes its other legacy awards away; the family then claims Universal Credit if would_claim_uc or would_claim_uc_at_legacy_closure is true, and the engine's default for the second, true, put every such family on Universal Credit. A new spine stage, uc_legacy_closure_take_up, after uc_capital_coherence and before pension_credit_take_up, ports uk-data#534 (a draft, at c67077a66; uk-data#492). A unit reporting Universal Credit, a unit whose would_claim_uc is true and a unit reporting none of the six legacy means-tested benefits keep the default. Every other unit is drawn at (r - p) / (1 - p), clipped to [0, 1]: r is DWP's claimed / (claimed + did not claim) for the unit's combination of legacy benefits (the all-households rate where DWP reports none), and p is the combination's share already claiming, at the spine's design weights (María's ruling of 2026-10-16; uk-data#534's share is unweighted). The rates are DWP's Stat-Xplore households sent a migration notice, notices July 2022 to June 2026, vendored from the pinned feed (dwp_move_to_uc_facts.json). Each unit reads an identity-keyed uniform. The flag joins the export surface's reviewed extra columns, so 5 of the 12 mirrored gate digests move; the policyengine-uk concept mapping binds it as a take-up input, so no take-up input is left at the engine's default. The roster pins move to 45 stages, and the coverage manifest, the H2 fixture, the stage JSON and the concept coverage report are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gets (#1095) Review of #1308: purchases_outside_sdlt_regions_weight was the raw weighted total of Scotland's and Wales's purchasers, and on the national spine the non-residential cell rests on fewer than ten source households; the fitted value, the shortfall, the event rate, the scale and the eligible owner weight were floats whatever their support. Every weighted field now goes through receipt_counts.small_cell_share on the distinct household_source_id values behind it, so one to nine sources read "<10"; the share at the stock cap appears only where neither the capped purchasers nor the rest rest on fewer than ten, and the capped support is an extreme_count band. Nothing was staged or uploaded with the old field. Tests: a cell of three outside sources and a fit region of five sources read "<10"; a capped side of two sources hides the share; the stage test now requires positive purchases and fitted transactions and value for both kinds (a nil target branch passed it before); and the packaged HMRC rows reproduce uk-data#573's household targets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1308: regional_home_values banded its capped cell on rows, and support copies from high_value_home_support repeat their source household, so a cell past ten rows could rest on fewer than ten sources. The cell is now counted on distinct household_source_id values (source_count, as the purchases stage counts them) and reported as sources_at_cap; the row totals go through receipt_counts.rounded_count. A test bands twelve copies of two households as "<10". No figure leaked: the cell is latent on the head spine, and the receipt is build output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…receipt (#1095) Review of #1308, with María's ruling of 2026-10-17: p, the share of a combination's drawn units that would claim anyway, pooled Great Britain and Northern Ireland, while DWP's Move to UC rates cover Great Britain only. p is now measured over Great Britain's units, and the probability applies to the combination's units in Northern Ireland too, as the Pension Credit take-up redraw does. Where p exceeds DWP's rate the probability is 0, and the receipt now flags the combination (rate_unreachable), never p itself, and only where ten or more source households carry it. Each combination's support is banded on distinct household_source_id values, not rows, since support copies repeat their source; the aggregates cover Great Britain only and go through receipt_counts.small_cell_share. The texts say that the share reaches DWP's rate in expectation where p is at most r, and declare the two limits uk-data#534 has: the drawn cohort includes units on the Pension Credit route, whose legacy benefits policyengine-uk does not close, and DWP's rates count every household sent a notice. The vendored resource now maps to the spine's 2024 build period. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1308: an operand that sums several cells was checked on its total match count only, so two facts for one listed member and none for another compiled, and a list of three members declared with a count of two passed when one was missing. An operand that sums cells now names them in exactly one list-valued selector field of expected_member_count distinct members, and each member must match exactly one fact. obr.sdlt compiles unchanged (each of its four HMRC record ids matches once in abf0921). Two tests cover the 2+0 case and the mismatched list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) Review of #1308, with María's ruling of 2026-10-17 to declare the HRAD allocation as uk-data#573 does: - "Receipts are checked against HMRC, never fitted" described a check that does not exist. The stage fits transactions and value only; households' SDLT is fitted at build level through obr.sdlt, and the texts now say so, and that uk-data#573's 30% higher-rates SDLT test is not carried over. - Households' HRAD is not published, so the allocation by individuals' shares of all Table 8a residential transactions is an assumption, as uk-data#573 says; its household lower bounds are 87,200 transactions and GBP 33.28bn. The texts declare that it probably overstates households' purchases, since nearly all receipts at or below the GBP 250,000 nil-rate band are surcharge and other buyers' receipts there imply more higher-rates transactions than their overall share. - obr.sdlt's notes declare two gaps it does not correct: Table 6b counts the higher rates before replacement-home refunds, which policyengine-uk never gives, while Tables 8a and 8b and the OBR line are net; and the engine's main-home purchase rate also counts the higher-rates transactions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1308: the engine freeze (María's ruling of 2026-10-16) was held by uv.lock alone; the UK extras accept any later release, and the builds only recorded the installed version. assert_installed_engine_is_pinned compares it with the version the engine pins were taken from and refuses a mismatch. It runs in spine_build._rules_engine, which gives the spine build its engine and which prepare_full_build and prepare_national_build call before they solve, and at the start of the release-cut battery the certifier runs. The HMRC calibration helpers' default simulation factory, which no build path calls, checks too. The match is exact, so a post-release or a local build of the pinned version is refused as well. An importable policyengine-uk without distribution metadata is refused, since its version cannot be read; an environment without policyengine-uk is left to the callers' own import errors. The tools that regenerate committed surfaces do not check: CI's --check jobs and the H2 parity run them on the lock. Tests drive _rules_engine and the release-cut battery with a later release, and cover the match, a post-release, the absent engine and the missing metadata. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On main after #1307 and #1306: 27,267 rows, 23,004 of them compiled. The 18 Scottish BRMA rows are ledger-only by construction, and no signed value moves. The 40 cells of the support floor's two authorities, E06000053 and E09000001, carry the floor's own signed rationale; nothing else changes. The release-blocking preflight gate uk_ledger_compile_parity_local_incumbent_2025 reads this receipt, so whichever of #1305 and #1308 lands second regenerates it on the combined tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…count (#1095) Re-review of #1308: the regional_home_values and uc_legacy_closure_take_up nodes did not declare household_source_id, and the graph executor hands a stage only its declared cells. In a graph build both receipts fell back without a word, the Move to UC one to household ids and the home-value one to row counts, so support copies counted once each. Both nodes now declare the column, and both stages refuse a frame without it, as property_purchases does. New tests run each production node through the executor's input projection and UKStageKernel on twelve support copies of three source households: the Move to UC combination reads "<10" for the flag and the support, and the home-value cap cell reads "<10" (the test lowers the cap, which on the packaged knots no rank below 1 reaches). Before this change the same tests read True and "10-29". Stage-level tests now also fail if the stage stops passing Great Britain's units (a UK-wide p crosses the rate) or the source ids. The H2 graph fixture moves on the two nodes' inputs only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… as 0 (#1095) Re-review of #1308: the purchases receipt sized the uncapped side as the fit's sources less the capped side's, which is the number of sources with no capped row. Where uncapped rows copy capped sources, a share on a three-source side shipped, and the fitted weight times one less the share gave that side's weight back. Each side is now counted on its own distinct sources, and the share is also withheld when one to nine sources carry the fit, since at the stock cap every purchaser buys at its stock and a share of 1.0 beside "<10" would still describe it. Tests put twelve capped rows on two sources, three uncapped rows on copies of capped sources, and a stock-cap fit on five sources; the old logic and a rows-not-sources count each fail them. The three stages shared a copy of the same support band, which read "<10" for an empty cell beside a zero weight. receipt_counts.support_band now serves all three and reads "0" there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iod (#1095) Re-review of #1308: both stages declare mapped_build_period 2024 for their vendored facts, HMRC's 2024-25 Stamp Tax tables and DWP's cumulative Move to UC rates, but neither checked it, so a 2030 frame ran on them. Each now refuses a frame at any other period, as property_components does, and the declared period is the constant the check reads. A test per stage covers a 2030 frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-review of #1308: the H2 fixture never reached the stock-cap fit, the branch the national spine's non-residential purchases take. Its synthetic non-residential target now asks a ninth more than the purchasers' stock, so the stage buys at the stock in both executors; the synthetic frame holds no other-residential stock, so that kind is still not imputed there. A stage test now fits one kind at the stock beside one it scales, in one run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…residents' SDLT (#1095) Re-review of #1308: main gave the region rows' local-only reason as the national spine's main_residence_value being the WAS donor's, not a Land Registry placement (microcosm#1301). N1 makes that untrue: the national spine now reads the value off the regions' Land Registry knots. The rows stay local-only for now, and the reason is restated in the three notes, #1301's fragment, the calibration-lines docstring, the generator's signed rationale with the membership file it writes, and its pin: binding them on the national line would move the national registry and solve while the knots' tails still place more homes in the top bands than the derived stock, which is left to microcosm#1112's follow-up. obr.sdlt's note said non-resident individuals' surcharge stays inside the individuals' share. Their whole SDLT does, and no FRS household is non-resident, so that is now the first of three declared gaps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8739557 to
ca13808
Compare
|
Reply to the re-review. Thanks for it. It is addressed at Blocking
Timeline (R0)
Low
Nits
Cross-PR
🤖 Generated with Claude Code |
The sixth #1095 ports PR. It renews the ONS savings-interest diagnostic and locks policyengine-uk 2.134.4, frozen for this PR (2.134.5 waits, see E1). It ports the stamp-duty purchases and the households' SDLT target (uk-data#573, uk-data#564). It gives the national line the regions' Land Registry home values (#1112) and draws the Move to Universal Credit claim flag at DWP's rates (uk-data#534). The rulings applied are María's of 16 and 17 October, and each commit names the one it applies.
Status: rebased on main after #1307 and #1306 merged. The commits from
8162e8dadto4cc99b93aaddress the first review of this PR, and those from2b03b7d1don address the re-review;6c011906dwas amended for it. N2, the high-value home OBR-leg fix, is no longer here: #1306 carries it. R0 to S1b, the head before the re-review and the head now (on main with #1307 and #1306) all pass the 7 calibrated-seam gates on 2.134.4. The receipts follow in an update of this body.Summary
Renewal (R0)
ons.savings_interest_incomeis renewed to 8 January 2027 (UK spine: savings interest income a third under HMRC SPI and five times under the ONS D.41 row — reconcile the target concept and review FRS interest capture #866). The exclusion lapses after 22 October, so this PR must merge by 21 October; if it cannot, R0 goes out alone on 20 October. The row stays a diagnostic and is never fitted (ruling R3 of 22 September). The register records the renewal as approved by María in session on 16 October; her confirmation of the 8 January 2027 expiry is owed before merge. R0 also updates UK local release: publish a K=15, 150,000-household dense dataset in at most two builds (#1301) #1307's test of the entries approved that day, and merges alone if needed.Engine (E1, and the freeze)
additional_residential_property_purchasedandnon_residential_property_purchasedfrom formulas into inputs that default to nil. Until the data supplies them (S1 below), a purchasing household pays SDLT on its main home only.APPROVED_UV_LOCK_SHA256re-derive.unused_pension_annual_allowanceinput at nil. On the national spine that moves Universal Credit awards and income tax for households with pension contributions, and the solve fails the weight-ratio gate (see Measurement). 2.134.5 waits for a follow-up that supplies the unused allowance and checks the relief inputs.6c011906d). An installed policyengine-uk other than the version the engine pins were taken from is refused in two places:spine_build._rules_engine, which gives the spine build its engine, and whichprepare_full_buildandprepare_national_buildcall before they solve;--checkjobs and the H2 parity run them on the lock.Stamp duty (S1, S1b, S2)
property_purchases, imputes households' annual purchases of additional dwellings and of non-residential property (uk-data#573 at 07f6b460f, a draft; uk-data#556).obr.sdlt, and uk-data#573's 30% higher-rates SDLT test is not carried over.8162e8dad). The share at the stock cap is also withheld where the fit or either side of it rests on fewer than ten, and an empty cell reads "0" (0d4a58c42).8928b1e80).value_fit,value_shortfall_share) and refuses below 80% of the value. The selection, its stock exponent and HMRC's transactions are unchanged.obr.sdltbinds households' SDLT (uk-data#564).stamp_duty_land_taxand addscorporate_sdltbeside it.calendar_year_window_scaled_by_ratio, carries the rule: the window of the reference's own series times the quotient of two operands. Each operand pins its own period and names its members in one list, and each member matches exactly one fact (4daa259f7).obr.sdltalone, from £15.03bn to £10.16bn.Home values (N1)
regional_home_values, runs after the high-value home support copies. It gives every England-and-Wales owner household with a value the one its region's uprated Land Registry distribution holds at the household's weighted mid-rank. It reads the region level ofuk/high_value_home_value_knots.jsonand movesproperty_wealthby the change. Scotland, Northern Ireland, renters and owners without a value keep theirs, and the council-tax band is untouched.main_residence_value_rank_basis, and the dense value node receives it through its slice and ranks on it. The node refuses a declared column that is missing, and arun_graphtest pins this. The release boundary drops the column on both lines.obr.sdlt, through the main-home purchase value, andons.land.land_valueandons.land.household_land_value, throughproperty_wealth.ca138083e). Main gave the reason that the national spine's value is the WAS donor's; N1 makes that untrue. The reason is now this: binding the rows on the national line would move the national registry and solve, while the knots' tails still place more homes in the top bands than the derived stock. That is left to the UK national release: main_residence_value keeps the WAS-imputed tail, so the surcharge's top bands stay empty #1112 follow-up.household_source_id, and the stage refuses a frame without it (2b03b7d1d).Move to Universal Credit (M1)
would_claim_uc_at_legacy_closureis drawn at DWP's Move to UC claim rates (uk-data#534 at c67077a66, a draft; uk-data#492).would_claim_ucor this flag is true. The flag's default put every such family on Universal Credit.uc_legacy_closure_take_up, runs afteruc_capital_coherence. It keeps the default for a unit reporting Universal Credit, a unit whosewould_claim_ucis true and a unit reporting no legacy benefit.household_source_id, and the stage refuses a frame without it (2b03b7d1d). It also refuses a frame at any period other than 2024 (8928b1e80).Deviations and open points
Measurement
Each arm builds its spine locally on feed abf0921 and runs the national role's calibration on it.
obr.sdltthere is the whole OBR line.obr.sdltwithin 0.2%. In the purchases stage, additional dwellings fit HMRC's value exactly, and non-residential purchases reach about 81% of HMRC's value at the stock cap, with transactions within 1%.obr.sdltto within 0.1%.obr.sdlt: from £9.70bn to £13.51bn at design weights, against a £10.16bn target; within 0.1% after the solve.ons.land.household_land_value: from £4.21tn to £5.09tn at design weights, against a £4.49tn target; within 0.02% after the solve on both arms.ons.land.land_value: misses by about 4.7% after the solve on both arms, so N1 does not cause the gap.ons.land.corporate_land_valuedoes not move.ca138083e, on main with UK local release: publish a K=15, 150,000-household dense dataset in at most two builds (#1301) #1307 and UK local surface before the Budget build: high-value homes OBR leg, per-vehicle fuel flag, Northern Ireland energy share and housekeeping (#1278) #1306, 2.134.4): loss 0.26816 to 0.00565; 98.4% of 1,215 rows within 10%; all 7 calibrated-seam gates pass. Main now holdsobr.ni_employerout as a diagnostic (pe-uk#2459), hence one row fewer.property_purchases, so the purchases fit is as before: additional dwellings fit HMRC's value exactly, and non-residential purchases reach about 81% at the stock cap.obr.sdltis within 0.4% and household land value within 0.1%. Total land value still misses by about 4.7%.Not in this PR
property_purchases,regional_home_valuesanduc_legacy_closure_take_upare deliberately ungated for now, andobr.sdltstays held byuk_target_fit.Disclosure
Checked against the UK Data Service rules before pushing: the commit messages, every added line, the fragments and this body. No record-level value, extreme, effective sample size, weight ratio or support count appears. The figures are published statistics or national weighted aggregates. The three stages' receipts band every cell on its distinct source households, in a graph build as well as in a direct call (
2b03b7d1d).Tests
ca138083e.ca138083eon 2.134.4: CI's engine-uk job, 217 tests, all pass. CI's engine-free job in full, 19,789 tests with 157 skips, all pass except 5 that this machine cannot run as CI does, and which pass in CI: two Orrery parser tests need an npm package that is not installed here, one reads the live release pointer, one refuses this Python 3.14.6, and one checks that the tier has no policyengine-uk.--checktools on 2.134.4 pass: the uprating pins, the concept coverage and the coverage manifest. The H2 fixture regenerates byte-identical at the head.🤖 Generated with Claude Code