Skip to content

Retire the legacy UK ETLs onto publisher-backed facts (#135 PR A) - #181

Merged
juaristi22 merged 2 commits into
PolicyEngine:mainfrom
juaristi22:uk-135-etl-retirement
Aug 20, 2026
Merged

Retire the legacy UK ETLs onto publisher-backed facts (#135 PR A)#181
juaristi22 merged 2 commits into
PolicyEngine:mainfrom
juaristi22:uk-135-etl-retirement

Conversation

@juaristi22

Copy link
Copy Markdown
Collaborator

Summary

PR A of #135: every hardcoded series in the legacy db/etl_obr.py / db/etl_ons.py dicts is now covered, ported, or registered as an explicit gap — the audit doctrine is: map to a package concept; else find and port the publisher source; else register the gap. No silent drops.

Ported (new facts):

  • obr-efo-economy-march-2026 — EFO March 2026 detailed forecast tables, economy: nominal GDP (Table 1.4), ILO unemployment rate 16+ (1.6), CPI + RPI year-on-year (1.7), Bank Rate (market-derived assumptions, 1.9), employment 16+ (1.6). Workbook committed (obr.uk 403s CI runners, same rationale as the receipts/expenditure packages); manifest sha256 + deterministic R2 keys.
  • obr-efo-aggregates-march-2026 — EFO March 2026 detailed forecast tables, aggregates: public sector current receipts (6.2), TME (6.1), public sector net borrowing (6.5), PSND as per-cent-of-GDP (6.13).
  • ons-families-households-2025 gains Table 5 record sets: households total + average household size (already-committed workbook, no new artifact).

Registered gaps (first-class rows in the checklist audit table; the publisher does not directly assert these in the staged workbooks):

  • real_gdp_growth — the economy tables publish real GDP levels (ABMI); deriving growth is consumer work per the facts-only ADR.
  • public_sector_net_debt in GBP — sheet 6.13 publishes PSND only as per cent of GDP; converting would be Chronicle-computed.
  • FY2024-25 rows for receipts/TME/PSNB — the aggregates sheets start those rows at FY2025-26.
  • db/etl_hmrc.py — partial adjacent coverage only; kept, with its series recorded as explicit PR A gaps (its own audit is follow-up).

Deleted: db/etl_obr.py, db/etl_ons.py, their tests, the load obr/load ons CLI branches + choices entries (argparse error beats silent no-op), and the chronicle/targets/loaders.py / chronicle/jurisdictions/uk re-exports. DataSource.OBR/ONS enum members stay (existing DBs carry the strings). Negative-existence + audit-registration assertions added to tests/test_chronicle_boundaries.py. CI's load all surface shrinks by the two removed sources.

Bundle expectations re-measured on the post-#173 base: fact_count 145,295 (+73), source_package_count 122, obr 253, ons 65,646.

Publish-raw note: the two new OBR workbook artifacts carry deterministic R2 URIs in their manifests; the credentialed publish-raw upload is pending (same protocol as prior waves).

Chronicle Governance

  • Approved Chronicle agent role: ledger-source-ingestor (new packages + record sets); the db/** deletions are the maintainer cleanup UK enablement tooling: source-inventory de-hardcode, UK consumer-artifact suite, legacy ETL cleanup #135 sanctions.
  • Deterministic checks run: source-package validation, source-cell preservation, consumer-contract validation, raw-facts boundary validation — full suite uv run pytest -q.
  • LLM judge verdicts:
    • ledger-source-fidelity: pending review (every new fact traces to the committed workbook cells; guard cells transcribed from the sheets)
    • ledger-target-profile: n/a
    • ledger-contract: n/a
    • ledger-boundary: pending review (derivation refusals above are the boundary holding)

Tests

Implemented by Codex under a test-iteration protocol; two recorded deviations (real-GDP-growth portability, aggregates FY2024-25 start) were independently verified against the workbook sheets before shipping. Verification, twice (Codex's run and an independent re-run): ruff clean; full suite 626 passed, 1 skipped (the count drops from 633 with the two deleted ETL test files; package tests +98 targeted assertions).

🤖 Generated with Claude Code

@vahid-ahmadi vahid-ahmadi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The audit doctrine — every hardcoded series covered, ported, or registered as an explicit gap, with the gaps as first-class checklist rows rather than silence — is the right way to retire an ETL, and it's the same shape as the microcosm side's reviewed-absence pattern: a fail-closed accounting of what didn't move, which is where retirement PRs usually hide their losses. Deleting etl_obr.py/etl_ons.py with their tests (−1,010 lines) against +3,150 lines of publisher-backed package declarations is the trade this repo exists to make.

Committing the EFO workbooks because obr.uk 403s CI runners is consistent with the receipts/expenditure precedent, and the manifest sha256 + deterministic R2 keys keep the committed copies verifiable rather than trusted. The registered gaps I read (e.g. real_gdp_growth, where the publisher asserts real growth only via tables the package doesn't stage) are correctly gaps rather than derivations — deriving them consumer-side from staged nominal/deflator facts is exactly the kind of decision that belongs downstream of the facts boundary, per the #166 ruling.

The targeted suites pass for me (172 tests across the consumer, source-package, alias-drift, boundaries, and source-file suites). One process note rather than a finding: this wave re-measured the bundle constants by hand again — the cost #157 exists to remove. Since wave 4 (NZ) is next and this PR's own churn is the freshest evidence, I'd sequence the #157 per-source expectations refactor before the NZ waves start rather than after; the proposal has been endorsed since the 17th and every wave landed without it pays the ~13-minute re-measurement tax again. Nothing blocking here.

@juaristi22

Copy link
Copy Markdown
Collaborator Author

Codex adversarial review completed for this PR. It found no concerning or material findings: the retired UK ETL paths are no longer referenced at runtime, the publisher-backed package coordinates match the committed artifacts, and the documented parity gaps are explicit Chronicle-boundary exclusions. The review was read-only; its sandbox could not run the Python test suite because the environment required writable dependency state.

@juaristi22
juaristi22 force-pushed the uk-135-etl-retirement branch from 3ca3fac to 1f9ec8a Compare August 20, 2026 09:51
Every hardcoded series in db/etl_obr.py and db/etl_ons.py is now either
covered by a package concept, ported from a staged publisher workbook,
or registered as an explicit gap in the checklist audit table - no
silent drops.

Ported: two new OBR packages from the EFO March 2026 detailed forecast
tables - obr-efo-economy-march-2026 (nominal GDP, ILO unemployment
rate, CPI, RPI, bank rate, employment 16+; workbook committed, obr.uk
403s CI) and obr-efo-aggregates-march-2026 (public sector current
receipts, TME, net borrowing, PSND as percent of GDP) - plus household
totals and average household size as Table 5 record sets on the
existing ons-families-households-2025 package.

Registered gaps (publisher does not directly assert them in the staged
workbooks): real GDP growth (levels only; deriving growth is consumer
work per the facts-only ADR), PSND in GBP (published only as percent of
GDP), FY2024-25 rows for the aggregates series (sheets start at
FY2025-26), and the etl_hmrc.py series with partial adjacent coverage -
that module stays pending its own audit.

Deleted: db/etl_obr.py, db/etl_ons.py, their tests, the load obr/ons
CLI branches and choices, and the loaders/jurisdictions re-exports.
DataSource.OBR/ONS enum members stay (existing DBs carry the strings).
Negative-existence and audit-registration assertions added to the
boundaries tests.

Bundle-expectation surface re-measured: fact_count 145,295 (+73),
source_package_count 122, obr 253.

Implemented by Codex under the test-iteration protocol (two recorded
deviations, both independently verified against the workbook sheets);
independently re-verified: ruff clean, 626 passed, 1 skipped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juaristi22
juaristi22 force-pushed the uk-135-etl-retirement branch from 6896a0a to c4232c0 Compare August 20, 2026 12:09
@juaristi22
juaristi22 merged commit ca7b012 into PolicyEngine:main Aug 20, 2026
1 check passed
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