Repository navigation
Conversation
|
Hand-off at Validation: 45 targeted tests passed in the foreground with Target-only impact: constituency Pearson r 0.110184; LA r −0.019566. Areas moving >5%/>25%/>100%: 607/427/69 of 650 constituencies and 333/263/86 of 360 LAs. UC household totals remain 6,095,661 and 6,095,645, preserving existing rounding. Birmingham 5,828→175,630; Hackney 70→38,243; Glasgow City 6,728→84,123. Correcting country shares changes child bucket totals; each area now sums exactly. Open items for the hub: independent review at this head; copy proposed queue row 17 from |
|
Independent review with execution (UK hub, GPT-6.1 Sol, The UC fix is correct.
To fix before the batch (round 2):
Scope additions ruled:
This PR joins the next uk-data batch, which merges on Max's go. |
|
Round 2 hand-off at
Validation: 45 passed with Impact remains target-level. No rebuild, recalibration, licensed-record read or data-file push. Recalibration stays in queue row 17, pending hub GO. Hub should dispatch independent review at this head; batch merge awaits Max's GO.
|
Fixes #468.
Local UC targets followed Stat-Xplore workbook order while calibration rows followed unrelated area-code orders. Birmingham therefore received 5,828 households instead of 175,630, and constituency counts already on 2024 boundaries were also passed through the 2010→2024 mapping.
The parser now matches every area to a canonical code, preferring supplied codes and otherwise normalising names, including Welsh bilingual labels. Missing, duplicate, unknown or ambiguous matches raise before rescaling (
policyengine_uk_data/utils/uc_data.py:20). Getters return code-indexed targets (policyengine_uk_data/targets/sources/local_uc.py:73,:118).Both constituency paths add UC totals and children columns after boundary mapping, then align by code (
policyengine_uk_data/datasets/local_areas/constituencies/loss.py:130;policyengine_uk_data/calibration/matrix_builder.py:234). Both LA paths also select UC by their actual target-row codes (policyengine_uk_data/datasets/local_areas/local_authorities/loss.py:117;policyengine_uk_data/calibration/matrix_builder.py:267). The children split takes country from each matched code and uses integer apportionment so its four buckets sum exactly to the area's total (policyengine_uk_data/targets/sources/local_uc.py:99). Database ETL now keys all 1,010 local UC targets by the parser's matched codes and canonical names (policyengine_uk_data/db/etl.py:432).Code alignment also exposed five unchanged Scottish constituencies represented by 2010 codes in the mapping source (
policyengine_uk_data/datasets/local_areas/constituencies/boundary_changes/mapping_matrix.py:8). Those codes are canonicalised, and mapped targets are explicitly reordered to the requested 2024 rows before the country mask is applied. On main only 593 of 650 mapped positions agree with the 2024 code file: every one of the 57 Scottish rows carries another Scottish seat's income, age and housing targets. This PR corrects them as a pure reorder; Scotland's totals are unchanged. SPI income source files and their source ordering are unchanged. The OA LA integration test also exposed imports of removed ONS uprating constants; that path now uses the same year-specificget_ons_income_uprating_factorsAPI as the dense LA builder (policyengine_uk_data/calibration/matrix_builder.py:271).The Scottish non-UC target moves from main to this PR are:
Scotland's totals are unchanged in every row above. These are target-level changes; recalibrated outcomes remain for queue row 17.
The regression tests state these invariants:
&/and, accents and either Welsh bilingual-label order. Explicit codes take precedence; incomplete, duplicate, unknown or ambiguous geography raises.Public target-only impact against
daad71cd26c1is below. Correlation is Pearson's r across all areas; movement meansabs(new / old - 1), with strict thresholds. The old constituency vector includes its erroneous boundary mapping and the old row placement.The national payment-distribution total remains 6,095,654. Existing independent integer rounding leaves the same +7 constituency and −9 LA residuals; this PR preserves that behaviour.
Examples are public Stat-Xplore household counts: Birmingham 5,828 → 175,630; Hackney 70 → 38,243; Glasgow City 6,728 → 84,123. Large constituency moves include Havant 28,570 → 8,609, Sheffield Hallam 20,179.5 → 3,016 and Hazel Grove 23,637.7 → 6,492. Fractional old constituency counts result from the erroneous mapping.
Correcting country shares changes the children-column national sums, while preserving the household-count totals above:
Validation uses a locked Python 3.13.9 venv (
UV_LINK_MODE=clone uv sync --frozen --all-extras), with BLAS/OpenMP threads capped at four. The dev-only pytest-xdist commit6c81e891is reverted in a separate commit.git diff daad71cd -- uv.lock pyproject.tomlis empty. pytest-xdist 3.8.0 is supplied only to the validation environment to accept the requested serial-n 0; neither dependency file changes.UV_LINK_MODE=clone uv sync --frozen --all-extras --python 3.13.9 uv pip install --python .venv/bin/python --no-deps pytest-xdist==3.8.0 execnet==2.1.2 .venv/bin/python -m pytest -n 0 \ policyengine_uk_data/tests/test_local_uc_alignment.py \ policyengine_uk_data/tests/test_local_uc_etl.py \ policyengine_uk_data/tests/test_devolved_housing_targets.py \ policyengine_uk_data/tests/test_la_loss_missing_sources.py \ policyengine_uk_data/tests/test_matrix_builder.py \ policyengine_uk_data/tests/test_uc_payment_distribution_targets.py \ policyengine_uk_data/tests/test_uc_by_children.py::test_scaled_country_children_buckets_match_latest_gb_totals uvx ruff format --check .Results: 45 passed in the foreground (six NumPy matrix-product runtime warnings; value and country-total assertions pass); Ruff: 266 files already formatted (ruff 0.17.1). At the independently reviewed head, all 19 new regression cases fail against
daad71cd26c1, with the following breakdown. Nine detect the bug on unmodified main; the other ten fail for missing API or an unrelated import:AttributeErrorfor the new matcher APIImportErrorRound 2 strengthens both constituency builder cases to check mapped age and employment-income rows before UC values, using an independent boundary aggregation that resolves the Scottish historical destination codes by name. This includes S14000107 (2010 S14000006) and renumbered S14000021. Both strengthened constituency cases fail on values against the seven production modules from
daad71cd26c1(2 expected failures; no API/import failures or skips). Both also reject the review's isolated mutant: restore main'smapping_matrix.py, relabel mapped rows positionally withset_axis(const_2024["code"]), and then select requested rows for the shuffled OA path. Each mutant case reports 570 of 6,500 mapped age/income cells mismatched. All source bytes were restored afterward andgit diff HEADis empty. These negative checks ran serially in the foreground; their XML/logs and reproduction script are in.job/.No dataset was built or recalibrated, and no licensed survey records were read. Recalibrated UC caseload/spending, local target fit and the #452 administrative caseload gap will be measured in the next hub batch build. Proposed rebuild-queue row 17 is prepared in
.job/QUEUE_ROW.mdfor the hub to copy; it has no GO. Merge remains subject to Max's batch go (d833).