Repository navigation
Lock policyengine-uk 2.151.0 and write the UK inputs it reads (#1095, #1278) - #1383
juaristi22 wants to merge 47 commits into
Conversation
The fifteen dwp.benefit_cap rows (the total and the fourteen amount bands of DWP's Benefit cap tables to November 2025, Table 4) bound benefit_cap_reduction. That variable adds the Housing Benefit cap and keeps the gross regulation 81 amount, while DWP counts Universal Credit households by the amount the award loses. Every row now binds uc_benefit_cap_reduction_after_floor at benefit-unit grain, and the measurement names the UC reduction. The total was the incumbent's 0/1 household indicator; it now counts the benefit units the bands partition, and the complementary withholding covers the closer difference. Regenerated on abf0921 (the national references from the feed cut to the national and local-authority rows): the target references move on the total's entity alone, household to benefit unit; the membership report and the national compile-parity receipt are unchanged. The diagnostic tool reads the bound variable, and the reviewed population variables add it. The OBR Universal Credit rows split by cap status keep benefit_cap_reduction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tire María's ruling of 2026-10-22 extends the zero-support floor to the national families. Its share ceiling sums published values, so the register (schema 4) now holds the floor's rows in scopes of one unit, each with its own ceilings: the UC payment-distribution and benefit-cap bands (benefit units, as before), the HMRC SPI income-band counts, the HMRC SPI income-band amounts, and the band-H council-tax rows by region. A test checks that every scope holds one unit. Measured on #1333's 2.145.0 spine, every HMRC £1m-and-over cell and every band-H region cell has carriers, so their thirteen entries retire and the rows bind, with their figures withheld where fewer than ten source households carry them. Plan 5's liable stock fits at design weights and drifts only while unbound, so its entry retires too. The OBR split of UC spending at the welfare cap and the England postgraduate repayments leave the targets for registry_parity.excluded: no household concept marks the welfare-cap boundary, and the stage assigns no postgraduate plan. obr.universal_credit still binds the sum of the two cap cells. Regenerated on abf0921: the national references and membership lose the three retired rows (1,322 to 1,319 active), and the compile-parity receipt signs them as fixture-only with their reasons. The other held rows keep their entries until arm 1 re-measures them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María's ruling D3 of 2026-10-08 held obr.vat out until a locked policyengine-uk split the constant survey-coverage factor in vat. policyengine-uk#2187, released in 2.135.7 and inside the 2.145.0 lock, does that. On #1333's 2.145.0 arm the row, measured while held out, already sits inside the 25 percent bound at both the design and the calibrated weights, so its entry retires and the row binds. The notes declare the residual the row keeps: OBR's receipts include VAT on private school fees from 1 January 2025, which policyengine-uk's current-law vat leaves out until policyengine-uk#2319. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s 95% intervals The #731 scorecard measured period 2024 against HBAI FYE 2024, but period 2024 is FRS FY2024/25, which HBAI calls FYE 2025 (uk-data#487). The new microcosm.build.uk_runtime.hbai_validation reads the four statistics the pinned feed carries for FYE 2025, each with DWP's 95% confidence interval and the release it came from: the median equivalised household income and the share of individuals in relative low income, before and after housing costs. It reports each measured statistic inside or outside its interval and refuses a missing statistic or fact; it never binds a row or fails a build (María's rulings of 2026-10-16 and 2026-10-20). scorecard_731.py takes --hbai-facts and writes an hbai_validation block at engine year 2024; the FYE 2024 reference figures it compared the other HBAI-shaped rows with leave the script, and those rows stay as diagnostics. The classifier is tested on fixture facts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…imation microcosm writes no self_employment_gross_receipts: no source of the self-employed's turnover is read yet. Since policyengine-uk 2.108.0 the trading allowance replaces expenses and does not stack on them, so without receipts trading_allowance_deduction relieves a profit of £1,000 or less in full and gives a larger profit no allowance, which puts taxable profit at most £1,000 a person from where receipts would put it (#1095). UK_ENGINE_DEFAULT_INPUTS, beside the take-up register in the concept mapping module, signs the approximation with that bound, as the plan for the next policyengine-uk bump set by default. An engine test checks each entry is an engine input the mapping never binds, and an engine-free test that no spine column in the H2 fixture's schema writes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María's ruling of 2026-10-17 left property_purchases, regional_home_values and uc_legacy_closure_take_up ungated for a follow-up. Each now has a release-blocking stage-health gate that blocks on an absent receipt: - uk_stage_property_purchases_fit: each purchase kind is drawn once, draws HMRC's Stamp Tax transactions within 5 percent, and fits HMRC's value less a recorded shortfall of at most one fifth, the floor the stage itself refuses below; the individuals' shares are proper shares. - uk_stage_regional_home_values_ranking: rows are re-ranked in every English region and Wales on the 2024 knots, at the weighted midpoint within each FRS region, with no source at the value cap. - uk_stage_uc_legacy_closure_take_up_contract: the Move to UC receipt withholds what a thin combination realizes, so the gate checks what it prints: the design-weight Great Britain basis, a probability and a declared source for each rate, a printed support band, and a well-formed unreachable flag. All three pass on #1333's 2.145.0 spine receipts. The gates join the spine scope, the data contract's battery map and certification scope, and the mirrored battery digests move. The H2 parity fixture does not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tape's Special Conditions add two obligations to the End User Licence: no attempt to attribute a record to a named individual, and analyses of the tape go to HMRC at least ten working days before they are distributed or published. Nothing in a build's outputs said which of them rest on the tape. microcosm.build.uk_runtime.spi_dependency reads which of a run's stages declare the tape among their artifacts (the spec's ukds_study_number, written bare or as "SN 9422"). The spine's build record carries the marker, spine_provenance_from_sidecar carries it into the calibrated candidate and its signed diagnostics, and both release assemblers restate it in release_manifest.json: on the microdata's artifact entry (spi_public_use_tape_dependent) and, with the conditions, under licensed_data. The assemblers rederive it from the stages the signed provenance names, through the packaged spec, and refuse a recorded marker that disagrees or a stage the spec does not declare; a provenance from a spine built before the marker records none, and the rederived one stands. On the packaged roster three stages read the tape. How SPI-dependent outputs are released stays María's ruling; the marker records the dependency only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Arm 1 (calibrate-only on #1333's 2.145.0 spine at the Phase A head) bound the ten HMRC £1m-and-over cells that A2 released. Bound, they moved neighbouring rows of the SPI channel that had fitted closely out of the 10 percent band, one cell stayed outside the release fit bound, and the arm's uk_target_fit gate failed; the other six gates passed. Under María's rule of 2026-10-21 a measured distortion keeps rows out, so the ten are held again as a family, re-signed to 2027-01-23 with that reason, pending a split that binds the cells which do not distort. The register names no figure of theirs or their neighbours': they rest on the SPI Public Use Tape. The band-H region cells, Plan 5's liable stock and obr.vat reached their targets on the arm without stretching their carriers' weights, and stay bound. The floor's adjudication and the changelog say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The twelve UC payment bands and Plan 5's repayments lapsed on 2026-11-26, the two Plan 2 stocks too, and the any-tenure housing-element count on 2026-11-14. Arm 1 (calibrate-only on #1333's 2.145.0 spine) measured each unbound at its calibrated weights, close to #1333's own arm: - every one of the twelve bands stays outside 10 percent, eleven short and one over; they stay on their own renewals until the award-band take-up of #1344 binds them (María's ruling of 2026-10-21); - the Plan 2 coverage gap stands; - Plan 5's repayments: fewer than ten source households carry them, so the reason gives no figure and the row's figures are withheld; - the housing element sits at the other/unknown-tenure gap itself. The rows rest in large part on the households of the SPI support channel, so the reasons give no new figure of theirs (SN 9422). Each entry is re-signed on 2026-10-23 to 2027-01-23, and the adjudications keep their history. The tests follow the new dates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María's ruling of 2026-10-23 extends the ten-household floor for published figures, with its complementary check, to constituency and local-authority rows; the area-support rule still decides which local rows bind. uk_withheld_row_sets and uk_thin_rows now take every row, in blocks: the national, regional and BRMA rows in one span, as before, and the local rows one grain and area at a time, since the local surface is too large for one dense span and binds many families per area. The positive-weight slice of the problem is built once for all blocks. The report guard matched a bare area code for every withheld key, which suits a BRMA's one family but would stop a dense build on any published row in a constituency with one thin row. It now takes the bare codes explicitly, and uk_withheld_gate_areas gives them for withheld BRMA rows only; a withheld local row is matched by its family/area/metric key. The dense terminal phase passes both. Tests: a thin row is withheld at every level; in one constituency a family total less its published band gives a thin band back, so the next band is withheld beside it, while a thin row in another area stands alone; and the guard names a published row of another family in the same constituency but refuses the withheld key and a withheld BRMA's code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
experiments/1095-uk-next-bump-phase-a-receipts.md records how Phase A was measured without a new spine: #1333's 2.145.0 arm as the control, arm 1 (calibrate-only on its spine with every candidate row bound) and arm 1b (the plan's contingency run, with the HMRC £1m-and-over cells held again). Arm 1 failed uk_target_fit on one of those cells and moved neighbouring SPI-channel rows out of the 10 percent band; arm 1b passes all seven gates, with the shared rows' fit, effective sample size and stretched share as on the control, and the band-H region rows, Plan 5's liable stock and obr.vat at their targets. It also records why the rows still held are renewed. The receipt names no SPI-channel row and gives no count of source households. It gives no row's model figure that rests on fewer than ten source households or in large part on the SPI channel's households. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The integration-uk smoke build blocked at phase 'transferred' on two of the gates a6280dba1 added. Both check the frame against published facts, which a synthetic fixture is not: it holds a few regions, so the regional home-values receipt rewrites three of the ten regions, and it sizes its own purchase targets to its few households, so the non-residential draw misses its count by more than 5% and the receipt carries none of HMRC's individuals' shares. Both entries now declare population_fact_check, as #1069 did for the Pension Credit take-up gate: a smoke build records their failures in the report and continues, and every other posture blocks on them as before. The legacy closure gate holds only the receipt's own contract, which the fixture meets, so it stays blocking in every posture. A test pins all three. The mirrored battery digests move. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María's ruling of 2026-10-23: weekly amounts annualise at 52 wherever a weekly or monthly rule reads them. policyengine-uk reads an annual amount back to a weekly or monthly one at policyengine-core's 52 weeks before such a rule tests it, so at 365.25 / 7 every FRS weekly amount read 0.34% high at Housing Benefit, Council Tax Reduction, Pension Credit, the non-dependant deductions and the hours tests. #1329 made the State Pension the first amount at 52 (her ruling of 2026-10-20); it is now the rule, not an exception. - frs_spine.WEEKS_IN_YEAR is 52, and STATE_PENSION_WEEKS_IN_YEAR leaves the spine; the readers that import the constant follow it (council tax, disability, education grants, legacy proxies); - the HMRC replay leaves mirror it, and their declared formulas say * 52; - the private-rent localisation keeps its own copy, now 52, so it imports nothing of the build; - the spec's annualize_periodic_amounts operation declares 52 for every amount and drops the State Pension exception; its prose and the HMRC leaf formulas say 52; source_stages.json, the release input coverage manifest and the H2 parity fixture are regenerated. LCFS spending keeps 365.25 / 7 and NTS trips 52.14, since no weekly rule reads them back. A new test holds every reader to the one constant; the State Pension and manifest tests follow. The 0.34% shift is measured on arm 2, the bump's one new spine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The UK lock moves from 2.147.2 to 2.151.0 (policyengine-core stays at 3.33.3), the first release past pe-uk#2573 and #2580 and the newest on PyPI. The uprating pins' stamp, the concept coverage (314 to 335 inputs), the coverage manifest, the H2 fixture, the cited versions and APPROVED_UV_LOCK_SHA256 re-derive; no uprating value moves. One engine test follows the new engine: since 2.149.0 a claim for Universal Credit ends an income-related ESA award (pe-uk#2563) and the engine's default unit claims it, so the ESA support-group test's tenant, on legacy ESA, now claims no Universal Credit. The gambling duty inputs of pe-uk#2590 stay at their defaults (microcosm#1359). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…526) policyengine-uk 2.148.1 (PolicyEngine/policyengine-uk#2571) projects stored domestic energy spending from the price period a dataset declares in its root energy_price_basis attribute, and keeps undeclared spending at its stored prices in every later year. A Microcosm H5 declared none, so every later year kept the 2024 prices lcfs_consumption sets (PolicyEngine/policyengine-uk#2526, its remaining item 2). The one physical UK writer now declares {"period_type": "calendar_year", "period_value": 2024} wherever the household table stores any of the three columns the engine projects from a declaration, with the keys sorted as the engine writes its own. The period is the one the stage-time gate uk_stage_lcfs_consumption_basis holds every LCFS spend level to (microcosm#1113), and a test keeps the two equal. An H5 without energy declares nothing; a reload and rewrite declares it again. An engine-tier test reads it back through policyengine-uk and checks the columns are the engine's own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) policyengine-uk 2.146.0 (pe-uk#2549) closes a legacy award through its owners: the claimant and partner, or a member's own award, which closes on its own. The uc_legacy_closure_take_up draw still read every member's reports, so an award a dependant claims in their own right could put the family in the draw, or keep it out as a Universal Credit unit (legacy_closure_take_up.py, flagged in #1095's bump item). The reports that set a unit's combination, and its Universal Credit status, now come from members marked is_claimant_or_partner, the FRS adult roles the spine already writes. The graph node declares the read, the operation names its reporters, and the spec, its schema entry and source_stages.json follow. A new test runs a dependant's own ESA (the family stays out of the draw) and a non-claimant's Universal Credit (the family stays in it); the stage refuses a frame without the column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From policyengine-uk 2.149.0 a claim for Universal Credit ends a claimant's or partner's income-related ESA. The UC take-up redraw kept each unit that holds a legacy benefit at its earlier single-rate flag, which sets many units reporting ESA, and no UC, to claim it, so the engine would end their ESA at the calibration year. A unit whose claimant or partner reports income-related ESA, and that neither reports Universal Credit nor is moved off its legacy benefits, now claims none: it was on the award at the interview, and a reported receipt is a fact. The rule is declared on the operation (kept_legacy_award) and the closure draw, which reads the same flag, sees it too; the receipt bands the units it keeps off UC. Housing Benefit, which the engine also ends on a claim, keeps the stored flag pending the HB and JSA PR (#867, #869). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María's ruling of 2026-10-23: Scotland opens in the Carer's Allowance draw. The stage kept it closed because Carer Support Payment reads the same flag and policyengine-uk did not apply its earnings limit; since 2.146.1 (PolicyEngine/policyengine-uk#2473) it does, so a drawn Scottish carer is paid only under Carer Support Payment's own limit. The eligible set loses its Scotland mask, and the receipt reports Scotland apart: its eligible support band, weighted persons (withheld under ten sources) and drawn support band, in place of the closed-region check. The texts, the spec and source_stages.json follow. The engine tier now checks that a drawn Scottish carer under the limit is paid Carer Support Payment and one over it is not, and the stage-through- engine test draws the Scottish carer over the 2024-25 limit and finds them paid at 2025. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FRS benefit code 6 is Bereavement Support Payment with its predecessors, and the spine summed it all into bsp_reported. policyengine-uk 2.149.0 (pe-uk#2572) gives Widowed Parent's Allowance its own input, because it is taxed and means-tested where the payment is not. María's ruling of 2026-10-22: split code 6 by rate, after a private check of the amounts. A weekly amount within 1% of a Bereavement Support Payment rate's weekly equivalent (GBP 350 or GBP 100 a month, frozen since 6 April 2017; at 12/52 for a month, quarter or year and at 1/4 for four weeks) stays bsp_reported; any other goes to widowed_parents_allowance_reported. The new column goes wherever War Widow's Pension goes: the spine's outputs, the SPI support and spine lists, the SPI benefit-coherence restore and its gate, the graph, the spec and the export allow-list with its gates.json mirror. The mirrored digests move, and source_stages.json and the coverage manifest are regenerated. A parametrised test runs each rate's two weekly equivalents, the edges of the 1% band either side, and amounts off every rate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
policyengine-uk 2.149.0 (pe-uk#2572) adds spousal_maintenance_income, which Universal Credit (UC Regulations 2013 reg. 66(1)(d)), Pension Credit and Housing Benefit count, unlike the child maintenance in maintenance_income. The spine read no alimony at all, and kept APAMT, the allowances from a husband or wife who lives away, in private_transfer_income. María's rulings: ALIAMT, or ALUAMT where ALIUS 2 says the last amount was not the usual one (2026-10-22), plus APAMT, which the FRS asks only of married adults whose spouse is away or separated (2026-10-23, after a private check of the recipients). APDAMT, the household bills such a partner pays directly to third parties, stays a private transfer. The new column goes to the spine's outputs, its non-negative outputs and the export allow-list with its gates.json mirror; an adult tab without the three alimony columns refuses, as one without SPPADJ does. Tests read each ALIUS answer, refuse each missing column, and keep every FRS field in one income column. The H2 fixture's adults carry the three columns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
policyengine-uk 2.149.0 adds pension_contributions_via_bonus_sacrifice, which the GBP 2,000 NICs exemption cap from April 2029 and the annual allowance tests read summed with salary sacrifice (pe-uk#2572 section 1). Microcosm wrote salary sacrifice only, so a costing of the cap left out the bonus route the OBR costs (#1340). María's ruling of 2026-10-22: impute it; the OBR's base starts in 2027-28, after the calibration year, so it anchors the stage instead of binding the calibration. - frs_spine writes frs_bonus_amount, each adult's gross occasional bonuses over the last 12 months from the JOB tab (BONAMT1-6, a bonus given after tax with its imputed weekly tax over the year); a tab without the fields refuses, and the carrier leaves at the release boundary. - salary_sacrifice gains a third operation after the salary conversion. Candidates are adults with a bonus whose pay without it reaches the upper earnings limit, the 2% band the OBR costs bonus sacrifice at. Each converts the whole bonus, within half the pay and the room left above the other routes, out of pay, in the order of identity-keyed draws, until the engine's projection of the converted bonuses to 2027-28 (each year's growth compounded, the threshold on the two routes summed) is nearest the OBR's base. The receipt bands its support on source households and withholds the base under ten. - The OBR's Table 1.1 tax base is vendored from the pinned feed (obr_salary_sacrifice_costing_facts.json, a streamed copy of tools/vendor_uk_ledger_facts.py's output), and the stage verifies it first. tools/pin_uk_bonus_sacrifice_anchor.py writes uk/bonus_sacrifice_anchor.json from it and the locked engine's earnings and population growth and upper earnings limit; an engine-tier test holds the anchor to the installed engine and the bonus route's excess to the engine's own cap arithmetic. - The spec, its schema and operation registry, the declared seeds, the graph's output cells, the export allow-list and its mirror (digests re-pinned) and the H2 fixture's jobs follow. The HMRC salary-sacrifice rows, which ASHE builds, keep binding the salary route alone, and a test says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
policyengine-uk 2.149.0 (pe-uk#2572) adds liquid_fuel_consumption and solid_fuel_consumption, parts of housing that add nothing to consumption. The LCFS stage left the diary's heating oil, bottled gas and solid fuels inside the housing remainder with no column. María's ruling of 2026-10-22: LPG with liquid, heat in the remainder, and the ONS 04.5 row measured on electricity, gas, liquid and solid fuel. - The donor split writes each fuel from its labelled parts (b017, c45312, b018, c45222; c45411, c45412); both are annualised, uprated to calendar-2024 prices on the CPI fiscal bridge as every diary spend column is (the consumption-basis gate reads them), and drawn last in the chain so every earlier draw is the chain's own. - The housing recomposition nets their draws and adds them back, so the total always holds them; a household whose drawn parts outgrow its drawn total keeps at least its fuels. - The recomposed-totals receipt's uncarried block becomes published_fuels: ONS 04.5.3 and 04.5.4 beside each fuel's donor total at diary prices and the frame's draw at stage weights. The stage-time gate recomputes the published rows; the spec, its schema, the graph's cells and the stage's outputs follow. - ons.household_energy_expenditure, which the contract keeps for registry parity and the reference surface signs out as superseded by its fuel rows, reads the four fuels through a value expression; its signed rationale no longer says the frame lacks liquid and solid fuel. - The consumption drift block reads the two fuels where the frame carries them, so an older spine keeps its block, and uk_consumption_drift_flags gives warn-only flags at #1278's R1 thresholds (2 percent for a total, half a point for a share), outside the diagnostics payload so its v8 schema stays as it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each COICOP division whose frame total per household stands above its donor's by more than the twelve divisions together do comes down to that shared ratio before the hold to the donor maximum; no other division moves. A recomposed total moves by its remainder alone, so the levelled parts keep their published levels. Declared as level_division_excess on the recompose operation; the receipt records each division's ratio and factor, and the stage-time gate checks them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1095) The WAS property draw of María's ruling of 2026-10-23. Three draws are appended after consumer debt, each from the holders of the column it rests on, so the first eight segments draw as before: - the directly held fraction of the share-like holdings outside ISAs, from which directly_held_shares (WAS UK shares plus employee shares and options) and unit_and_investment_trusts (WAS collective investments) are written on the final corporate_wealth less the ISA, so the three sum to corporate_wealth and the engine's share_like_capital does not move (pe-uk#1974); - the debt secured on other residential property and on non-residential property, zero where the asset is zero and scaled down together where they would pass the mortgages on other property. The recorded UC and Pension Credit capitals and the reporter redraw's screen net each class's debt after the costs of sale, floored at zero per class (UC Regs 2013 reg 49(1)(b); SPC Regs 2002 reg 19(b)), as the engine values UC property capital. The donor cleaning refuses debts that pass the other mortgages; the wealth coherence gate holds the split and the debts as identities; the four columns are reviewed export extras. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#953) policyengine-uk applies the single adult household 25% discount from 2.148.0 (pe-uk#1864, council_tax_discount_rate). The new contract row mhclg.council_tax_stock.single_adult_discount counts England households at that rate against MHCLG Council Taxbase line 8, all bands, the England row of the latest October return not after the build base period. The billing-authority cells bind in the next dense build; no incumbent row has this definition, so it is an unmapped declaration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
policyengine-uk projects the 2024 dataset to the 2025 calibration year and relabels every holder by a course started at 18; the stage dates a course from the age its borrower left full-time education (#868, #1299). The engine test pins where the two disagree: a course dated after 2012 by its leaving age but before by the age rule becomes Plan 1, and a 1993 course is written off, so the calibration measures the engine's plans at 2025. An engine that keeps the stage's dating fails it, and the SLC rows are then re-measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Arm 2 of the next bump (one spine and one calibration on policyengine-uk 2.151.0) re-measured the rows still held, unbound at its calibrated weights. Since #1344 draws UC take-up by award band, four of the twelve UC payment-distribution bands come within 10 percent, so their entries retire and the rows bind (the plan's rule: bind a held row that fits); the eight that stay keep their 2026-10-23 renewals, their reasons restated on arm 2. The four Housing Benefit rows and DWP's JSA claimants stay outside the 25 percent bound at design weights. Their 2026-12-08 entries are renewed, signed on 2026-10-24 to 2027-01-24, pending the Housing Benefit and JSA PR (#867, #869). The two ONS energy rows, held out since #1113, keep their entries; their reasons add arm 2's consumption drift block, on which electricity and gas spend and the gas-connected share stay within the warn-only flags between the design and the final weights. The UC bands rest in large part, and the Housing Benefit and energy rows in part, on households of the SPI support channel, so their reasons give no new figure (SN 9422). The JSA row's claimants at arm 2 are all in FRS households, and its reason gives its figures. The register tests follow the counts and the dates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…atio The plan of 2026-10-22 set a default on the open 7270-versus-7271 ruling (microcosm#890 G): bind orr.rail_government_support on ORR table 7271's net operational government support from all sources, unless an arm measures a distortion. Arm 2c, a calibrate-only run on arm 2's spine with the row bound on table 7271 beside the four UC bands, did: the row reached its target, but the weights concentrated past the release bound, uk_weight_ratio failed, and the effective sample size fell by about a tenth. So the row stays held out on table 7270's basis, its entry keeps the 2026-12-11 window, and its reason and adjudication record the measurement. The basis ruling stays open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
experiments/1095-uk-next-bump-phase-bc-receipts.md records how the 2.151.0 lock and Phase C were measured: the control on main, arm 2 (one spine and one calibration at the bump head), arm 2b (calibrate-only on arm 2's spine with the four UC payment bands bound) and arm 2c (with the ORR row bound on table 7271 as well). Arm 2 and arm 2b pass all seven gates; arm 2c fails uk_weight_ratio, so the ORR row stays held. It also records each Phase C item's check and why the rows still held are renewed. The receipt names no SPI-channel row and gives no count of source households. It gives no row's model figure that rests on fewer than ten source households or in large part or in part on the SPI channel's households. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@juaristi22 thanks, this is my review at Verdict. The bump is careful work and CI is green at the head. The lock, the new inputs and the What I ran
FindingsMust
Should
Nit
What looks right
Merge order
🤖 Generated with Claude Code |
|
Fixed the cross-geography subtraction gap in The publication layer now withholds all local-authority, constituency and BRMA/statistical-scope model figures until joint publication safety across geographies is established. This also applies to separate BRMA-only files and stale caller-provided suppression sets. Administrative target facts stay available. Public gate details cannot disclose hidden local values through numerical errors or named failure messages. Private calibration values and fit-gate decisions are preserved: a failed local fit still blocks release. This is a conservative restriction on published diagnostics; it does not implement a general joint solver or retroactively repair old artifacts. Independent review found no new defects in this repair. The exact snapshot passed 364 focused tests, including synthetic parent-minus-child reconstruction cases and private failing-fit enforcement. Ruff and test-layout verification also passed. No licensed records were used. |
|
@juaristi22 thanks, this is my second review, at Verdict. The must is fixed for disclosure. Every constituency, local-authority and BRMA model figure is now withheld from published diagnostics, so a region row less its published local rows has nothing left to give back. But the redaction also reaches the full gate report that the local sign-off tool reads, and that tool now refuses every local build, a passing one included. It also drops the signed local exclusions from the release manifest without saying so. Nothing leaks either way, but the local release line cannot be signed off at this head. CI is also red: one engine-free test still patches a name the commit removed. The 16 shoulds and 7 nits from round 1 are unchanged: the delta touches only the withholding code, and the PR body has not been edited since. What I ran
Status of round 1
2 to 17 (shoulds) and 18 to 24 (nits): open, no change at New findings in the deltaShould
Nit
What looks right
Merge orderUnchanged from round 1: this PR, then #1381, then my #1373. If you take the private/public split in item 25, #1381's shared files (the diagnostics and the gate kernel) will need a rebase. 🤖 Generated with Claude Code |
|
Pushed d48652be to repair the synthetic graph fixture and align Orrery assertions with mandatory local withholding. The fixture bypasses only carrier-span selection; local publication suppression and private fit-gate decisions remain active. Validation: 395 targeted tests pass, and independent verification passes 143 tests, both on Python 3.13. Ruff formatting and lint pass. Hosted Python 3.14 validation is pending. This test-only follow-up preserves the reviewed PR history and leaves its |
…nors Vahid's review of #1383, items 5 and 6, and María's rulings of 2026-10-24. A bonus sacrificed is never received, so the FRS records it in neither pay nor its bonus amounts (the FRS 2024-25 derived-variable notes, SN 9563, add received bonuses to UGRSPAY). The stage took candidates' received bonuses out of pay, which lowered taxable pay before the HMRC and SPI rows rebound it. Now a candidate is an adult with a bonus whose pay reaches the upper earnings limit, and its sacrifice, the bonus up to half its pay, is added beside pay, which stays as it is; the room rule against the other routes and the pre-conversion pay for bonus-only rows go. The received bonus marks a bonus-paying job and its size. An SPI-channel adult carries its FRS twin's bonus beside the tape's pay. It now draws a bonus share of pay from a base-FRS adult with pay in the same pay cell (weighted pay quantiles, a cell with fewer than 20 donor source households joining the one below), by person weight, keyed on person_id; FRS rows keep their own bonus. The receipt bands the drawn adults on source households. The spec, its schema and source_stages.json declare the new parameters; the coverage manifest and the H2 fixture follow. Tests: the candidate rule, the half-pay bound with no room rule, the stage leaving pay whole, and the SPI draw (share of own pay, the donor floor, stability under a row shuffle, the refusal without donors). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or's same spend Vahid's review of #1383, item 9, and María's ruling of 2026-10-24. Transport's ratio counted petrol, diesel and bus, which the stage levels up to published totals, so its cut landed on its remainder for an over-draw that was not the chain's. A division's ratio is now the spend the chain drew for it per frame household over the donor's mean of the same spend: for housing and transport, the remainder against the donor's total less the same parts (lcfs_donor_drawn_means); for any other division, its whole draw. A division above the divisions' shared ratio, measured once before any levelling, comes down to it. One pass, by her ruling: measured again after each cut, the shared ratio falls until every division sits at the lowest one's, which is close to levelling to the donor totals she ruled out on 2026-10-23. The declaration (rule excess_over_shared_ratio, basis drawn_spend_over_donor_spend_per_household), its schema, the stage's notes, source_stages.json, the coverage manifest and the H2 fixture follow; the stage-time gate's checks hold as they were. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's review of #1383, item 8 and nit 20. COICOP puts liquefied hydrocarbons under 04.5.2 (gas), and c45222 is a 04.5.2 code, so ONS's 04.5.3 leaves out the bottled gas the liquid column holds by María's ruling of 2026-10-22. The published-fuels receipt now gives the donor's liquid fuels without it too, with the concept note, so the ratio to ONS reads the diary's capture and not the concept gap. The column's comment, the stage's notes and the changelog say that both fuels stay at the diary's level, about twice ONS's, unlevelled, so a costing on them would come out near twice ONS's spend. A test pins each fuel's diary parts, bottled gas inside the liquid fuels, and c45511 (hot water, steam and ice) left in the remainder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's review of #1383, item 12. Every code-6 amount at no Bereavement Support Payment rate went to Widowed Parent's Allowance, so a lump sum, a part month or a misreport became a taxable, means-tested allowance. An amount at the allowance's 2024-25 rate (GBP 148.40 a week, DWP's Benefit and pension rates 2024 to 2025; within 1%), or below it as a reduced award, is now the allowance; any other amount, above the allowance's rate and at no rate, stays bsp_reported. An allowance with an inherited additional pension above its rate reads as the payment, and a lump sum spread over a year below the rate reads as a reduced allowance; the rule cannot tell those apart. The spine stage's notes, source_stages.json, the coverage manifest, the H2 fixture and the changelog follow; the test runs both sides of the allowance's rate and a lump sum above it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d to it Vahid's review of #1383, item 10, and María's ruling of 2026-10-24. policyengine-uk's gov.simulation.vat.survey_consumption_coverage, which policyengine-uk#2187 introduced, was derived on the certified Microcosm UK 2024-25 national release so that its VAT meets OBR's 2024-25 receipts. Binding obr.vat therefore mostly pulls the consumption weights back toward that release, after this PR changes the consumption base (the heating fuels and the division levelling), and it binds over the private-school VAT that current-law vat leaves out until policyengine-uk#2319. The row is back on the measured-diagnostics register, signed on 2026-10-24 to 2027-01-24 (a draft for María), and rebinds when policyengine-uk re-derives the factor on a file that does not bind it. The changelog fragment states the final position, and the load test follows the entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ault Vahid's review of #1383, item 4. policyengine-uk 2.148.4 adds housing_benefit_residential_capital_exception, which asks for the working-age residential capital tariff exception pre-assessed (Housing Benefit Regulations 2006 reg. 52(4)-(5), (8)-(9); NI reg. 49), and the build leaves it at False without saying so. It joins UK_ENGINE_DEFAULT_INPUTS with the error it can make: the FRS samples private households and records no assessment of the accommodation or saved circumstances the exception covers, so Housing Benefit is understated only for a qualifying working-age resident, who takes tariff income on capital above GBP 6,000 instead of GBP 10,000. The register's tests (an engine input the mapping never binds, written by no spine column) cover the entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's review of #1383, item 3. The engine test only read the energy_price_basis attribute back. It now also loads a written file through policyengine-uk's Microsimulation and checks that each energy column in 2025 and 2026 is the stored spending times the engine's energy price index over its 1 January 2024 value, every household alike, and that a copy without the declaration keeps its stored spending. The changelog says what the declaration changes and that releases built before it stay undeclared. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's review of #1383, item 11: uk_consumption_drift_flags was called only by its test, so the receipt's drift flag came from a hand run. The UK calibration diagnostics now turn each flagged total or share into a diagnostic_warnings entry (code uk_consumption_drift, severity warning), naming it and the threshold it passed and none of its figures; the payload's v8 schema stays as it is and nothing is gated on them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A scope's share ceiling sums published values, so its unit label must be the unit its targets are counted in. uk_support_floor_target_unit reads it from the contract measurement (a count's entity, or pounds for an amount), and the run's floor input refuses a scope labelled otherwise, beside the approval-window check. The band-H scope was labelled "dwellings"; its rows count households (occupied chargeable dwellings), so it now says so. Vahid's nit 24 on microcosm#1383. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…efusal frs_annual_income's docstring still said current pay annualises at 365.25 / 7; since uk-data#531 it is 52 weeks (frs_spine.WEEKS_IN_YEAR). The restated ons.household_energy_expenditure rationale is signed on 2026-10-24, the day it was restated. The held-rows fragment now says a schema 3 register is refused rather than read, so an old run directory's register no longer replays, and that each floor scope's unit is checked. Vahid's nits 15, 19 and 21 on microcosm#1383. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The take-up contract still applied carers_allowance_newly_entitled to persons outside Scotland, from before Scotland opened in the draw. Its citation and population now say Scotland's carers take the same rate: Carer Support Payment reads the same claim flag, and the contract holds no rate of its own for it. The stage docstring says the same. Vahid's nit 22 on microcosm#1383. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reverts 3ce1fca and d48652b, at María's ruling of 2026-10-24. They withheld every constituency, local-authority and BRMA model figure from what ships, which blanked the local fit evaluation and, as Vahid's second review of microcosm#1383 found, stopped the local sign-off, the release manifest's signed exclusions and the size evaluation (items 25 to 27). Her rule stands: a row that ten or more distinct source households carry publishes its figures; a thin row, and any published row that would give it back by difference, is withheld. The next commit restores the joint check across grains that the must (item 1) asks for. BRMA rows publish from ten households under the national block's check (her ruling of 2026-10-17, re-affirmed on 2026-10-24). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its parents Vahid's review of #1383, item 1 (must): the local withholding checked the local rows one grain and area at a time, so a published region row less its published local cells could give a withheld cell back, and so could a region's constituencies less its local authorities, or a national row less a family's published cells. uk_withheld_row_sets now spans, beside the national block: - each region's rows of every grain, the rows whose positive-weight carriers all live in it (local authorities and constituencies nest in regions); - each local family with its higher-grain parents: the targets the cross-grain declarations (bridges, fan-out, sum and band bridges, partitions) or a nested measurement tie it to (uk_local_family_parents). The blocks overlap, so a row one block withholds beside a thin one is protected in every other block that holds it (any combination holding it counts as too small to give back), and the blocks run again until none withholds another row. Local rows need the frame's household region and refuse without it; the dense gates and the Orrery summary pass each row's contract target. On a synthetic region of 2,218 rows the check takes under two seconds. Tests: a region row less its cells, constituencies less authorities, a national parent less its family's cells, a row withheld by one block kept hidden in another, and the refusal; each mechanism mutant-checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's review of microcosm#1383. Nit 18: the feed vendors MHCLG's Council Taxbase 2025 in its revision of 21 January 2026, whose counts are as at September 2025; the row's selector note and changelog said "the October count", after the feed's 2025-10 period label. Item 13: the FRS 2024-25 asks for alimony or an allowance "from a previous partner" (AliMny), so ALIAMT also holds a former cohabitant's payments, which policyengine-uk's spousal_maintenance_income leaves out; the survey does not say whether the partner was a spouse or civil partner, so the stage's comment and changelog state the approximation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's review of microcosm#1383, item 7. The anchor grows each sacrificed amount with the OBR's average earnings and the weights with the ONS population to 2027-28; the OBR grows its base with employment and earnings. The base is met at the stage's weights, and calibration does not bind it. The stage's comment and the changelog say so; the check of both OBR lines at the final weights is a private receipt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's review of microcosm#1383. The Phase B and C receipts now give the single adult discount count's vintage (as at September 2025, revised on 21 January 2026); the remainders-basis levelling, under which six divisions come down on arm 3's spine and communication keeps its draw; the donor's liquid fuels without bottled gas beside ONS's 04.5.3; the bonus sacrifice rulings and the anchor's growth basis; the bound rows that absorb the 52-week rule (item 15); and the benefit cap's complementary withholding and its Universal Credit scope (item 17). Figures that rest on the SPI channel's households stay with the licensed data; arm 3's calibration receipt follows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
The next policyengine-uk bump (plan of 2026-10-22, microcosm#1095 and microcosm#1278). It locks policyengine-uk 2.151.0, the first release past pe-uk#2573 and pe-uk#2580, and writes the inputs those releases read. One PR of focused commits in three phases, then the rows arm 2 re-measures.
Closes #1340, closes #1320, closes #1222, closes #1349. Part of #1319: Scotland opens in the Carer's Allowance draw, and the back-test and the follow-ups listed there stay open.
Phase A, on the 2.147.2 lock (13 commits; receipts in
experiments/1095-uk-next-bump-phase-a-receipts.md)obr.vatbinds again;Phase B, the lock (1 commit): policyengine-uk 2.147.2 to 2.151.0, policyengine-core unchanged at 3.33.3. The uprating pins' stamp, the concept coverage (314 to 335 inputs), the coverage manifest, the H2 fixture and
APPROVED_UV_LOCK_SHA256re-derive. The ESA support-group test's legacy tenant no longer claims UC, since 2.149.0 ends income-related ESA on a UC claim (pe-uk#2563). The gambling duty inputs of pe-uk#2590 stay at their defaults (#1359).Phase C, on 2.151.0 (12 commits; receipts in
experiments/1095-uk-next-bump-phase-bc-receipts.md)energy_price_basis(pe-uk#2571);The rows arm 2 re-measures (3 commits, with the Phase B and C receipts)
uk_weight_ratio.Measurement
All runs are local and licensed; their outputs stay with the spines. Details are in the two receipts.
uk_weight_ratiofails and the effective sample size falls by about a tenth, so the row stays held on table 7270.Disclosure
No figure in this PR, its commits or its receipts rests on fewer than ten source households or names a record. No row's model figure is given where the row is of the SPI channel or rests in large part or in part on the SPI channel's households: SN 9422's Special Conditions send analyses of the tape to HMRC ten working days before they are distributed, and that ruling is open (#1278). The surface-wide fit and weight statistics are given as in #1308. Publisher figures appear as published. The private checks behind C1, C2 and C10 stay with the licensed data, outside the repository.
Signatures for María to confirm
mhclg.council_tax_stock.single_adult_discount(in-year snapshot, signed 2026-10-23 to 2026-12-11), drafted as the band rows' hold is.ons.household_energy_expenditure(the frame now carries liquid and solid fuel).Not in this PR
Tests
Counted with
--junitxml, on this machine.tools/ci_test_plan.py verify: ok.tools/spec_engine_coverage.py --check: 42,184 of 42,184 configuration fields, 41 of 41 inventory checks.🤖 Generated with Claude Code