Skip to content

Lock policyengine-uk 2.145.0, follow its bus fares and bind thin target rows - #1333

Draft
juaristi22 wants to merge 10 commits into
mainfrom
uk-pe-uk-bump-2139
Draft

juaristi22 wants to merge 10 commits into
mainfrom
uk-pe-uk-bump-2139

Conversation

@juaristi22

@juaristi22 juaristi22 commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #1095. #1332 has merged, so this PR now targets main. Implements #1331 with the window decision (b).

The lock goes from 2.134.4 straight to 2.145.0. That release carries PolicyEngine/policyengine-uk#2536 (the fix for PolicyEngine/policyengine-uk#2523) and PolicyEngine/policyengine-uk#2546 (bus fares from the published fares index). It does not stop on 2.141.6 to 2.141.9: those grow every country's water bills by Ofwat's series, and only #2536 gives Scotland its own series and holds Northern Ireland flat.

Summary

Lock and re-derived surfaces

  • uv.lock, the three >= floors and APPROVED_UV_LOCK_SHA256 move to 2.145.0; policyengine-core stays at 3.33.3.
  • The engine pin, the uprating pins' stamp, the concept mapping's engine_version, the concept coverage, the coverage manifest, the source manifest, the H2 fixture and the cited versions re-derive. The engine has 311 inputs (310 at 2.142.0): pip_dl_points, pip_m_points and local_bus_uncapped_single_fare join, and the two PIP categories become formulas that the supplied categories still set.
  • The concept mapping's capital reason follows 2.136.1's rule: a recorded uc_reported_capital of 0 or more is a unit's complete capital.

What the releases after 2.142.0 bring

  • 2.143.0 stacks capital gains on top of taxable income when it splits them between the higher and additional bands, and sets the annual exempt amount against the gains where it saves the most tax. The national calibration binds HMRC's capital gains tax rows; every one stays inside its bound.
  • 2.143.0 gives Northern Ireland's Local Housing Allowance its own freeze and percentile parameters. They hold the Great Britain values for 2024 to 2026, so the baseline does not move; only a reform to one side now leaves the other alone.
  • 2.144.0 adds PIP points inputs and derives a category from them only when none is supplied. Microcosm writes both PIP categories from the FRS, so nothing moves.
  • 2.145.0 prices bus fares from the BUS0415a index by area and fiscal year (below).

Engine inputs: written or left at the default

  • war_widows_pension_reported is written (below).
  • unused_pension_annual_allowance is a formula from 2.142.0, so it is no longer an input: the engine estimates carry-forward from the five previous years.
  • These stay at the engine's default, each for a stated reason:
    • defined_benefit_pension_share (2.142.0). The engine counts a defined-benefit arrangement's input as its contributions times defined_benefit_input_per_contribution, which is 1, so the share would change the annual allowance only for net-pay contributions at 75 and over. employer_pension_contributions.py says so.
    • pension_contributions_via_salary_sacrifice_pre_2015: the FRS records no start date, so all salary sacrifice counts in threshold income (FA 2004 s. 228ZA(6)). That overstates threshold income for arrangements made before 9 July 2015, and so the taper and the charge's reach, in any comparison with HMRC; salary_sacrifice.py says so.
    • pip_dl_points and pip_m_points (2.144.0): the FRS records the award's components, not the assessment's points, and the categories are supplied.
    • local_bus_uncapped_single_fare (2.145.0): the engine's fitted fare table prices cap changes; drawing person-level fares from NTS donors is outside UK bus fares: keep in step with the engine's per-year fares, take the single-ticket share from cap-regime years, and check cap savings against NTS fares paid #1331.
    • pension_annual_allowance_taxable_lump_sum_death_benefits: no source.
    • other_residential_property_secured_debt and non_residential_property_secured_debt: they reach UC only for a unit without a recorded capital figure, and every unit on the spine records one.
    • is_full_year_category_a_director (2.141.7): it applies to 2022-23 National Insurance only.
    • salary_sacrifice_returned_to_income: a legacy input the engine documents as never computed.
  • The release coverage contract lists the enhanced FRS's populated inputs only, so these are outside it.

Two benefit caps and UC capital (2.135.0, 2.136.1)

  • 2.135.0 gives Universal Credit and Housing Benefit a cap each and removes is_benefit_cap_exempt and its parts. The ESA support-group test reads Housing Benefit's specified-benefit exemption, and the UC relationship diagnostic lists both schemes' flags.
  • 2.136.1 values UC property apart, at 90% less secured debt, and shares it over every claimant and partner in the household. A recorded figure is a unit's complete capital and consumes its own share. Every unit on the spine records one, so nothing counts twice.
  • A unit left on the sentinel beside a unit that records the household's property, for UC or Pension Credit, is the one case the engine would count twice. The stage's receipt counts such units, and the UC capital gate now refuses any.
  • Both recorded figures project by GDP per head, as financial capital does, while from 2.139.1 the engine projects other residential property by house prices. The stage's texts say so: by the OBR indices the engine carries, the gap is 1.5% by 2025 and 2.0% by 2026 from a 2024 base.

War Widow's Pension (#1222)

Bus fares (#1331)

  • The 2025 fare-receipt rows move on the engine's window (María's ruling of 2026-10-21, replacing the calendar-year basis of 2026-09-10). Each area's BUS0415a quarter-end index is in force from the start of the quarter it closes and is day-weighted over 6 April to 5 April, as 2.145.0 reads gov.dft.bus.local_bus_fares_index. London and England outside London move by their own series, and England's receipts move as their sum. On the June 2026 release England's factor is 1.0763 (1.0570 on the calendar basis) and London's 1.00001.
  • Parity. The bus parity receipt ties each area's factor to the engine's index ratio, and the engine test holds the tie within 0.1% at the locked engine. At 2.145.0 the two agree exactly.
  • Single-ticket share from the cap years. The NTS stage declares fare_cap_regime (England's £2 cap outside London, whole in 2023 and 2024) and reads the single-ticket share on those years only, because the FRS 2024-25 base year sits under the cap. 2022 stays in the band and trip fit. Outside London the share of fare-paying boardings paid at the point of use moves from 0.70 (2022 to 2024 pooled) to 0.73.
  • Fare-mix lines (report only). The ticket receipt adds, for England outside London: before the cap, the share of point-of-use boardings above £2 and their mean fare; under it, the share paid at £2. A line, or its complement, under 10 unweighted boardings or 10 distinct households reads <10. The 930 receipts doc, Part M, has the readings.
  • The ticket receipt's weight. The receipt divided the household weight out of each boarding's trip weight and never multiplied it back, so every diary household counted alike. It now uses the full trip weight, as the stage's share does. No stage output read the receipt.

Thin target rows (María's rule of 2026-10-21)

  • A target row is no longer left out because its cell rests on fewer than ten records; only a measured distortion of the calibration keeps it out.
  • The support floor drops only rows no source household carries, which the solver cannot fit. Its floor must be 1, and the benefit-cap amount bands join its scope.
  • Thirteen per-row exclusions that rested on thin support retire: the eleven benefit-cap amount bands and the HMRC £500k to £1m dividend and property-income-count rows. Rows with zero support, and rows held out for measured frame gaps or undershoots, stay.
  • A bound row that fewer than ten distinct source households carry keeps its model figures in the build on every line, as BRMA rows' have since Place UK private rent and BRMA at the assigned area; bind Scotland's rents at BRMA grain (#1262, #1090) #1305: the diagnostics, the national gate evidence, the certifier, the national role and the Orrery summary withhold them, loss totals are restated over the published rows, and no run forwards an epoch's loss. The national fit gate decides on the published rows and counts the withheld ones, and a report that names a withheld row stops the build.

Not in this PR

What moves

Measurement

  • One spine on the final head, calibrated twice on that spine: as pushed, and with the thin-row commit reverted, so the two runs differ only in the binding. The measured head is the pushed code locked from policyengine-uk 2.145.0's release commit, which PyPI had not yet published; the pushed lock takes the PyPI release.
  • Over the 1,216 rows bound in both runs, 99% are within 10% in both; one row moved just past 10%. The effective sample size and the share of design weight stretched 9.5 times or more do not change, and the weight-ratio gate passes in both. Every newly bound row is reached, and binding them lowers the stretch on the households that carry them. So no row goes back out.
  • Against Draw UK QRF stages from uniforms keyed on each record's id, and tie pension contributions to pay #1332's head (the spine only), the keyed draws keep changes local: about 3% of households redraw their wealth, 0.3% their home values and 6% their consumption, each where the engine's own values for that household moved; every other change is a small shift from a rake or a scale step.

Tests

Run locally; CI runs on this PR now that #1332 has merged.

  • engine-uk tier: 212 passed on 2.145.0's release commit, whose package files the PyPI wheel matches exactly; the lock and bus-parity tests: 21 passed on the PyPI lock.
  • engine-free, the touched surfaces: 786 passed (6 skipped). microcosm-frame: 1,422 passed. microcosm-graph: 806 passed; the three Orrery parser tests need node modules this machine lacks.
  • tools/spec_engine_coverage.py --check passes (42,184 of 42,184 fields).
  • Mutants: the single-ticket share read pooled, the fare-mix floor on boardings only, the receipt's old weight, and a national fit gate without the withheld filter each fail a test.

🤖 Generated with Claude Code

@vahid-ahmadi

Copy link
Copy Markdown
Contributor

@juaristi22 thanks, this is my review at 6ca0b4b58.

Verdict. The 2.141.1 step is sound. I checked every variable policyengine-uk removed or renamed between 2.134.4 and 2.141.1 (the old benefit_cap, is_benefit_cap_exempt and its three parts, is_benefit_cap_single_claimant_rate, household_uc_reported_capital, and is_benefit_cap_exempt_earnings renamed to the UC one). The build references none of them now, and the two places that did (the ESA test and the UC diagnostic) are updated. The lock is clean: only policyengine-uk moves, both hashes match PyPI, and APPROVED_UV_LOCK_SHA256 matches the file. But this is a waypoint, not the final lock, and the body says so. It cannot merge until pe-uk #2536 is merged and released, and that release will carry eight more releases (2.141.2 to 2.141.9) as well as #2536. Those change water uprating, salary sacrifice uprating, UC deductions and the benefit cap's reported amount, so the coverage, the manifests and "What moves" will all need re-deriving again. Item 1 is the one thing to settle before the final re-lock.

What I ran

  • Fresh worktree at the PR head, uv sync --all-packages --locked --extra uk: policyengine-uk 2.141.1, policyengine-core 3.33.3.
  • tools/ci_test_plan.py verify: passes (engine-uk=54 files, integration-uk=1).
  • Engine tier, every file in list-job engine-uk: 221 tests, all passed.
  • Engine-free, engine_free/ of microcosm-build (uk, shared), microcosm-data, microcosm-frame and microcosm-graph: 13,097 passed, 107 skipped, 3 failed. All three failures come from my environment, not this PR: test_engine_is_reported_unavailable_without_the_uk_extra expects policyengine-uk to be absent, which it wasn't because I didn't hide it, and the two Orrery parser tests need node, which isn't on this machine.
  • The new test_war_widows_pension_leaves_bereavement_support fails with the base's frs_spine.py and passes at the head.
  • Checked against PyPI: the 2.141.1 wheel and sdist SHA-256 in uv.lock, and the upload times of 2.141.1 to 2.141.9.
  • Checked against pe-uk's tags: the removed and renamed variables for 2.134.4 to 2.141.1, and the new variables and uprating changes in 2.141.2 to 2.141.9 and #2536 (head 25b5c3dfb).
  • Recomputed the house price vs GDP per head gap from the 2.141.1 parameters: 1.54% by 2025 and 2.05% by 2026 from a 2024 base, so the stage text's 1.5% and 2.0% are right.
  • git merge-tree against main, UK pre-Budget data: measure stored values at their period, draw Carer's Allowance claims, and the #1278 items (#1324, #1319, #1278) #1329 and Draw UK QRF stages from uniforms keyed on each record's id, and tie pension contributions to pay #1332.
  • Not run: a full build, the seven gates or the measured arm. They need the FRS, SPI and WAS microdata, which I don't use. CI didn't run either (the base isn't main, as the body says).

Findings

  1. must (merge order): go straight from 2.141.1 to the #2536 release, with no stop on 2.141.6 to 2.141.9. At 2.141.1, water_and_sewerage_charges, housing_service_charges, pension_contributions_via_salary_sacrifice, the ISAs and the debt columns are not in uprating_indices.yaml, so they stay flat after the 2024 base (pe-uk 2.141.6 changelog). 2.141.6 (#1863) then grows water by Ofwat's series in every country, 27% in 2025-26, and only #2536 gives Scotland its own series (9.9% in 2025-26) and holds Northern Ireland flat. So a lock on any of 2.141.6 to 2.141.9 would overstate Scottish water bills in AHC housing costs. Today's order is Draw UK QRF stages from uniforms keyed on each record's id, and tie pension contributions to pay #1332, then pe-uk #2536 merged and released, then this PR re-locked on that release, then merged. Two things affect timing. #2536 now conflicts with pe-uk main, since #1863 and #2488, which it merged in, have landed. And it has no approving review yet. A line in the body saying "not on 2.141.6 to 2.141.9" would stop someone re-locking early to unblock it.

  2. should: the DWP benefit cap targets count UC households, but the binding counts both schemes. The fourteen dwp.benefit_cap.* targets (uk_population_targets.json:4394 and :17825 on) cite Table 4's UC households (ledger concepts dwp.uc_capped_households_*). They bind benefit_cap_reduction, which in 2.141.1 is adds = ["uc_benefit_cap_reduction", "housing_benefit_benefit_cap_reduction"]. This isn't new: the single cap before 2.135.0 covered Housing Benefit too. But 2.135.0 is what makes the UC-only binding possible, and this PR adopts 2.135.0. DWP counts 160,000 households capped in UC and 150 on Housing Benefit at May 2026 (Benefit cap: number of households capped to May 2026), so the real gap is small. The model's gap depends on how many legacy HB families it caps, which the measured arm can show. Also, from 2.141.3 the UC part stays the gross reg. 81 amount, and the amount the award actually loses after the floor is uc_benefit_cap_reduction_after_floor. For the amount bands that's the closer concept. This could be a follow-up issue, but it belongs with the final lock.

  3. should: "What moves" and the coverage need another pass on the final lock, and the body should say so. The body lists the effects up to 2.141.1. The #2536 release will also bring:

    • 2.141.2: CTR and Carer's Allowance pension deduction shares as parameters (no change in value);
    • 2.141.3: UC deductions only for units that claim UC, deductions and cap reduction under the protected floor, and the 25% deductions cap dated 12 April 2021;
    • 2.141.5 and 2.141.9: CTR means-tests the applicant and partner, and counts IIDB, SDA and incapacity benefit as income;
    • 2.141.6: the uprating fixes in item 1;
    • 2.141.7: a new input, is_full_year_category_a_director (2022-23 NI only, so it can stay at default);
    • 2.141.8: SDLT purchase schedules and the salary-sacrifice NI cap.

    From #2536 itself: unused_pension_annual_allowance moves from variables/input/ to a formula (gov/hmrc/pensions/unused_pension_annual_allowance.py), so the concept coverage loses it as an input. defined_benefit_pension_share is a new input, and defined_benefit_pension_input_amount is a new formula. The concept mapping should say why the build leaves the share unset. With defined_benefit_input_per_contribution at 1, setting it changes nothing except net pay at 75 and over. The UC benefit cap earnings threshold also becomes £9,516 for 2024-25 and £10,572 for 2026-27, not a flat £10,152, so the benefit cap rows move again. None of this is wrong in the PR. It's the work left for the final step.

  4. should: the receipt for units left on the sentinel should be a gate, and should cover Pension Credit. uc_capital_coherence.py:376-382 counts sentinel units beside a unit that records UC property, but nothing fails when the count is above zero. The PR's safety argument rests on "every unit on the spine records one". That holds for FRS 2024-25 (the _frs_benunit_capital docstring cites the audit: all 18,850 rows populated). But frs_spine.py still maps a blank or negative TOTCAPB4 to -1, so a later survey year could reach it silently. Two more points. recording needs uc_share > 0, so a household whose reference unit reports UC (and so records no UC share) but does record Pension Credit property isn't counted. Yet the module docstring (:103-115) says the Pension Credit proxy double counts there as well. I suggest counting both schemes and adding an == 0 check to the stage's gate.

  5. nit: the body says 2.141.1 was "the newest release on PyPI on 20 October". 2.141.2 was uploaded at 16:24 UTC, five minutes before the re-lock commit was authored (16:29 UTC). By the end of that day 2.141.5 was out, and 2.141.9 is current. Item 3 covers the substance, so this is wording only.

  6. nit: the pre-2015 salary-sacrifice choice leans one way. Leaving pension_contributions_via_salary_sacrifice_pre_2015 at nil puts all salary sacrifice in threshold income (FA 2004 s. 228ZA). For long-standing arrangements that overstates threshold income, and so the taper and the annual allowance charge payers. That's a fair default with no start date in the FRS, but the concept mapping's reason should say which way it biases the HMRC comparison.

  7. nit: Widowed Parent's Allowance stays in bsp_reported. The body leaves it open, which is right for now. Once pe-uk takes bsp_reported off CPI (#2381's step 2), the WPA part of code 6 (about £16m of £123m in FRS 2024-25, by Split War Widow's Pension (FRS code 9) out of bsp_reported #1222's own count) would be frozen in error. Split War Widow's Pension (FRS code 9) out of bsp_reported #1222 should stay open until that's settled, rather than close with this PR.

  8. nit (overlap): UK pre-Budget data: measure stored values at their period, draw Carer's Allowance claims, and the #1278 items (#1324, #1319, #1278) #1329 conflicts with this branch in generated files. git merge-tree of UK pre-Budget data: measure stored values at their period, draw Carer's Allowance claims, and the #1278 items (#1324, #1319, #1278) #1329's head with this head conflicts in release_input_coverage_manifest.json, test_uk_frs_spine.py, the H2 fixture (person.csv, uk_spine.json) and three files from Draw UK QRF stages from uniforms keyed on each record's id, and tie pension contributions to pay #1332. Whichever lands second re-derives the manifest and the fixture rather than hand-merging them. This PR merges cleanly onto main as it stands.

What looks right

  • uv.lock moves only policyengine-uk (2.134.4 to 2.141.1), and the three >= floors move with it. Both artefact hashes match PyPI, and shasum of uv.lock equals APPROVED_UV_LOCK_SHA256 (5a739f00…). No stray 2.134.4 or 2.139.2 is left outside the changelog and experiments.
  • The War Widow's Pension split goes everywhere bsp_reported goes: the spine, graph cells and consumes, the SPI rewrite and fill lists, the restored-report columns and the coherence gate. The new spine test pins code 9 apart from code 6.
  • The ESA support-group test now reads Housing Benefit's specified-benefit exemption, which is the right successor after 2.135.0's split.
  • The capital texts match the engine. In 2.141.1, uc_reported_capital returns -1 unless set, and a set value is the unit's complete capital. Property is valued apart at 90% less secured debt, and the secured-debt inputs are read only by the two UC property variables, so leaving them unset is harmless while every unit records.
  • The house price and GDP per head gap in the stage text is right to the decimal shown.

🤖 Generated with Claude Code

juaristi22 and others added 10 commits October 21, 2026 19:09
Only policyengine-uk moves (2.134.4 to 2.139.2); policyengine-core stays at
3.33.3, which still meets its floor. Nothing the build writes is renamed,
removed, re-typed or moved between entities.

Re-derived as #1308's lock commit did: the uv lock and
APPROVED_UV_LOCK_SHA256, the engine pin, the uprating pins' version stamp
(every pinned value is unchanged), the concept mapping's engine version,
the floors in the three pyproject files and the stage manifests, the
coverage manifest, the H2 fixture, and the version-only texts. The concept
coverage goes from 302 to 308 inputs: unused_pension_annual_allowance
(2.134.5), pension_annual_allowance_taxable_lump_sum_death_benefits and
pension_contributions_via_salary_sacrifice_pre_2015 (2.135.6),
war_widows_pension_reported (2.135.7), and the two property secured-debt
inputs (2.136.1).

The liquid-asset reason follows 2.136.1: uc_reported_capital defaults to -1
and, set, is a unit's complete capital; benunit_reported_capital replaces
the financial sources only, and property is valued apart and shared across
the household's claimants and partners.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pital

2.135.0 gives Universal Credit and Housing Benefit a cap each and removes
is_benefit_cap_exempt and its parts. The ESA support-group test reads
Housing Benefit's specified-benefit exemption, which follows the stored
group for this tenant on income-related ESA, and the UC relationship
diagnostic lists both schemes' exemption flags.

2.136.1 values UC property apart (property_sources at 90% less secured
debt) and shares it across every claimant and partner in the household,
whatever their unit records; a recorded uc_reported_capital is a unit's
complete capital and consumes its own share. Every unit on the build's
spines records a figure, so nothing is counted twice there. The three
engine tests that place units on the -1 sentinel now expect the new
shares, and the stage's texts and notes describe the rule. The receipt
counts any unit left on the sentinel beside a unit that records the
household's property, the one case the engine would count twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The FRS spine summed benefit codes 6 and 9 into bsp_reported. Code 9 is
War Widow's or Widower's Pension, which rises with CPI, while Bereavement
Support Payment's rates are frozen. policyengine-uk 2.135.7 gives the
pension its own input (pe-uk#2382), so code 9 now goes to
war_widows_pension_reported and bsp_reported keeps code 6 (#1222).

The new column goes wherever bsp_reported goes: the spine's outputs, the
graph's stage cells, the SPI fill and rewrite columns, and the reports an
SPI-channel row restores from its FRS twin, with the benefit coherence
gate checking it. The source manifest, the H2 fixture and the gate
digests re-derive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
policyengine-uk's dataset uprating projects both recorded capital
figures, uc_reported_capital and pension_credit_reported_capital, by GDP
per head, as it does financial capital. From 2.139.1 it projects other
residential property by house prices, while non-residential property and
owned land stay on GDP per head. So the other residential property in a
recorded figure grows faster than the engine's own projection of it: by
the OBR indices the engine carries, 1.5% faster by 2025 and 2.0% by 2026
from a 2024 base. The stage's module text and its spec note say so; the
source manifest and the H2 fixture re-derive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
policyengine-uk 2.142.0 carries pe-uk#2536, the fix for pe-uk#2523. It
adds defined_benefit_pension_share and the defined-benefit input amount,
estimates unused annual allowance carried forward when none is supplied,
uses one definition of relevant UK earnings, uprates water and sewerage
charges by country with a Scottish Water series, and derives the UC
benefit cap's earnings threshold from the national living wage. The
lock goes straight there, with no stop on 2.141.6 to 2.141.9, whose
water uprating overstates Scottish bills (Vahid's review of #1333).
policyengine-core stays at 3.33.3.

The floors, APPROVED_UV_LOCK_SHA256, the engine pin, the uprating pins'
stamp (the values do not change), the concept mapping's engine_version,
the concept coverage (308 to 310 inputs), the coverage manifest, the
source manifest, the H2 fixture and the cited versions re-derive.
unused_pension_annual_allowance is now a formula, so it leaves the input
list; defined_benefit_pension_share, is_full_year_category_a_director and
salary_sacrifice_returned_to_income join it and stay at their defaults.
employer_pension_contributions.py says why the defined-benefit share
stays unset, and salary_sacrifice.py which way leaving the pre-2015
input at nil leans (Vahid's review of #1333, findings 3 and 6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From policyengine-uk 2.136.1 a benefit unit on the -1 sentinel takes its
own share of its household's property, which a unit recording the
property beside it already holds, so the engine would count it twice.
The stage's receipt counted such units for UC only; it now counts them
for UC or Pension Credit, since a unit that reports UC records no UC
share but may still record Pension Credit property. The UC capital gate
now refuses any such unit, so the argument that every unit on the spine
records a figure stays checked if a later survey year reaches the
sentinel (Vahid's review of #1333, finding 4). The gate's notes and
digests re-derive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ipt lines (#1331)

The NTS bus stage declares fare_cap_regime: England's £2 single-fare cap
outside London, whole in the 2023 and 2024 survey years and absent in 2022,
with a penny's tolerance. The stage reads the single-ticket share on the cap
years only, because the FRS 2024-25 base year sits under that cap; 2022 stays
in the band and trip fit. The ticket receipt adds fare-mix lines for England
outside London: before the cap, the share of point-of-use boardings above £2
and their mean fare; under it, the share paid at £2. A line reads <10 when it,
or its complement, rests on fewer than 10 unweighted boardings or 10 distinct
households.

The receipt now also weights each boarding by the full trip weight. It
divided the household weight W2 out for the person-level sums and never
multiplied it back, so every diary household counted alike in its shares and
fares. No stage output read the receipt.

The test donor and the H2 fixture's donor now spread every region over every
survey year, so the cap years hold London donors. Receipts Part M has the
engine-free readings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María's rule of 2026-10-21: a target row is never left out because its
cell rests on fewer than ten records; only a measured distortion of the
calibration keeps it out. The floor of ten governs what is published.

- The support floor drops only rows no source household carries (the
  solver's initialiser refuses those). Its floor must be 1, so a count
  floor cannot come back through the register. The benefit-cap amount
  bands join its scope.
- The per-row exclusions that rested on thin support alone retire: the
  eleven benefit-cap amount bands and the HMRC £500k to £1m dividend and
  property-income-count rows. Rows with zero support, and those out for
  measured frame gaps, stay.
- A bound row that fewer than ten source households carry keeps its model
  figures in the build on every line, as BRMA rows' have since the #1305
  review. uk_withheld_rows counts every row. The national gate kernel
  blanks thin rows in its evidence, restates the manifest's losses over
  the published rows and refuses a report that names a thin row. The
  national fit gate decides on the published rows and counts the withheld
  ones, and every parity-evidence producer states its withheld set, so a
  missing one fails closed. The certifier skips withheld rows, the
  Orrery size summary publishes no all-row total, and no run forwards an
  epoch's loss.

The four-household seam fixture and the three-household toy graph would
withhold every row, so those pipeline tests lower the count to one or
publish every row, and the withheld path has its own tests, including a
national seam whose only row is thin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María's ruling of 2026-10-21 replaces the calendar-year basis of
2026-09-10: the 2025 England and London fare-receipt rows move from
2024-25 as the engine's model year does. Each area's BUS0415a quarter-end
index is in force from the start of the quarter it closes and is
day-weighted over 6 April to 5 April, as policyengine-uk reads
gov.dft.bus.local_bus_fares_index (fiscal_year_blend,
PolicyEngine/policyengine-uk#2546). London and England outside London
move by their own series and England's receipts move as their sum, as
the engine prices each area by its own index. On the June 2026 release
England's factor is 1.0763 (1.0570 on the calendar basis) and London's
1.0000086.

The bus parity receipt also ties each area's factor to the engine's
index ratio (its measurement year over its benchmark year), and the
engine test holds the tie within 0.1% at the locked engine. The target
references are unchanged; the membership and the national compile-parity
receipts re-derive from the pinned feed, the two fare rows only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
policyengine-uk 2.145.0 carries pe-uk#2536 (the fix for pe-uk#2523) and
pe-uk#2546 (bus fares follow the BUS0415a index by area and fiscal
year). Since 2.142.0 it also stacks capital gains on taxable income
across the higher and additional bands and sets the annual exempt amount
where it saves the most tax (2.143.0), gives Northern Ireland's Local
Housing Allowance its own freeze and percentile parameters (2.143.0),
and adds PIP points inputs, from which it derives a category only when
none is supplied (2.144.0). policyengine-core stays at 3.33.3.

The floors, APPROVED_UV_LOCK_SHA256, the engine pin, the uprating pins'
stamp (the values do not change), the concept mapping's engine_version,
the concept coverage (310 to 311 inputs: pip_dl_points, pip_m_points and
local_bus_uncapped_single_fare join at their defaults, and the two PIP
categories become formulas that the supplied categories still set), the
coverage manifest, the source manifest, the H2 fixture and the cited
versions re-derive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juaristi22 juaristi22 changed the title Bump the UK lock to the newest policyengine-uk (2.141.1, then the #2523 fix release) Lock policyengine-uk 2.145.0, follow its bus fares and bind thin target rows Oct 21, 2026
@juaristi22
juaristi22 changed the base branch from uk-keyed-draws-pension-coherence to main October 21, 2026 20:33
@juaristi22 juaristi22 closed this Oct 21, 2026
@juaristi22 juaristi22 reopened this Oct 21, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants