Repository navigation
Weight UK BRMA assignment by census private-rented households - #1087
Conversation
The frs_brma stage drew BRMAs in proportion to row counts of the 2019-20 LHA list of rents. Its Scottish, Welsh and Northern Ireland lists are byte-identical copies of English BRMAs' lists (matched on the April 2019 rate), so those nations' draws ignored their rental markets: Greater Glasgow had 2% of the Scottish entries against 16% of Scotland's private renters. Replace brma_rent_counts.json with brma_private_rented_households.json: private-rented households by region and BRMA from the censuses (England and Wales 2021, Scotland 2022, Northern Ireland 2021), using the bedroom band matching each LHA category (A and B one bedroom, C two, D three, E four or more; Northern Ireland has no bedrooms question, so its counts weight every category). The generator pins the households CSV by sha256 and row count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ange Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-pin the generator to the revised households CSV, whose Northern Ireland rows now come only from NISRA and NIHE sources (each BRMA's households times NI's private-rented share). Pin the committed cells in CI by digest and by each nation's census total, test the fail-closed path through assign_brma_by_cell, give the generator and test one staged-CSV path, and re-pin the UK spine graph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings #1087 up to main 07bbb65 (128 commits). Two conflicts, both regenerated pins rather than hand-picked: - release_input_coverage_manifest.json: took main's file and reran tools/build_uk_release_input_coverage_manifest.py. Its only diff from main is the 17 source_manifest_sha256 pins moving to the merged source_stages.json (ebcde058...). - microcosm-graph uk_spine/uk_spine.json: took main's file and rewrote it from uk_spine_graph(). Its only diff from main is the frs_brma stage_contract_sha256 (5b8f0b36... -> 4285376b...), the value this PR already pinned. Main did not touch frs_brma.py, the BRMA resource loader or the BRMA tests; the frs_brma stage in source_stages.json, spec/sources.yaml, country_package.json and the parity fixture auto-merged to main plus this PR's resource rename. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The resource rename lengthened load_brma_count_resource past ruff format's line width; main's copy was format-clean. No stage contract, spine graph or identity pin hashes this module's source bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ted households Sol review of 766df94 (P3 nit): the docstring still described the old rents table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both conflicts were in generated files, so each was regenerated with the repo's own tool after the merge rather than resolved by hand: - release_input_coverage_manifest.json: tools/build_uk_release_input_coverage_manifest.py. The 17 conflicting source_manifest_sha256 values now all equal the SHA-256 of the merged source_stages.json (19cac0f6...). The output is identical whichever side was used as the placeholder, and --check passes. - uk_spine/uk_spine.json: tools/graph_uk_spine_fixture.py. The output equals the semantic 3-way merge (frs_brma's stage_contract_sha256 from this branch; child_benefit_take_up's and create_uk_frs's from main). Every other file the generator writes matched the merged fixture byte for byte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main moved again (the #1095 UK data ports and the policyengine-uk 2.122.2 / policyengine-core 3.32.19 lock). The same two generated files conflicted, and each was regenerated with the repo's own tool after the merge: - release_input_coverage_manifest.json: tools/build_uk_release_input_coverage_manifest.py. The 17 source_manifest_sha256 values all now equal the SHA-256 of the merged source_stages.json (5c1c7040...). The output is identical whichever side was the placeholder, and --check passes. - uk_spine/uk_spine.json: tools/graph_uk_spine_fixture.py. The output equals main's graph with this branch's frs_brma stage_contract_sha256, the only node field the branch changes. Every other file the generator wrote, including sources/fixture.json, matched the merged fixture byte for byte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hand-off to the UK hub: ready to land on its gates (d830)Head: Merge resolution. Both merges conflicted in the same two generated files. Each file was regenerated with the repo's own tool, not hand-resolved:
Parity with policyengine-uk-data 1.58.0 (#516).
Independent review. A GPT-6.1 Sol delta review ( Tests.
State. MERGEABLE, CLEAN, not a draft, and no CHANGES_REQUESTED review. Nothing is pending on this session's side, and it depends on no other PR. Per d830, uk-data 1.58.0 was published on 2026-10-07, so this can land on its gates. Evidence: 🤖 Generated with Claude Code |
|
Landed by the UK hub on the gates, per Max's d830: it lands right after the uk-data batch release, and policyengine-uk-data 1.58.0 was published 10/7. Handed off by session local_8586070c.
|
What changes
The UK
frs_brmastage drew each benefit unit's Broad Rental Market Area in proportion to the row counts of the 2019-20 LHA list of rents (brma_rent_counts.json). That list's Scottish, Welsh and Northern Ireland lists are byte-identical copies of English BRMAs' lists, each matched to the English list whose 2019 30th percentile is nearest the nation's April 2019 rate, so those nations' draws ignored their rental markets. PolicyEngine/policyengine-uk-data#515 has the evidence. For example, Greater Glasgow had 2% of the Scottish entries; the genuine Scottish list gives it 18%, and Scotland's Census 2022 16% of the nation's private renters.This PR replaces the resource with
brma_private_rented_households.json: census private-rented households by region and BRMA, using the bedroom band that matches each LHA category.cells[region][LHA_category][brma]shape, sofrs_brma.py's sampler is unchanged.tools/build_uk_brma_household_table.pyreplacesbuild_uk_brma_count_table.py. It pins the households CSV by sha256 (fd40dae0…) and row count (936). Weight FRS BRMA draws by census private-rented households policyengine-uk-data#516 adds the same CSV, with sources, method, validation and a byte-for-byte rebuild pipeline.The stage's source text and every resource reference (country package, source stages, spec, tests, graph parity fixture) are renamed to match.
Validation of the weights
The check is the within-region correlation of BRMA shares with DWP's Universal Credit households assessed under LHA, averaged over April 2019 to November 2020:
Invariants
Tested in
test_uk_brma_resource.py:assign_brma_by_cellraiseKeyError.sample_categorical_from_countsand the identity-keyed draws are unchanged.Not in this PR
efrs_parity_reference.jsoncompares against an incumbent build. It needs regenerating once the incumbent dataset is rebuilt with the same weights, which happens outside PR CI.cross_grain_private_rent_scotland_brmais waiting for could come from the same Scottish output-area crosswalk. That is a separate change.Review
An independent Opus review (round 1) requested changes, and all of them are addressed:
The UK spine graph is re-pinned for the new resource. Round 2 approved after rerunning the resource tests. A one-count mutation of the JSON fails the CI digest test.
Commands run
pytestonengine_free/uk/test_uk_brma_resource.py,test_uk_take_up_contract.py,test_uk_frs_spine.py,engine_free/shared/test_country_spec.py,test_spec_engine_country_bundles.pyandtest_spec_engine_identity_contracts.py: all passed. The regeneration test ran withUK_BRMA_HOUSEHOLDS_CSVset.engine/uk/test_uk_release_input_coverage.pyandmicrocosm-graphengine/uk/test_acceptance_h_parity.pypass after regenerating the coverage manifest and the pinned spine graph.ruff checkandruff format: clean.python3 tools/ci_test_plan.py verify: ok.Update 2026-10-05: main merged, parity with uk-data#516, review
origin/main(fcbda41, no rebase), then formatting and a changelog fragment (766df94). Two files had conflicts:release_input_coverage_manifest.jsonand theuk_spine.jsonparity fixture. Both keep main's content; only the source-manifest hashes and thefrs_brmacontract hash change, and the review rebuilt the latter independently. All 15 of this PR's changes survive, and every file that changed only on main keeps main's contents and modes.fd40dae0…).tools/emit_uk_brma_distribution.py, is fixed in d23bd3e; that docstring is the only change.🤖 Generated with Claude Code