Repository navigation
UK spine follow-ups: SPI donors funded, WAS coherence, residential split, Child Benefit, release-cut blockers (#1063) - #1089
Conversation
Automated review pass (Claude Code, high effort) — round 1 at
|
items 1, 2, 4) spi_income_band_donors copied 120 FRS households per HMRC Table 2.5 band from GBP 200,000 and added the band's published taxpayers on top of the incoming weights: about 450,000 households of created mass on rows starting at up to 2,992 each, recorded with no declared factor under graph policy `free`, with no coverage family and an RNG draw. Channel design: - Each band seats max(120, ceil(published taxpayers / 250)) donors at equal weights of the published taxpayers over the count (1,436 / 244 / 120 / 120 on the 2024-25 counts; none above 250). - The donors' mass leaves the incumbent households of each donor's region in proportion (María's ruling: region), so the total and every region's mass are conserved; the total is made bit-exact on one incumbent row and the record carries declared_factor 1.0 under its own reason. Graph policy `declared`. - Seating is identity-keyed: Efraimidis-Spirakis keys log(u) / (w * p) on stable_identity_uniforms(person_id, seed 3, salt spi_income_band_donor_draw:<band>), one carrier per household, highest band first. The carriers' leaf draw in hmrc_spi_income_spine is keyed on the FRS person each carrier copies (salt spi_income_band_donor_leaf_draw) instead of the row order. - The tape is prepared as the income stage prepares it (its stage-1 seed and the ONS age draw), so composites and State Pension recipients sit in the same age bands in the propensity table and the band pools. - Small frames: seats scale to at most 15% of the eligible households and the weights so no region gives up more than half its mass; both scales are recorded and the published band masses are asserted only when both are one. A full-sample build must be at full scale. Declarations: manifests rendered from the stage's own payload, the closed schema branches, `_declared_seeds` keyed by salt, a `spi_income_band_donors` family with mass_conserving semantics in the release-input coverage manifest, and the gate uk_stage_spi_income_band_donors_support rewritten (conserved total, maximum weight, minimum count, funding factors, band masses at full scale). Identity tool: E8 reconstructs the pre-donor frame from the artifact (CGT layers folded, each region's incumbents scaled back) and checks the stored layer; with the licensed tape (--spi-tab) it reruns the seating from ids in original and permuted person order against the stored donors, carriers and band weights. The tape-derived propensity table is not written into the receipt. Coverage manifest, charter-H2 fixture and gate digests regenerated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…m 3) The SPI income band donors were the last stage to add support mass; they are now a funded channel, so every stage family declares mass_conserving. The family parser refuses any other semantics, the terminal family gate accepts only a household record that conserves the total and declares factor one, and the manifest generator reads the one constant. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…HMRC's August 2025 statistics (#1063 fold-in) frs_take_up drew would_claim_child_benefit at a flat 89% (HMRC, 2022) over every benefit unit with the FRS reporters on top, and child_benefit_opts_out at a flat 23% over every benefit unit whatever its income. The engine pays on the first and never reads the second, so 96% of eligible children were claimed for and paid and obr.child_benefit sat about 20% over. New stage child_benefit_take_up, after pension_credit_take_up and before CGT cloning: - one temporary engine materialization of is_child_or_qualifying_young_person_for_child_benefit and adjusted_net_income (consumed only); - claims by family, keyed on the age of the eldest eligible child: a reporter claims, the other families claim at rates solved from the eldest age down so the claimed share of the eligible children of each single year of age is HMRC's Table 15 rate (May 2025, opted-out families included), weighted at the stage's household weights; clipped rates are receipted; - opt-outs: the published opted-out share of registered families (684,635 of 7,552,330, August 2025) of the claiming families, drawn among claiming non-reporting families with the highest adjusted net income at or above full withdrawal of the charge, then inside the taper for any remainder (thresholds read from the engine); - would_claim_child_benefit = claims and not opted out (the flag the engine pays on); child_benefit_opts_out = opted out; a unit without an eligible child keeps its early draw. Trial on the 1 October spine at design weights: 86.7% of eligible children claimed for (target 87.1% at the frame's age mix, HMRC 86.6%), 9.0% of claiming families opted out, all from fully charged families, 11.1m children in payment against 13.5m before. The published rows are vendored from the pinned Chronicle feed (hmrc_child_benefit_statistics.json). Gate uk_stage_child_benefit_take_up holds the claimed share overall and by age and the opted-out share; the terminal take-up signal gate no longer measures the two flags. New op kinds assign_family_claims_by_child_age and assign_opt_out_by_charge_income with closed schema branches; graph cells, kernels, fixture tool, roster 36 -> 37, microcosm-data gate maps, coverage manifest, charter-H2 fixture and digests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The salary_sacrifice stage fitted its QRF on the FRS respondents asked the question and predicted for everyone else in the frame, children and people without a job included: on the 30 September national build 1.94m of the 7.6m people with pension_contributions_via_salary_sacrifice had no employment income (0.53m under 16) and carried GBP 7.1bn of the GBP 22.5bn, and the stage's headcount receipt counted them before its conversion top-up. The prediction population is now the people not asked who have employment income; a person not asked with none is set to zero and the receipt records the rows and mass. An asked person keeps what they reported. The conversion tops the headcount up from the true starting count (rate 0.15 of an 18.0m donor pool on the 1 October spine, cap 0.5). Manifests, coverage manifest and charter-H2 fixture regenerated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tems 5, 6 and the identities) On the national build from main, 22 percent of mortgage_debt (GBP 381bn) sat on households off a mortgaged tenure, housing-association renters held GBP 300bn of main_residence_value, 8 percent of owners had none, net financial wealth exceeded gross on 17 percent of households and property_wealth departed from its components on a third. Tenure entered the chain as one soft predictor, the recipient's is_renting came from an engine formula that omits RENT_FROM_HA, and every total was drawn independently of its parts. - One four-way tenure category on both sides (uk_runtime.tenure_constants, also read by the local targets): the donor's from Ten1R8 and DVPriRntR8, the recipient's from tenure_type. Its flags replace is_renting and has_mortgage_tenure; the stage reads no engine tenure formula. - main_residence_value is fitted and drawn on the owner tenures only and mortgage_debt on the mortgaged tenure only, zero by rule elsewhere. The receipt records the donor mortgage mass the rule leaves out (mortgages on other property held off a mortgaged tenure), read against TotMortR8 and OthMortR8_sum. - Totals are derived from drawn components: property_wealth (with a drawn remainder for buy-to-let, overseas and other property), gross_financial_wealth (with a drawn remainder) and net_financial_wealth as gross less consumer debt and the student loan balance. The pinned tab satisfies each identity on every row; cleaning refuses a donor that does not. A sum that leaves the donor's range gives up the excess from the remainder first, and the receipt counts the rows. - Seven chain segments with their own child seeds (the first four roots are unchanged). - New release-blocking gate uk_stage_was_wealth_coherence; the support gate also covers private_pension_wealth. - regional_property_uprating scales the property components with the total, so the identity survives the uprating. Manifests, schema, coverage manifest, H2 fixture (its WAS donor now satisfies the identities) and gate digests regenerated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
On the 30 September spine (main c5a1cba) the identity tool failed E7 and E8: - E7 read every SPI-synthetic household as support clone index 1; the income band donors carry the same flag at index 2. It now reads the donors' index. - E8 compared the stored and recomputed student_loan_plan with Series.equals, which calls equal columns of different string dtypes unequal. It now compares values. - E8's reversed-order recompute of the incidence anchor differed from the forward one by 1e-13: the sums the anchor's factors depend on were pairwise float sums, which move in their last bits under a row permutation. The anchor takes correctly rounded sums, so its weights do not depend on the row order. With these, E7 and E8 both pass on that spine. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…assignment (#1063 items 7, 8) The residential-property flag was realised by one weighted systematic walk over every liable gainer in ascending gain order. The balance a heavy row left behind was paid by the next row whatever its weight, so a light row at the top of the gains order was flagged far more often than its probability, and one row could move the realised residential gains by most of the Table 8 total (the cap-80 arm of #1045 failed that way). - Each HMRC gain band has its own walk, offset and balance. The receipt reports per band the pool, expected and realised count and gains, and the walk's own bounds, with the share of realised residential gains on the ten largest flagged stakes and the largest pool stake against the target. - uk_stage_hmrc_cgt_asset_type_spine_summary holds every band to those bounds and the totals to the wider of 5 percent and the summed band bounds. The Bernoulli sigma and maximum_gains_sigma are retired: the sigma assumed independent draws and shrank when rows were split. - A zero-weight row can no longer be flagged. - The main type is fitted once per claimant status: claimants to Table 7's shares among the three eligible types, non-claimants to the shares that restore the published composition. It is realised by an error-diffusion walk in descending gain order, so realised gains by type track the fit. The assignment is deterministic and seed 554 is retired. - The receipt reports the composition by claimant status against Table 7. The fact fence and diagnostic-only status are unchanged. Manifests re-rendered from the code, schema, coverage manifest, H2 fixture and gate digests regenerated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
slc.borrowers.plan_2_liable and slc.borrowers.plan_2_above_threshold expired on 2026-10-03; an expired entry raises in the national build and in the release-cut certifier. Renewed one month on María's ruling of 2026-10-02; the plan-2 borrower coverage gap stays with microcosm#868. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…#1063 item 7) The banded walk of e0b41a59b turned residential probabilities into whole flags, so its gains error in each HMRC band was bounded by one row's stake, and in the open band one stake (£10.9bn at a 0.2% probability) was 7.5 times the band's whole expectation: the band was either short by its lottery expectation (−£172m) or over by a giant stake (+£10.3bn). Closing rows, sub-bands and weight-keyed eligibility were considered and rejected (ruling 2026-10-02). - New expansion stage cgt_residential_split after cgt_incidence_anchor; hmrc_cgt_asset_type_spine moves after it (roster 35 → 36). The stage solves the residential logistic as the asset-type stage did and splits every household carrying liable gainers into arms: p·w and (1 − p)·w for one gainer, 2^k arms at product weights for k gainers (k > 3 refused). The residential arm's gainer carries the whole gain in capital_gains_residential_property; lineage columns household_is_cgt_residential_clone, cgt_residential_clone_index (the kernel's id + j × multiplier rule) and cgt_residential_probability. Mass and every household's composition are conserved (graph policy conserve, declared factor 1.0, exact-total correction on an unsplit incumbent, mass_conserving coverage family). No draw, no seed. - At design weights the residential count and gains are identities on Table 8a in every gain band. Gate uk_stage_cgt_residential_split_mass holds the conserved mass, the arm weights as the declared products, the arm count implied by the households by liable gainers, the solve and the identities by band; the asset-type summary gate holds the identities its arms restate and drops the walk bounds. - hmrc_cgt_asset_type_spine types the residential arms and keeps the BADR claims and the Table 7 fit by claimant status; seed 553, _banded_systematic_flags and assign_residential_property_flag go. - The weight-ratio and ESS family folds, the geography identity kernel (a cgt_residential_split path step), the export allow-list, the national sampling raw mask, the student-loans receipt and the E8 identity receipt (arms reconstructed first, clone pairs and support copies checked on the arm-free frame) carry the new layer; the parity fixture, coverage manifest and gate digests are regenerated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… c9) The certifier rehearsal on the 2026-09-30 national build failed 5 of 20 gates. Each is addressed at its source: - uk_export_surface: the candidate label is microcosm_uk_2024_25; the certifier and the full-build evidence read the surface through uk_export_candidate_columns (structural ids stripped, the frame's weights presented as household.household_weight); the 43 declared stage outputs the incumbent never carried are allow-listed (ruling 2026-10-02); the one reviewed exclusion, person.incapacity_benefit_reported, leaves at the release boundary (uk_release_export_frame), with the graph readback expecting the same frame and the spine keeping the column for the SPI income stage. - uk_degenerate_release_surface: FRS 2024-25 renames TRAIN to TRAIN2 and recodes it (9 = none of these, 10 = Kickstart); the education stage reads it, so is_in_approved_training carries signal; incapacity is dropped. - uk_nonnegative_columns: the LCFS donor's diary consumption is floored at the declared floor (0) before the imputation, the clip ranges and the rake, with a receipt; the support gate declares the floor and holds it. - uk_input_mass_parity: adult_ema and dfe_education_spending enter the per-reference register (the enhanced FRS barely carries either input). - uk_qrf_tail_concentration: the sparse charity-gifts leaf re-enters the register (168 carriers; the 2026-09-21 retirement is recorded). Smoke builds: uk_stage_child_benefit_take_up declares population_fact_check as the Pension Credit gate does, and the anchor composition check allows the absolute rounding tolerance the other mass identities use. The gates manifest, coverage manifest, parity fixture and digests are regenerated; the regression battery's clock moves to the entries' approval date. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The arms B and C, the certifier rehearsal R5, the Child Benefit trial, the residential split and the rulings of 2026-10-02, with arm C2 and the final build still to land. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ebff841 to
1dd2c31
Compare
…ure, the pins and the readouts (#1063) - Blocker: the five internal disability carriers leave the export allow-list and are dropped at the release boundary beside incapacity_benefit_reported; the input-mass evidence pin and its test mirror follow the c9 register entries. - WAS mortgages (item 3): only the main-residence mortgage (TotMortR8) is tenure-stratified; the mortgages on other property (HMortGR8 less TotMortR8) are drawn on every tenure without a stratum and mortgage_debt is derived as their sum, so a renter's or an outright owner's buy-to-let keeps its mortgage beside the property. Eight chain segments (the first seven roots unchanged); the coherence gate holds the main-residence mortgage off the mortgaged tenure at zero and the mortgage identity on every row; the donor-range cap pins a float overshoot to the maximum. - Item 4: scripts/residential_readout.py reports the by-band residential count and gains on calibrated weights beside the design identities, and the row-level weight shape with the arms; C2's readings are in the note. - Item 5: the children-in-payment gap is the design-weight child base. - Item 6: the split's docstring names what calibration binds. - The stack arm's blocked cell, dwp/uc_payment_dist/SINGLE_annual_payment _28_800_to_30_000, has one supporting household whose award moved out of the band when the larger donor block reshuffled every later draw; it joins the measure exclusions beside its sibling of the same class. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Thanks, all six addressed in the latest commit; the branch is now on
On the open calls: the opt-out pool and the Table 8a promotion are María's; the buy-to-let value sits in the drawn remainder of One more thing the stack arm found: 🤖 Generated with Claude Code |
…sehold UC band (#1063) The stack arm on 5583250 calibrates to loss 0.00769 and blocks on two cells. dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_22_800_to_24_000 has two supporting households on every main-based spine; both awards moved out of the band when the stages drawn after the WAS wealth chain read their rows in a new order, so it joins the uk-data#452 measure exclusions beside its siblings. hmrc.spi_region.income_tax_by_region_12570_15000@E12000008 sits on its target at design weights (69.6m against 69.5m; 62.4m on main, where the solver pulled it to +22.6%) and the same pull now lands it at +32.0%; the regional low-band cells move 10-30% at design weights between spines because the salary-sacrifice and pension draws are positional. It is deferred four weeks in the target-fit register (it was deferred on 2026-09-18 and retired on #1012 at +24.5%), for the draw-order fix at its source and the pull's diagnosis. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…l employment-income bands (#1063) The deferral's reason and the receipts note said the draw order; the stack 2 solution says the solver fills the 20-31% short national employment-income bands with the same low-paid South East households that carry this cell. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t a flat index (#1063) The three lowest employment-income rows were 20-31% short at design weights on every spine. They are SPI 2023-24 Table 3.6 amounts, the employment income of taxpayers whose total income falls in a fixed nominal band, and the registry projected them to 2025 with the flat OBR average-earnings index (1.107), while the count, total-income and tax rows by band already use HMRC's own band-specific growth from Income Tax Liabilities Table 2.5. An amount held in a fixed band moves with the band's membership: HMRC projects the 12,570-15,000 band's total income +5.0%, the 15,000-20,000 band's -2.3% and the 20,000-30,000 band's +0.3%. The SPI tape re-banded under the engine's own indices agrees with the direction in every band. The employment, self-employment and private-pension amount references (39) now use hmrc.itl_2026.total_income_growth_by_total_income_band. The three lowest employment targets move from GBP 18.7bn, 53.8bn and 190.4bn to 17.7bn, 47.5bn and 172.5bn, and the frame's design-weight gaps from -19.8%, -31.2% and -25.1% to -15.5%, -22.1% and -17.4%. Dividend and savings-interest amounts keep their own indices, since those move with rates rather than band membership. The remaining gap is the frame's composition of the low bands (the receipts note names where), a follow-up in the spine. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ers just above the allowance (#1063) Arm stack 3 on the band-aware targets: 7/7 seam gates, loss 0.00713, the employment rows within 4-12%, the South East cell still +30.3%. The frame has 0.278m South East taxpayers in the 12,570-15,000 band against HMRC's 0.364m (2.31m against 2.97m nationally) and they pay GBP 250 each against GBP 215, so the bound count rows scale them by a third and the tax cell overshoots. The deferral's reason and the note say so; the fix is the lowest band's support in the frame. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ts (#1063) The incumbent-2025 compile-parity receipt pinned the 39 SPI Table 3.6 amount references at their flat-index values. With the band-aware ITL growth projection (2fe7d8b) the compiled values moved and the release-cut certifier's first part, uk_ledger_compile_parity_incumbent_2025, refused the final build's candidate on the stale signatures. Regenerated against the pinned ledger (facts 28b7105…, national surface): exactly those 39 rows change, 243 parity, target-reference and country-spec tests pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…plit order-free (#1063) The E8 identity receipt on the final build's spine failed three ways. Two share a root on main: since microcosm#1069 c9 the salary_sacrifice stage lowers a converted record's employment_income and zeroes its employee contribution in place, after the CGT support split and the incidence anchor banded every carrier on that pay. The receipt's recomputes therefore banded 2,797 clone carriers on post-sacrifice pay, moved 82 of them down a Table 3 band, derived different anchor targets (55,622 households off by up to 286) and selected a different support family in two bands. The stage now keeps a converted record's pre-conversion pay on salary_sacrifice_pre_conversion_pay (zero elsewhere; an internal carrier dropped at the release boundary), and every receipt of a stage before salary_sacrifice reverses the conversion from it. The third was the split's own: two person orders of the same frame gave arm weights 1e-13 apart because the logistic solve's bisection sums are pairwise float sums. The split walks the liable gainers in person_id order (the identity on the spine's sorted tables) and breaks a tie for the exact-total correction row by household id; the order test is bitwise. Manifests, coverage manifest, the UK graph's cell inventory and the charter-H2 fixture regenerated; receipts for the 2fe7d8b final build in the experiment log. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ema input-mass exclusion (#1063) The release-cut certifier on the second final build reached all 20 gates. Two failed on columns the release boundary drops: the five internal disability carriers and the salary-sacrifice pre-conversion pay carrier leave the candidate (UK_RELEASE_EXPORT_DROPPED_COLUMNS), so uk_nonnegative_columns and uk_qrf_tail_concentration, which check every declared stage output, reported them absent. Both bindings now read an export-dropped declared column from the spine frame the certifier supplies, at the spine's weights; without that frame the absence still fails, as before. uk_input_mass_parity failed the adult_ema exclusion as stale: the build carries it at +74% against the enhanced-FRS reference, inside the tolerance, so the entry is retired and the sealed evidence digest moves. The gate's three live findings (access_fund, jsa_income_reported, working_tax_credit_reported) are diagnosed in the experiment log and left to the ruling: one FRS outlier at the calibration's weight bound and the SPI channel's legacy-benefit leaves, neither new to this stack. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Automated review pass (Claude Code, high effort) — round 2 at
|
| Item | Status | Evidence |
|---|---|---|
| 1 Internal disability carriers on the export allow-list | Closed | All five, plus incapacity_benefit_reported and the new salary_sacrifice_pre_conversion_pay, are in UK_RELEASE_EXPORT_DROPPED_COLUMNS (national_frame.py:466-480). test_internal_disability_carriers_stay_out_of_export_registers passes locally. |
| 2 Plan-2 renewal on main | Open, now urgent | See 2 above. |
| 3 £127bn of other-property mortgages dropped | Closed in code; one receipt line stale | Other mortgage is HMortGR8 − TotMortR8 via _donor_remainder (was_wealth.py:489), which refuses a donor row whose main-residence mortgage exceeds the total. So mortgage_debt = main + other holds on every donor row and no mass leaves. Only main_residence_mortgage is stratified (was_wealth.py:89). However, Arm B in the receipts (1063-uk-spine-followups.md:53-55) still says the rule "drops … £127bn". Your reply says the receipt now reports the other-mortgage mass held off the mortgaged tenure instead, but I couldn't find that figure in the note. Please mark the Arm B line as superseded and add the held mass. |
| 4 Table 8a bands after calibration | Closed as reported | The readout is in the receipts (lines 76-84). The national totals hold and the bands move: £1–2m 730 → 552 and £2–5m 427 → 274. Stating the by-band identities as a design-weight property is honest. Promoting the bands is María's call. One gap: scripts/residential_readout.py is cited but isn't in the tree. Please commit it, or say it lives with the licensed data. |
| 5 Children in payment, 11.1m against ~11.73m | Closed | The explanation is in the receipts (lines 141-146): a design-weight base of 14.04m against a calibrated 14.79m gives 11.7m at the same rates. |
| 6 "Binds" wording | Closed | The split's docstring and notes now name the two national rows. |
New since round 1
- Question: the certifier's last failure. The receipts say the rerun passes 19 of 20, with only
uk_input_mass_parityfailing, onaccess_fund+535%,jsa_income_reported+1,058% andworking_tax_credit_reported+747%.- The analysis that this predates the stack is convincing for JSA and tax credits.
- On
access_fund, one household carries 98% of the mass. Its £1,035.62 a week has FRS period code 5, and the spine annualises it to £54,037. - If period code 5 is a calendar month, the weekly figure may itself be a mis-weeklyised annual or termly amount. That would make it a data or period-code fix rather than an outlier fence.
- Worth checking before María rules. Either way, the PR is titled "release-cut blockers" and the cut still fails one part, so the body should say so.
- Nit: thin cells flipping on draw order. Both new UC exclusions are cells with one or two supporting households, whose awards left the band because later draws that aren't keyed by identity read their rows in a new order. The exclusions are signed and consistent with the 2026-08-26 siblings (uk-data#452, expiry 2026-11-26). But each upstream stage change can now cost a thin cell. Keying the remaining draws by identity would stop that churn, so it's worth a line in UK spine follow-ups after #1045: SPI band donors as a mass-conserving support channel, WAS tenure coherence, the residential draw's bound and Table 7 composition, then a national build #1063's follow-ups.
- Note: weight-shape margin. The folded max-to-median is 1,028, against main's 609 and the 1,151 bound. That passes, but it's closer to the bound than main has been. The receipts already flag it, so no change is needed.
Checked and correct
- Determinism fixes: the salary-sacrifice pre-conversion pay carrier and the person-order walk for the residential split, from the E8 diagnosis, both look right. The second build's spine is bitwise identical in every shared column.
- Tests: the targeted suites for the WAS wealth, residential split, Child Benefit, salary sacrifice, terminal gates, battery bindings and source stages tests all pass locally. The only failure is item 1.
- Merge base: the branch is on main after UK pensions: resident State Pension, Pension Credit, contributions and salary-sacrifice relief (#1069) #1084 merged, with 21 commits.
…eferrals, the readout tool (#1063) CI's engine-free lane failed on test_uk_uc_family's pinned counts: the two thin dwp/uc_payment_dist cells this PR excludes (SINGLE 28,800-30,000 and COUPLE_NO_CHILDREN 22,800-24,000, the uk-data#452 class) leave 81 active and 19 excluded rows, not 83 and 17. Both pins now say so. The release-cut certifier's one open part, uk_input_mass_parity, is settled by ruling (2026-10-04, in session): the deferrals needed to build and publish the national dataset are signed, each with its diagnosis. access_fund (expiring 2027-01-04): one FRS record, sernum 14443, reports a GBP 4,500 access fund under period code 5 (calendar month per the FRS 2024-25 variable listing), weeklyised by the FRS to GBP 1,035.62 and annualised by the spine to GBP 54,037, eleven times the next value; the period rule is owed in the spine before the entry expires. jsa_income_reported and working_tax_credit_reported (2027-04-04): the SPI synthetic channel's stage-2 QRF imputes these legacy-benefit leaves onto taxpayer rows, which the enhanced-FRS reference never carried; the 30 September main candidate sat at +428% and +421% on the same columns. The sealed input-mass evidence digest and the register mirrors move with the entries; the battery fixture's exclusion clock advances to the signing date. Review round 2's other items: tools/uk_residential_readout.py is the readout the receipts cite; the Arm B receipt line is marked superseded with the held other-mortgage mass from the final build; the follow-ups (identity-keyed positional draws, the SPI channel's legacy leaves, salary_sacrifice before the CGT stages) are listed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… the seam test at the registers' latest approval (#1063) The certifier rerun on the signed head passed all 20 gates and then refused to compose: "spine: signature does not authenticate under the release signing key". Not the key (every report, the run's own included, carries the same fingerprint) but the bytes: the gate battery signs its reports over json.dumps(sort_keys, compact) while the certifier verified the parts, and signed the certificate, over the logbook's #628 form, which renders 1.0 as 1 and 1e-05 as 0.00001. The two agree on the float-free synthetic fixtures and on no real report, so the first certification to reach composition was the first to see it. The battery now exports canonical_report_bytes and the certifier verifies and signs with it, the form the data contract's verifier already uses; a regression test puts such floats in a part. CI's engine-free lane, widened by round 2's diff to test_uk_national_graph, found the seam-scope test reviewing the real target-fit register at a fixed 2026-09-29: the South East deferral approved 2026-10-02 was refused as not yet in force. The test now reviews at the latest approval across the committed registers, inside every live window, so a new approval cannot make it premature while an expired entry still fails as the real review would. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Automated review pass (Claude Code, high effort) — round 3 at
|
| Item | Status | Evidence |
|---|---|---|
| Engine-free CI | Fixed at 5720b80d (CI still running at post). |
At 427bec73 the UC pins were fixed (81 and 19, test_uk_uc_family.py:360-361), but engine-free failed on test_uk_national_graph.py::test_national_gates_evaluate_the_seam_scope_and_record_the_evidence (assert ['uk_target_fit'] == []): the fixture reviewed exclusions at 2026-09-29 while 747313a signs the SE £12,570–15,000 deferral as approved 2026-10-02, so the gate called it premature. 5720b80d replaces the five hard-coded dates with _review_date(), the latest approved_on across the five registers, and asserts it precedes the earliest expiry. That fixes it without pinning a date the next approval would break, and an expired entry still fails. |
New in 5720b80d: certification signatures |
Correct, and worth calling out. | _verify_part_signature and _sign_certification now canonicalise with the battery's canonical_report_bytes instead of the logbook's canonical_json_bytes. The two differ on floats (1.0 vs 1, 1e-05 vs 0.00001), so the old verifier would have refused every real battery report while passing float-free synthetic fixtures. I found no other certification verifier still using the logbook form. |
| access_fund input-mass parity | Closed as a signed deferral; the period fix is owed. | It is now signed: approved_by juaristi22, dated 2026-10-04, expiring 2027-01-04, with the diagnosis. One record carries 98% of the candidate's access-fund mass (£1.01bn against £160m), and calibration takes it and its two CGT copies to the 10× weight bound. So the release would ship £1bn of access fund that is almost certainly wrong. The fix could be small: in the spine, treat this record's access fund as annual (or cap it at the scheme maximum). That would be better than publishing with the deferral. If it stays deferred, the release notes should name it. |
| New deferrals (jsa_income_reported, working_tax_credit_reported) | Accepted, with a note. | Both are signed, dated, expire 2027-04-04, and give their reasons: the SPI channel's stage-2 QRF imputes these legacy leaves onto taxpayer rows, and the 30 September main candidate was already at +428% and +421%. Since WTC closed in April 2025, the follow-up she lists (the SPI channel's legacy leaves) should land before these expire. |
| Readout tool | Closed. | tools/uk_residential_readout.py is committed, and --help runs. The by-band numbers need licensed weights, so I didn't reproduce them. |
| Receipts' £127bn wording | Closed. | Arm B's line is marked superseded (experiments/1063-uk-spine-followups.md:51-60). It now gives the held mass on the final spine: the donor holds £127.3bn off the mortgaged tenure (£111.6bn of it other-property mortgages), and the recipient frame holds £273.1bn on 1,386 households, with zero identity violations. |
| Plan-2 exclusions | Renewed here; main is still past expiry. | This branch has slc.borrowers.plan_2_liable and plan_2_above_threshold at 2026-11-03. On origin/main (c1611fbf, 4 Oct) both still say 2026-10-03, and no separate main PR exists. So UK builds from main fail at the exclusions step until this merges. So this PR should merge as soon as CI is green, or the renewal goes to main on its own. |
Locally at 427bec73: test_uk_uc_family, test_uk_weighted_integrity, test_uk_battery_bindings and the shared test_contract all pass. engine-uk, integration-uk and lint are green in CI; engine-us was still running.
|
Thanks. Round 2 addressed at 5720b80. CI's engine-free lane had two failures, not one: the UC registry pins you found, and
🤖 Generated with Claude Code |
…tification (#1063) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ale (#1095) #1089's certifier signed three input-mass exclusions on 2026-10-04: income-based JSA (+1,058% against the enhanced-FRS reference) and Working Tax Credit (+747%), both carried by the SPI channel's stage-2 legacy-benefit leaves, and the access fund (+535%), one FRS household at the calibration's weight bound. spi_benefit_coherence zeroes the two leaves on SPI rows, and on arm A9 (the review head d89a3dd on main) the calibrated columns sit at GBP 97.7m (+316%) and GBP 149.6m (+103%) and the access fund at GBP 258.6m (+62%), its household off the bound: all inside the 452% fence, so the release-cut input_mass_parity gate fails the three entries as stale. They are retired, as in 7efa9d0; dfe_education_spending stays. The evidence pin returns to d28a1fd6..., the register's digest before the three were signed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) #1089 (2fe7d8b) moved the SPI Table 3.6 employment, self-employment and private-pension amounts by total-income band to HMRC's band growth (hmrc.itl_2026.total_income_growth_by_total_income_band) by editing the generated uk/target_references.json, which it also re-serialised with literal pound signs. The population contract still declared the flat OBR average-earnings, per-capita mixed-income and private-pension indices for the three targets, so regenerating from feed 825406f gave e8f829... against the committed bf7549..., and the feed-gated test_committed_surfaces_regenerate_from_pinned_feed[national] failed on main (CI skips it without the licensed feed). The contract now declares the band-growth index, with notes saying so, for the three targets, and both generated resources are regenerated: the references equal the committed ones as parsed JSON (only the encoding returns to the generator's), and the membership report, which still recorded the flat-index uprating for the 39 references, now records the band factors (-2.3% for 15,000-20,000, +0.3% for 20,000-30,000). Compiled values are unchanged: the three lowest employment bands stay at GBP 17.7bn, 47.5bn and 172.5bn, and the national compile parity regenerates and passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's should-fix on #1100: retiring the access_fund input-mass exclusion left the period-code defect it recorded with no active record. The FRS weeklyises ACCSSAMT from the reported amount and its period code ACCSSPD, and an access-fund award is paid per academic year or term. On the 2024-25 tab the 16 awards' calendar-month amounts run up to the size of a whole annual award, so an award read as monthly can annualise to more than ten times every annual-coded award; #1089 had to sign an exclusion when calibration took such a household to the weight bound. access_fund_annual reads ACCSSPD: a calendar-month award (code 5) that annualises to more than twice the largest annual-coded award (code 52) on the tab is read as its per-period amount, ACCSSAMT x 52/12. On the 2024-25 tab that repairs fewer than 10 awards and leaves large but plausible monthly amounts as reported, as it does the awards with no period code. A tab without the ACCSSPD column refuses. The spec names the rule, the test and H2 fixtures carry ACCSSPD, and the coverage manifest and H2 fixture are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) #1089 (2fe7d8b) moved the SPI Table 3.6 employment, self-employment and private-pension amounts by total-income band to HMRC's band growth (hmrc.itl_2026.total_income_growth_by_total_income_band) by editing the generated uk/target_references.json, which it also re-serialised with literal pound signs. The population contract still declared the flat OBR average-earnings, per-capita mixed-income and private-pension indices for the three targets, so regenerating from feed 825406f gave e8f829... against the committed bf7549..., and the feed-gated test_committed_surfaces_regenerate_from_pinned_feed[national] failed on main (CI skips it without the licensed feed). The contract now declares the band-growth index, with notes saying so, for the three targets, and both generated resources are regenerated: the references equal the committed ones as parsed JSON (only the encoding returns to the generator's), and the membership report, which still recorded the flat-index uprating for the 39 references, now records the band factors (-2.3% for 15,000-20,000, +0.3% for 20,000-30,000). Compiled values are unchanged: the three lowest employment bands stay at GBP 17.7bn, 47.5bn and 172.5bn, and the national compile parity regenerates and passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's should-fix on #1100: retiring the access_fund input-mass exclusion left the period-code defect it recorded with no active record. The FRS weeklyises ACCSSAMT from the reported amount and its period code ACCSSPD, and an access-fund award is paid per academic year or term. On the 2024-25 tab the 16 awards' calendar-month amounts run up to the size of a whole annual award, so an award read as monthly can annualise to more than ten times every annual-coded award; #1089 had to sign an exclusion when calibration took such a household to the weight bound. access_fund_annual reads ACCSSPD: a calendar-month award (code 5) that annualises to more than twice the largest annual-coded award (code 52) on the tab is read as its per-period amount, ACCSSAMT x 52/12. On the 2024-25 tab that repairs fewer than 10 awards and leaves large but plausible monthly amounts as reported, as it does the awards with no period code. A tab without the ACCSSPD column refuses. The spec names the rule, the test and H2 fixtures carry ACCSSPD, and the coverage manifest and H2 fixture are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) #1089 (2fe7d8b) moved the SPI Table 3.6 employment, self-employment and private-pension amounts by total-income band to HMRC's band growth (hmrc.itl_2026.total_income_growth_by_total_income_band) by editing the generated uk/target_references.json, which it also re-serialised with literal pound signs. The population contract still declared the flat OBR average-earnings, per-capita mixed-income and private-pension indices for the three targets, so regenerating from feed 825406f gave e8f829... against the committed bf7549..., and the feed-gated test_committed_surfaces_regenerate_from_pinned_feed[national] failed on main (CI skips it without the licensed feed). The contract now declares the band-growth index, with notes saying so, for the three targets, and both generated resources are regenerated: the references equal the committed ones as parsed JSON (only the encoding returns to the generator's), and the membership report, which still recorded the flat-index uprating for the 39 references, now records the band factors (-2.3% for 15,000-20,000, +0.3% for 20,000-30,000). Compiled values are unchanged: the three lowest employment bands stay at GBP 17.7bn, 47.5bn and 172.5bn, and the national compile parity regenerates and passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's should-fix on #1100: retiring the access_fund input-mass exclusion left the period-code defect it recorded with no active record. The FRS weeklyises ACCSSAMT from the reported amount and its period code ACCSSPD, and an access-fund award is paid per academic year or term. On the 2024-25 tab the 16 awards' calendar-month amounts run up to the size of a whole annual award, so an award read as monthly can annualise to more than ten times every annual-coded award; #1089 had to sign an exclusion when calibration took such a household to the weight bound. access_fund_annual reads ACCSSPD: a calendar-month award (code 5) that annualises to more than twice the largest annual-coded award (code 52) on the tab is read as its per-period amount, ACCSSAMT x 52/12. On the 2024-25 tab that repairs fewer than 10 awards and leaves large but plausible monthly amounts as reported, as it does the awards with no period code. A tab without the ACCSSPD column refuses. The spec names the rule, the test and H2 fixtures carry ACCSSPD, and the coverage manifest and H2 fixture are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) #1089 (2fe7d8b) moved the SPI Table 3.6 employment, self-employment and private-pension amounts by total-income band to HMRC's band growth (hmrc.itl_2026.total_income_growth_by_total_income_band) by editing the generated uk/target_references.json, which it also re-serialised with literal pound signs. The population contract still declared the flat OBR average-earnings, per-capita mixed-income and private-pension indices for the three targets, so regenerating from feed 825406f gave e8f829... against the committed bf7549..., and the feed-gated test_committed_surfaces_regenerate_from_pinned_feed[national] failed on main (CI skips it without the licensed feed). The contract now declares the band-growth index, with notes saying so, for the three targets, and both generated resources are regenerated: the references equal the committed ones as parsed JSON (only the encoding returns to the generator's), and the membership report, which still recorded the flat-index uprating for the 39 references, now records the band factors (-2.3% for 15,000-20,000, +0.3% for 20,000-30,000). Compiled values are unchanged: the three lowest employment bands stay at GBP 17.7bn, 47.5bn and 172.5bn, and the national compile parity regenerates and passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's should-fix on #1100: retiring the access_fund input-mass exclusion left the period-code defect it recorded with no active record. The FRS weeklyises ACCSSAMT from the reported amount and its period code ACCSSPD, and an access-fund award is paid per academic year or term. On the 2024-25 tab the 16 awards' calendar-month amounts run up to the size of a whole annual award, so an award read as monthly can annualise to more than ten times every annual-coded award; #1089 had to sign an exclusion when calibration took such a household to the weight bound. access_fund_annual reads ACCSSPD: a calendar-month award (code 5) that annualises to more than twice the largest annual-coded award (code 52) on the tab is read as its per-period amount, ACCSSAMT x 52/12. On the 2024-25 tab that repairs fewer than 10 awards and leaves large but plausible monthly amounts as reported, as it does the awards with no period code. A tab without the ACCSSPD column refuses. The spec names the rule, the test and H2 fixtures carry ACCSSPD, and the coverage manifest and H2 fixture are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) #1089 (2fe7d8b) moved the SPI Table 3.6 employment, self-employment and private-pension amounts by total-income band to HMRC's band growth (hmrc.itl_2026.total_income_growth_by_total_income_band) by editing the generated uk/target_references.json, which it also re-serialised with literal pound signs. The population contract still declared the flat OBR average-earnings, per-capita mixed-income and private-pension indices for the three targets, so regenerating from feed 825406f gave e8f829... against the committed bf7549..., and the feed-gated test_committed_surfaces_regenerate_from_pinned_feed[national] failed on main (CI skips it without the licensed feed). The contract now declares the band-growth index, with notes saying so, for the three targets, and both generated resources are regenerated: the references equal the committed ones as parsed JSON (only the encoding returns to the generator's), and the membership report, which still recorded the flat-index uprating for the 39 references, now records the band factors (-2.3% for 15,000-20,000, +0.3% for 20,000-30,000). Compiled values are unchanged: the three lowest employment bands stay at GBP 17.7bn, 47.5bn and 172.5bn, and the national compile parity regenerates and passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's should-fix on #1100: retiring the access_fund input-mass exclusion left the period-code defect it recorded with no active record. The FRS weeklyises ACCSSAMT from the reported amount and its period code ACCSSPD, and an access-fund award is paid per academic year or term. On the 2024-25 tab the 16 awards' calendar-month amounts run up to the size of a whole annual award, so an award read as monthly can annualise to more than ten times every annual-coded award; #1089 had to sign an exclusion when calibration took such a household to the weight bound. access_fund_annual reads ACCSSPD: a calendar-month award (code 5) that annualises to more than twice the largest annual-coded award (code 52) on the tab is read as its per-period amount, ACCSSAMT x 52/12. On the 2024-25 tab that repairs fewer than 10 awards and leaves large but plausible monthly amounts as reported, as it does the awards with no period code. A tab without the ACCSSPD column refuses. The spec names the rule, the test and H2 fixtures carry ACCSSPD, and the coverage manifest and H2 fixture are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #1063. On
main(after #1084). Receipts:experiments/1063-uk-spine-followups.md.The eight items and the fold-ins
Items 1, 2, 4 (c1): the SPI income band donors become a mass-conserving support channel. Each band seats
max(120, ceil(published taxpayers / 250))donors at equal weights, funded in proportion from the households of each donor's region; no created mass, graph policydeclared, an identity-keyed seating (saltspi_income_band_donor_draw) the E8 receipt reruns from ids with the licensed tape.Item 3 (c2):
mass_increasing_supportleaves the coverage validator.Items 5, 6 (c3+c4): WAS wealth is coherent with tenure (no mortgage debt off mortgaged tenure, no main-residence value off owner tenures) and with its own totals (property and financial wealth derived from their components, identities asserted at cleaning); new gate
uk_stage_was_wealth_coherence.Items 7, 8 (c5, c6, c5b): the residential-property flag is carried as weight by a new expansion stage,
cgt_residential_split, after the incidence anchor: each liable gainer's solved probability splits the household into arms atp·wand(1 − p)·w(2^karms forkgainers), so the residential count and gains are identities on HMRC Table 8a in every gain band at design weights, with no draw and no seed; calibration decides between the arms as it does for the incidence clones. The asset-type stage types the arms and fits Table 7 once per claimant status with an error-diffusion walk (seed 554 retired). The per-band walk of c5 is replaced because its gains error in the open band was bounded by one stake several times the band's expectation.Fold-ins: salary sacrifice predicted only for people who are paid (c7); Child Benefit claims and opt-outs redrawn after the SPI chain against HMRC's August 2025 statistics in a new
child_benefit_take_upstage (c8).Release cut (c9): the certifier rehearsal's five blockers cleared at their source (candidate label, export surface read without ids and with the weight, 43 declared outputs allow-listed,
incapacity_benefit_reporteddropped at the release boundary, FRS 2024-25'sTRAIN2read, the LCFS donor floored at 0 with a receipt, three signed register entries). The plan-2 measure exclusions are renewed to 2026-11-03.Certifier: parts are verified, and the certificate signed, over the gate battery's canonical bytes; the logbook's Chronicle: one append-only trace for every build attempt at every rung #628 form the certifier used renders
1.0as1, so every real signed report failed to authenticate while the float-free fixtures agreed, a latent defect reached once the gates all passed. Regression test added.Identity receipts after the pensions PR: since microcosm#1069 c9 the
salary_sacrificestage lowers a converted record's pay in place, after the CGT support split and the incidence anchor banded on it, so the E8 recomputes banded 2,797 clone carriers on post-sacrifice pay and failed on the final build's spine. The stage now keeps a converted record's pre-conversion pay onsalary_sacrifice_pre_conversion_pay(an internal carrier, dropped at the release boundary) and the identity tool reverses the conversion for every receipt of an earlier stage; the residential split walks the liable gainers inperson_idorder so its arms are bitwise identical for any row order. The certifier's non-negative and QRF tail gates read export-dropped declared outputs from the spine frame.Target registry: the SPI 2023-24 Table 3.6 employment, self-employment and private-pension amounts by total-income band are projected to 2025 with HMRC's band-specific Income Tax Liabilities growth, as the count, total-income and tax rows by band already were, instead of a flat national index. The flat average-earnings index raised the £15,000 to £20,000 band's employment amount 10.7% while HMRC projects the band's total income down 2.3%; the three lowest employment targets move from £18.7bn, £53.8bn and £190.4bn to £17.7bn, £47.5bn and £172.5bn, and the frame's design-weight gaps from 20 to 31% to 15 to 22%. The remaining gap is the frame's composition of the low bands, documented in the receipts note as a follow-up.
Measured so far (licensed local arms, nothing released)
shippable: true, candidate aa31bdf6…). The compile-parity receipt was re-signed for the band-aware Table 3.6 amounts and the staleadult_emaexclusion retired.Tests
Stacked PRs get no CI here. At the stack head: 983 targeted tests, the engine-free lane (6,294 passed; the two failures were the extras-free-venv and importlib-mode environment checks), the engine-UK lane (137), the integration smoke build and the parity fixture tests pass; the c9 commit was checked on its touched files plus the engine-UK lane and the smoke build.
Open calls
other_residential_property_value(WASDVHseVal) excludes buy-to-let, which sits in the drawn remainder.dwp/uc_payment_distcells join the uk-data#452 measure exclusions (to 2026-11-26): SINGLE 28,800–30,000 (one supporting household) and COUPLE_NO_CHILDREN 22,800–24,000 (two, design weights 1,025 and 1,999 against 2,761), whose awards left their bands when the larger donor block reordered the rows the later positional draws read. Keying those draws by identity is a follow-up.🤖 Generated with Claude Code