Repository navigation
Uprate three more columns, and guard the gap that hid them - #1863
vahid-ahmadi wants to merge 7 commits into
Conversation
|
Changes requested: clear the formatting failure and register the changelog fragment. Reviewed head: The uprating additions remain useful. Main
Acceptance commands from the repaired checkout: uv run pytest policyengine_uk/tests/code_health/test_uprating_declarations.py -q
uv run ruff format --check policyengine_uk/tests/code_health/test_uprating_declarations.py
uv run ruff check policyengine_uk/tests/code_health/test_uprating_declarations.py
uv run towncrier build --draft --version 0.0.0Require all three tests and both Ruff checks to pass, verify that Towncrier includes the fragment, and obtain green CI on the updated head. Keep this repair scoped to formatting and the fragment filename; changing the economic indices or removing exceptions requires separate evidence. Validation performed: exact-snapshot guard tests 3 passed in 0.91s; formatter failure and ignored fragment independently reproduced. Execution used the existing Python 3.13.14/core 3.32.9 environment. The map was compared with current main and existing variable declarations. The guard confirms consistency with those declarations; it does not independently establish the economic choice of indices. No private-data projection or rebased integration run was performed, and the proposed repair has not been applied or tested. Live posting check (2026-10-02T15:11:38.782329+00:00): same reviewed commit; GitHub reports |
747a1d1 to
8300b0a
Compare
juaristi22
left a comment
There was a problem hiding this comment.
Re-review of 8300b0a: the two requested blockers are addressed in the diff. The guard test is formatted, the changelog fragment now has the .fixed.md type, and the added mappings are placed under the variables’ declared indices. Lint and the four install/smoke jobs pass; the current Test job is still running, so this is a comment rather than an approval.
Should address: test_every_known_exception_still_declares_uprating checks only that an exception variable exists and still declares uprating. It does not check that a KNOWN_UNUPRATED entry remains absent from the YAML or that a KNOWN_INDEX_OVERRIDES entry still has an index mismatch. If an exception becomes stale, it can mask a later gap. Please check that each exception’s reason still holds, or remove it when resolved. This is a guard-coverage concern; I found no demonstrated current mapping error.
I could not independently run the guard, Towncrier draft, or private-dataset projections in this workspace. Please wait for the Test job before treating this re-review as complete.
Review of #1863 — Uprate three more columns, and guard the gap that hid themBase repository: PolicyEngine/policyengine-uk Source DocumentsNo source documents registered; see scope and validation. CriticalNone. Should AddressNone. SuggestionsNone. Evidence Gaps
Notes
Validation SummaryReused exact-head validation (not rerun in this batch): 12 passed, 1 warning in 6.35s; snapshot import confirmed; raw command/paths in pr-1863-code-tests-config.json and pr-1863-code-tests.log; Diagnostic: ten-column uprating script ( Reused exact-head validation (not rerun in this batch): 0 official originals; static source/policy review; no duplicate model execution. Manifest: pr-1863-review-sources.json; bundled check_source_manifest.py passed under existing Python3.13; cache result pr-1863-review-source-cache-check.json CI at 155f50b: Install + smoke-import (py3.11)=SUCCESS, Install + smoke-import (py3.12)=SUCCESS, Install + smoke-import (py3.13)=SUCCESS, Install + smoke-import (py3.14)=SUCCESS, Lint=SUCCESS, Test=SUCCESS. Detailed code, policy, source and reproduction artifacts were retained locally. Timingelapsed seconds: 1151.70s; setup seconds: 271.12s Review SeverityCOMMENT. Open findings: 0 critical, 0 should address, 0 suggestions. |
Follow-up to #1860, closing most of #1862. Three variables declared an uprating index but were missing from uprating_indices.yaml, so they were never uprated. On enhanced_frs_2024_25, 2024 -> 2027: water_and_sewerage_charges 375.51 -> 522.12 (+39.0%) housing_service_charges 91.81 -> 105.06 (+14.4%) pension_contributions_via_salary_sacrifice 418.69 -> 466.81 (+11.5%) Each matches its index compounded over the same years exactly: ofwat water bills +39.0%, OBR lagged average earnings +14.4%, OBR average earnings +11.5%. All three indices already had the yoy_growth twin the YAML needs, so this is a YAML-only change. rail_usage is deliberately NOT included. Its declared index, gov.dft.rail.ridership_index, is a CUMULATIVE index with 2020 = 1.0 — "Used for uprating the quantity component of rail subsidy spending" — not a year-on-year rate. Adding it to a yoy_growth block compounds the level and uprates the variable by about 684% over 2024-27. Uprating it properly needs a year-on-year series, which is more than a YAML entry. The durable fix is the code-health test suggested in review of #1860: policyengine_uk/tests/code_health/test_uprating_declarations.py asserts that every variable declaring `uprating` appears in the YAML under the matching index. Verified it fails when an entry is removed, rather than only passing today. Three exceptions are listed with reasons rather than silently tolerated: rail_usage and employee_pension_contributions_reported as not uprated, and savings_interest_income as uprated by a different index from the one it declares — the mismatch noted in #1862, left for someone with the context to say which is intended. A third test keeps those lists honest by asserting each entry still exists and still declares uprating. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lose the gaps it now finds - ruff format test_uprating_declarations.py (the Lint failure). - Rename the fragment to uprate-four-remaining-columns.fixed.md so towncrier renders it under Fixed rather than dropping it. - After rebasing onto main, the guard flags ten variables declared since: seven are genuine gaps and now uprate by the index they declare (cash_isa, stocks_and_shares_isa, mortgage_debt, consumer_debt, rent_paid_as_boarder, rent_paid_as_lodger by per-capita GDP; self_employment_gross_receipts by per-capita mixed income); the three energy columns are listed as deliberately unuprated, per #1868. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The exception check only confirmed each entry still existed and declared `uprating`. It now also fails when a KNOWN_UNUPRATED variable has been added to uprating_indices.yaml, or when a KNOWN_INDEX_OVERRIDES variable is now uprated by its declared index (or has left the YAML), naming the list to edit. Unit tests feed the guard stale entries to prove each case is caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Suggested The check isn't required yet (decision d1368); it fails fix PRs whose description names no reproducer. 🤖 Generated with Claude Code |
155f50b to
d150116
Compare
|
Rebased onto main (d150116). The one conflict was in |
juaristi22
left a comment
There was a problem hiding this comment.
Re-reviewed d150116d0d08c9b9db2234f348dd38c84ea816e1. The rebase retains both main’s uc_reported_capital entry and this PR’s uprating entries. The stale-exception guard now fails as intended; all eight focused current-head guard tests pass. I found no new YAML membership defect.
I checked the official OBR March 2026 economy workbook: its earnings, nominal-GDP and mixed-income figures support the PR’s 11.5% and 14.4% earnings examples and the numerator series. The remaining source gap is the dated ONS population projection/vintage used to turn GDP and mixed income into per-capita factors. The YAML points only to the ONS homepage, and its 2025 population growth differs from the rate implicit in the OBR workbook.
For water bills, Ofwat’s published 2025–26 26% figure was a forecast; its later release reports 27% for that year and 5.4% for 2026–27, versus the model’s 26% and 5.5%. The 2027–29 factors are custom projections, and the local build expects an untracked ofwat_increases.csv, so I could not reproduce their company-weighted derivation. Please document the inputs, vintage and projection calculation, or bound the effect of using these existing series for the newly uprated columns. I can revisit approval with that provenance and completed current-head CI.
…series' provenance Water bill growth for 2025-26 becomes 27%, the figure in Ofwat's 29 January 2026 statement, replacing its 30 January 2025 forecast of 26%. 2026-27 becomes 5.4%, Water UK's 28 January 2026 national average, replacing a 5.5% projection. The 2027-2029 projections are kept and their method is recorded, including that their inputs were never committed. ons.population is documented as the OBR long-term economic determinants for the March 2025 EFO (19 June 2025), with the ONS 2022-based migration category variant from 2030-31, and the per-capita series note that they use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks. Both points are addressed in 7ab0afa, with details under "Provenance" in the description.
Following Max's comment, the description now has the @juaristi22 could you re-review? |
Resolve uprating_indices.yaml: keep main's trading_loss and this branch's self_employment_gross_receipts under obr.per_capita.mixed_income. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
List main's four owned_company inputs under the indices they declare, which the guard caught after the merge. Narrow main's fallback assertion in test_projection_horizon.py to the columns that are still unlisted, and correct the guard docstring now that the uprating attribute drives the post-2030 fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged main into this branch (6c3f5d6). Beyond the conflict, which kept both
|
juaristi22
left a comment
There was a problem hiding this comment.
Re-reviewed 6c3f5d60e4947512e1bc9a77b2ff40a252dbcd40 after the provenance updates and main merge. The code checks are clear: all 24 changed guard, water-growth and projection tests pass, including the Hypothesis checks. The new company columns use their declared indices, and the post-2030 fallback does not double-uprate them. Captured current-head CI passes.
The dated OBR release attribution is now documented, and I verified Water UK’s 2026–27 increase of 5.4% (£33 to £639). Two numerical source checks remain incomplete in this run:
- The official OBR workbook downloads returned “No Access” HTML or403, so I could not independently check the population row and the newly supplied per-capita vintage bounds.
- Both permitted routes to the cited Ofwat statement were blocked, so I could not newly corroborate the changed 2025–26 value of27%. I have not established that the value is wrong.
The explicitly disclosed 2027–2029 forecast/weights limitation remains tracked by #2384. I am leaving this review PARTIAL with no confirmed code defect. Accessible copies of the exact official workbook/table and Ofwat statement would let me close the remaining source checks without repeating the model tests.
Follow-up to #1860, closing most of #1862. Thanks @juaristi22 for finding these and for suggesting the guard.
The three fixes
Each declared an uprating index but was absent from
uprating_indices.yaml, so was never uprated (on main since #2376's projection fallback, it stays flat through 2030 and grows only after). Onenhanced_frs_2024_25, 2024 → 2027:water_and_sewerage_chargeshousing_service_chargespension_contributions_via_salary_sacrificeThe water row uses the published 2025-26 and 2026-27 bill increases (see Provenance below); it was 522.12 (+39.0%) with the old 26% and 5.5%. Each matches its own index exactly, which is the check that they are now uprated by the right thing rather than merely uprated.
All three indices already had the
yoy_growthtwin the YAML needs — your caution about missing parameters turned out not to apply to these — so this is a YAML-only change.rail_usageis deliberately excludedIts declared index is a cumulative level, not a year-on-year rate:
Values run 0.95 (2024) → 1.005 (2027). Putting it in a
yoy_growthblock compounds the level and uprates the variable by ~684% over 2024–27. I had it in the YAML at first and caught it on the before/after check. Uprating it properly needs a year-on-year series, which is more than a YAML entry.The guard
policyengine_uk/tests/code_health/test_uprating_declarations.pyasserts every variable declaringupratingappears in the YAML under the matching index — the durable fix you suggested, which would have caught #1859 at the point it was introduced.I verified it fails when an entry is removed, rather than only passing today. (That check matters: a guard I wrote on the dashboard side turned out to pass regardless of the thing it claimed to prevent, so I no longer trust one I have not seen fail.)
Three exceptions are listed with reasons rather than silently tolerated:
rail_usage— cumulative index, as aboveemployee_pension_contributions_reported— reported counterpart feeding imputationsavings_interest_income— the index mismatch you flagged; declaresons.household_interest_incomewhile the YAML appliesper_capita.gdp. Left as-is for someone with the context to say which is intended — I did not want to change an uprating basis on a guess.A third test keeps those lists honest: each entry must still exist and still declare
uprating, so a stale exception fails rather than lingering.Since review (rebased onto main, 7 Oct)
ruff formaton the guard test; the changelog fragment is typed.fixed.md, so it renders under "Fixed".cash_isa,stocks_and_shares_isa,mortgage_debt,consumer_debt,rent_paid_as_boarder,rent_paid_as_lodger. Per-capita mixed income:self_employment_gross_receipts.electricity_consumption,gas_consumptionanddomestic_energy_consumptionare listed inKNOWN_UNUPRATED, because the data build prices energy spend (Stop CPI-uprating energy, which the data build already prices #1868).8300b0a96: guard tests 3 passed (and fail withcash_isaremoved);tests/code_health1,953 passed; the YAML suite 2,605 passed;ruff format --check .andruff check .clean.Verification
265 passed, 45 skipped (262 before, plus the three new tests). Changelog fragment included.
Checks at
7ab0afa33: guard tests 8 passed;tests/code_health, the water test and the top-level uprating test files 2,314 passed; the YAML suite 3,058 passed;ruff format --check .andruff check .clean;.github/check_fix_pr.pyPASS against this description. The new water test fails with the old 0.26 and 0.055.#1862 stays open for
rail_usageand thesavings_interest_incomebasis question.Merge with main (14 Oct)
Merged
origin/main(232 commits behind). Three things changed beyond the conflict:uprating_indices.yamlconflicted onobr.per_capita.mixed_income: main addedtrading_loss, this PRself_employment_gross_receipts. Both kept.owned_company_capital,owned_company_holding_value,owned_company_trade_assetsunder per-capita GDP,owned_company_income_shareunder per-capita mixed income). Listed under the index each declares.upratingattribute to grow unlisted columns after 2030 (_unmapped_uprating_indices). The guard docstring no longer calls that attribute dead metadata, andtest_unmapped_inputs_preserve_legacy_years_and_grow_after_2030now asserts only the columns still unlisted (rail_usage,employee_pension_contributions_reported) are fallbacks, since the columns this PR lists grow every year instead.Provenance of the series these columns now use (since review, 12 Oct)
Water bills (
ofwat.water_bills). Values are charging years from April, stored at 1 January (2025 holds 2025-26).utils/water/forecast_water_bills.py(Improve water forecasts #1239). The script takes the customer-weighted mean of the CCW per-company table and adds a hardcoded CPIH path. The CCW page says that table shows Ofwat's PR24 draft determinations. The weights were inofwat_increases.csv, which is gitignored and was never committed, so these values cannot be reproduced. Filed as Water bill projections for 2027-29 cannot be reproduced from the repo #2384.water_and_sewerage_charges, which this PR starts uprating.create_ahc_deflator.pyreads it offline and was not rerun. Effect: the 2026 and later water factors rise by 0.70% (1.27 × 1.054 against 1.26 × 1.055), about £3.50 a household a year on the mean above.Population (
ons.population), the denominator forper_capita.gdpandper_capita.mixed_income.household_weightis uprated by the same population series, so in the uprating step aggregates still grow with nominal GDP or mixed income. The vintage mainly shifts the split between amounts per household and household counts.ons.populationdriveshousehold_weightand everyper_capita.*series, so a refresh has to re-derive them together. Filed as Refresh ons.population and re-derive the per-capita series from one vintage #2383. The YAML now cites the dated release, the mapping and the vintage instead of the ONS homepage.Reproducer:
policyengine_uk/tests/code_health/test_uprating_declarations.py::test_declared_uprating_variables_are_in_the_yaml,policyengine_uk/tests/code_health/test_uprating_declarations.py::test_the_yaml_uprates_by_the_declared_index,policyengine_uk/tests/code_health/test_uprating_declarations.py::test_every_known_exception_still_holds,policyengine_uk/tests/code_health/test_uprating_declarations.py::test_the_guard_passes_exceptions_that_still_hold,policyengine_uk/tests/code_health/test_uprating_declarations.py::test_the_guard_flags_an_unuprated_exception_added_to_the_yaml,policyengine_uk/tests/code_health/test_uprating_declarations.py::test_the_guard_flags_an_override_that_now_matches,policyengine_uk/tests/code_health/test_uprating_declarations.py::test_the_guard_flags_an_override_dropped_from_the_yaml,policyengine_uk/tests/code_health/test_uprating_declarations.py::test_the_guard_flags_missing_or_undeclared_exceptions,policyengine_uk/tests/test_water_bills_growth.py::test_published_water_bill_growth,policyengine_uk/tests/test_water_bills_growth.py::test_water_index_compounds_the_published_yearsaxiom: n/a: uprating of survey input columns and economic-assumption provenance; no tax or benefit rule changes