Skip to content

Port UK compact source stages and 2024-25 refresh from uk-data #145

Open
11 of 14 issues completed
Open

Description

@MaxGhenis

Parent: #144.

Why

Populace UK can replace the local-geography/matrix path, and the current compact H5 already carries several recent uk-data columns. But if policyengine-uk-data is archived, Populace needs to own the source-stage logic and provenance for those columns instead of relying on uk-data build history.

Scope migrated from uk-data

Open PRs:

Recent merged PRs that need Populace-owned source-stage equivalents:

Acceptance criteria

  • Populace has UK source-stage modules/manifests for these compact-data inputs, with no policyengine_uk_data imports.
  • The compact artifact can be rebuilt for at least the current Populace UK release year and the FRS 2024-25 refresh path.
  • Export-variable gates prove the compact H5 includes the same PolicyEngine-UK variables expected by policyengine.py.
  • Determinism tests cover every stochastic assignment on the live build path.
  • Source flags and diagnostics make synthetic SPI/capital-gains support inspectable without row-order inference.

2026-08-12 update — this issue is workstream E of the UK-migration master epic #665 (it absorbs the source-stage track of the now-closed #144).

Full item list to port, each as a declarative source stage + gate (children filed as picked up); order constraints: wealth before consumption (num_vehicles), income before capital gains.

Acceptance: the microcosm-built spine replaces the certified incumbent H5 in the national build; eFRS parity fixtures beat or match the incumbent on the frozen register with signed differences.

Activity

  1. MaxGhenis commented on Jul 8, 2026

    @MaxGhenis
    ContributorAuthor

    Three portable lessons from policyengine-uk-v2#133 for the SPI source stage this issue tracks:

    1. Region map: uk-v2 found and fixed a GORCODE bug (code 3 skipped → Yorkshire misassigned; corrected to the contiguous 1–12 map). The populace spi_income stage spec should adopt the corrected map from day one and carry a test pinning all 12 regions — the bug lived only in one of the org's two SPI extractors, which is the cost of parallel extraction.
    2. Tape-year naming convention: uk-v2's year folders mix start-year and end-year naming (spi/2021 = end-year, spi/2022 = start-year). The populace stage should declare ONE convention explicitly in the spec (recommend labeling by tax year, e.g. 2022_23, which is unambiguous).
    3. Multi-year tapes + uprating: uk-v2 carries 2020 and 2022 tapes with explicit uprating to 2025–27. The populace stage spec should plan for multiple vintages with declared uprating stages rather than a single hardcoded tape.

    Also worth adopting repo-wide: uk-v2 runs a "Data pipeline dry run" CI job on PRs — a cheap wiring check populace's CI (tests-only) doesn't have; a build-plan dry-run job would catch stage-wiring breaks pre-merge.

  2. juaristi22 commented on Aug 14, 2026

    @juaristi22
    Collaborator

    Workstream E kickoff: child structure, sequencing, and verification plan (2026-08-14)

    WS-E starts now, in parallel with the P1 critical path (#622/#623): only the final spine swap needs the fixed calibration harness — every ingest and imputation stage develops and verifies independently against a frozen parity bar (the incumbent's enhanced_frs_2023_24.h5, the extraction already pinned in uk/efrs_parity_reference.json). Build at the 2023 vintage first; the FRS 2024-25 refresh follows parity sign-off.

    Children (filed as sub-issues of this epic)

    # Issue Depends on
    E1 #677 shared manifest: source_stages.json, operation handlers, StagePlan migration — (lands alone first; coordinate with #666)
    E2 #678 full raw FRS ingest → spine Frame (starts with the raw-vintage audit) E1, #666
    E3 #679 FRS derived layer (council tax, disability, education, proxies, SIC) E2
    E4 #680 stochastic layer (take-up anchoring, identity-keyed draws, LHA/BRMA, flags) E3
    E5 #681 WAS wealth + ISA split + regional property uprating (supersedes PR #181) E2/E3
    E6 #682 LCFS consumption + NEED raking + ETB VAT + services/NHS E5 (num_vehicles)
    E7 #683 SPI channel on the microcosm spine + FRS-only stage 2 E2–E4, #688
    E8 #684 capital gains structure + salary sacrifice + student loans E7, E5
    E9 #685 net-new stages: UC deductions, bus fares (supersedes PR #153), WAS debt E1 + E5/E6; floats
    E10 #686 spine assembly, whole-spine parity, swap acceptance E2–E9, #688, #630
    E11 #687 FRS 2024-25 refresh E10
    — #688 joint E/D adjudication: spine grain at the seam before E7 strata declarations

    Critical path: E1 → E2 → E3 → E4 → E7 → E8 → E10, with E5 → E6 alongside and E9 floating. Incumbent releases after ebf733c widen only E11 — the parity bar stays frozen through E2–E9.

    Architecture doctrine (applies to every child)

    Country-agnostic first; the US build is the model. Gates the US exercises that uk/gates.json doesn't declare get declared into the shared battery per child (nonnegative_columns, enum_domain, support, aggregate_admin, macro_realism, …) — declarations and bindings only, no UK gate code. Operation kinds reuse or generalize existing vocabulary; UK-flavored kinds only where semantics are genuinely UK. Every child PR carries a UK-specificity note listing any UK-specific code and why it could not be general. Rules-engine dependencies run through a thin, country-parameterized adapter (shared materialize_rules_engine_predictors operation; engine country must match dataset country; per-stage predictor lists declared in the manifest).

    Verification (per stage, then whole-spine)

    Per stage: StageRecord.nonzero_share vs the committed 145-column parity reference (CI-checkable, tolerances as test literals); weighted-total deltas vs the licensed 131-column register (published SDC-safely, min count 3); tail-concentration recording (#609 instrument — accumulates toward arming the weighted-integrity gates); three-level determinism (bit-identity, row-permutation identity-stability, manifest-declared seeds). Whole-spine + swap (E10): candidate extraction diffed against the frozen reference, control-vs-candidate staging builds compared with tools/compare_uk_h5_payload.py, the full battery in release-candidate posture, and a committed signed-differences register — anything differing that is not in the register is a defect.

    Corrections to this issue's framing (found during planning)

    1. Record count: the doubling applies once — (16,364 base + 10,000 zero-weight SPI-synthetic) × 2 CGT clone + 780 band donors = 53,508 pre-clone; × 10 OA clones = 535,080. The CGT band donors do not start at zero weight; only the SPI stack does.
    2. Rules-engine breadth: not just LHA/BRMA and the DSA split — nearly every incumbent imputation stage materializes formula-computed QRF predictors (household_net_income, capital_income, council_tax, total_income, current_education, …) through a mid-build Microsimulation. Hence the adapter doctrine above.
    3. Grain mismatch: the parity instruments pin the pre-clone eFRS; the staging build consumes the post-clone certified H5 — Adjudicate the UK spine grain at the ingest/calibration seam #688 adjudicates the seam jointly with Calibrate the UK national build from Ledger-backed targets #623.

    Key adjudications recorded (2026-08-14)

    • CGT: port the structure (doubling + clone flag + band donors), keep the merged Impute capital gains amounts from the published joint distribution #560 amounts stage, drop the incumbent's in-build torch sigmoid-blend — equal clone mass split at importance kind; calibration (Calibrate the UK national build from Ledger-backed targets #623) binds the chronicle CGT band facts. Signed difference.
    • Defects not replicated, fix-and-sign: WEEKS_IN_YEAR uniformly; council tax ported post-uk-data#449 with per-nation signed deltas (uk-data#448); owned_land support receipt; UC take-up stays 0.55 for the parity build (uk-data#452 tracked against WS-D caseload binding).
    • Stage-internal anchors (NEED/Ofgem, DfT, road fuel, SLC stocks, salary-sacrifice headcount): chronicle-fact-fed where the family exists, else pinned declarations — never Python literals. Chronicle feeds coordinate with in-flight wave-2 work before wiring.
    • Take-up/stochastic parameters: committed build/uk/ resources with citations; the childcare fitting tool is ported (properly seeded) but stays out of the build, matching the incumbent.
    • QRF model caching: shared metadata-keyed cache tooling ships default-off; builds refit per-run from seeds.
    • Post-calibration scalers (rail/bus/fuel/bus-fare gradient): out of WS-E — adjudication posted on Calibrate the UK national build from Ledger-backed targets #623.

    Full plan doc (child specs, unknowns register U1–U15, incumbent inventory): uk-microcosm-migration-ws-e-plan.md, ask @juaristi22 for the latest copy.

  3. juaristi22 commented on Aug 17, 2026

    @juaristi22
    Collaborator

    Adjudication recorded (2026-08-17): receives_benefits_in_own_right is produced by E3's frs_education stage — settled with María on the E3 increment (PR #703).

    Context: the column is required by the 145-column coverage contract but named in no child issue's scope. It is a pure derivation over five E2 spine columns (UC/JSA/ESA reported > 0), computed in the QYP context E3 ports, and no other WS-E child claims it. E7 has no rewrite obligation: the incumbent's SPI stage-2 re-imputes the flag's inputs on synthetic donors but never re-derives the flag itself, so donors keeping the stacking default is port-faithful behavior (noted as a known incumbent quirk, not a defect to fix in WS-E).

  4. juaristi22 commented on Aug 19, 2026

    @juaristi22
    Collaborator

    End-of-workstream revisits registered from E5 (#681 / PR #714) adjudications (María, 2026-08-19):

    1. owned_land input-mass-parity reviewed exclusion expires 2026-09-19 (one-month deadline, entry in input_mass_reviewed_exclusions.json). The E5 stability receipt measures a 37.7% national / 2.41× London weighted-total swing between adjacent seeds — the policyengine-uk-data#448 realization-variance class (sparse heavy-tailed WAS farm/estate records). The gate fails the expired entry until the adjudication is renewed, so this cannot silently rot. At the end of the E increments, either: adopt a variance remedy (winsorised donor variable or a separate land imputation per Carry the SSI reconcile per-pass trajectory through raise and record (#447) #448's suggestions) and drop the exclusion, or renew it with the E10 whole-spine evidence.

    2. num_bedrooms predictor quality in the WAS wealth QRF: the 2026-08-19 licensed audit found HBedRmR8 is −8 (UKDS sentinel) for 95.8% of round-8 household-tab rows — the bedrooms question is effectively unasked, and no alternative bedrooms column exists in the tab. E5 recodes the sentinel to 0 (signed difference; the incumbent trains on raw −8s), but a predictor that is ~96% structurally missing carries almost no legitimate signal either way. At the end of the E increments, decide: drop it from the predictor set (a method change vs the incumbent spec), source it differently, or keep-and-document.

    🤖 Generated with Claude Code

  5. juaristi22 commented on Aug 24, 2026

    @juaristi22
    Collaborator

    Filed #757 as the swap child of this issue: everything that must happen after the spine is approved — retiring the incumbent feed (W8/W9/W11, national driver to calibration-only, UK_CANDIDATE_DATASET_NAME to populace_uk_2024), arming the thresholds against the spine's own certified line per the US #327 doctrine, and retiring the workstream-E diagnostic markdowns into gates, regenerable artifacts, or dated archive.

    It is explicitly gated on #747 being reviewed and merged, since every step there either retires a fallback the spine depends on or re-points a threshold at the spine's own line.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions