Repository navigation
Uprate residential property values with house prices - #2446
Conversation
|
Fixed CI1 in Validation: both previously failing tests pass within 24 affected Python tests; 13 council-tax programme cases also pass. Independent verification returned CLEAN (1/1). Local checks used Core 3.32.27. Hosted CI for the new head is pending. |
vahid-ahmadi
left a comment
There was a problem hiding this comment.
Fine once the purchase-price index is settled.
@juaristi22, the move to the OBR house-price index is right for #2392, and the cumulative-ratio approach keeps the forward projection and the HVCTS deflation on one basis. One inconsistency is left, plus a merge note.
- should,
policyengine_uk/data/uprating_indices.yaml:112-114:main_residential_property_purchasedismain_residence_value * property_purchased, so main-home purchase prices (and the SDLT, LTT and LBTT on them) now move with house prices.additional_residential_property_purchasedstays on GDP per capita. So two purchases of the same property type now grow at different rates: from 2024 to 2030 the model's GDP-per-capita index rises by a factor of 1.214 and its house-price index by 1.169. Either moveadditional_residential_property_purchasedtohouse_pricestoo, or say in the comment why it should follow incomes.non_residential_property_purchasedandowned_landcan stay as they are. - should,
policyengine_uk/data/uprating_indices.yaml: #2447 conflicts with this PR in this file (I checked withgit merge-tree). #1863 and #2382 also edit it and merge cleanly. #1863 also changestest_projection_horizon.py, so its projection guard needs rerunning against whichever of the two lands second. - nit,
policyengine_uk/data/economic_assumptions.py:240and:286:apply_single_year_upratingnow chains the house-price ratio year by year, andapply_upratingthen overwrites it with the cumulative ratio. The result is right, but a one-line comment at:286saying that the multi-year path replaces this value would save the next reader some time.
What I checked
- Read the issue, the HVCTS policy paper and the model's
house_pricesseries (OBR March 2026 Table A.1). The 2024 to 2026 ratio is 1.16237 / 1.10421 = 1.053, as the issue says. - Hand-computed the new YAML case: £2,010,000 x 1.029 x 1.027 = £2,124,133.83, which falls in the first band at £2,500 a year.
pytest test_residential_property_uprating.py test_projection_horizon.py: 24 passed. The council tax YAML directory: 13 passed.- With the source and data changes reversed: the HVCTS YAML file gives 1 failed, 12 passed, and
test_residential_property_uprating.pygives 9 failed, 2 passed. ruff checkandruff format --checkon the six changed Python files: clean.- I did not run a population replay or check the size of the HVCTS revenue change.
- Reproducer and axiom lines are present;
fixedfragment type is right. CI is green on the current head.
🤖 Generated with Claude Code
dbb74ae to
bd41642
Compare
|
Fixed the remaining exact-band precision loss in This review round also aligns additional-dwelling purchase-price projection with HPI and retains the landed secured-debt GDP mappings and CPI/UC documentation. Validation: 128 affected Python tests and 33 programme YAML tests pass, including nine focused later-year boundary, override and immutability controls. Ruff and the Fix evidence check pass. The annual HPI proxy and post-2030 model-continuation qualifications remain in the PR description. |
Aggregate impact on certified data: passBase Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 22 (thresholds in Notes
Moves flagged for review
Receipts by tax head
Spending by benefit and service
Caseloads
Government balance, each component counted once
Model totals
Household income totals
Mean household net income in each side's own deciles
Standard reform costings (change in gov_balance)
Household net income by decileMean change in household net income per household, and as a share of the decile's base income; households stay in the base run's deciles.
No change in any year: components the model counts twice; population; poverty rates; people in poverty; inequality; standard reforms: change in each reform's target. Checks failing on both base and head (1)
Counted-once checkEach of 84 components was raised by £1 per unit in 2026-27, and every head of its totals was read household by household: its own head must rise by exactly £1, no other tax head may move, no other benefit may rise, and the model's own total must move by what its heads moved. A head that breaks a rule is measured again twice: with every other head held at its baseline value, and with every other head held at its value after the first £1 while the component rises again. It fails where either still shows the response. 0 failed; 0 were skipped.
Provenance
Dataset: Receipts by tax head: head levels
Spending by benefit and service: head levels
Caseloads: head levels
Government balance, each component counted once: head levels
Model totals: head levels
Components the model counts twice: head levels
Household income totals: head levels
Population: head levels
Poverty rates: head levels
People in poverty: head levels
Inequality: head levels
Mean household net income in each side's own deciles: head levels
Standard reform costings (change in gov_balance): head levels
Standard reforms: change in each reform's target: head levels
|
vahid-ahmadi
left a comment
There was a problem hiding this comment.
@juaristi22 round 2, at bd41642d3. I looked at what changed since dbb74ae4a (the range-diff after your rebase, plus the two new commits 5c54f1db2 and bd41642d3).
Verdict: both shoulds and the nit are fixed, and the new boundary fix is sound. Approving. There's one small note on the PR description below.
Round-1 points
- Additional-dwelling purchase prices: fixed.
uprating_indices.yamlnow listsadditional_residential_property_purchasedunderhouse_prices, so main-home and additional-dwelling purchases grow at the same rate.non_residential_property_purchasedandowned_landstay on GDP per capita, with a comment saying so. The new tests pin this, and they reach SDLT, LTT and LBTT. If I restore the old mapping, 5 of them fail. - Merge order: resolved. #2447 and #2382 have merged, and this branch is rebased onto current main (
8b12bce94, 0 commits behind). #1863 is still open. It merges cleanly with this PR (git merge-tree), and I rantest_projection_horizon.pyat this head (below). Whichever of the two lands second should still rerun that file. - nit, chained-then-replaced stocks: fixed.
economic_assumptions.py:286now has the comment.
New commit bd41642d3 (HVCTS boundaries)
Scaling the fixed 2026 thresholds up by the index ratio, instead of scaling the value down, gives the same result in exact arithmetic. The scale is copied, so the parameter table is not changed. The case that matters is a home observed in 2026 at exactly £2m, £2.5m, £3.5m or £5m and then projected forward. In 2029 and 2032 each one stays in its published band, on both the direct and the dataset route, and £1 below each stays in the band below. If I revert the variable, 4 of the new tests fail.
I also checked 2029 values supplied directly near the scaled boundaries (ratio 1.0843). In float32, the formula's boundaries come out as float32(T) * ratio: £2,168,517.75, £2,710,647.25, £3,794,906.25 and £5,421,294.50. Your test_c1_one_float32_step_below_current_price_boundary_is_not_snapped checks those exact values, and the next float32 value below each, and it passes. The pure float32 rounding of T × ratio differs from these by under 25p, so a value within 25p of a scaled boundary can fall on either side. For example, a supplied £3,794,906.00 sits just under the true £3,794,906.10 and gets the lower band. That's float32 resolution, not a defect.
New findings
- nit, PR description: say what this does to receipts. The Aggregate impact run on the merged head shows SDLT down £0.20bn in 2025-26, rising to £0.78bn in 2031-32. LTT, LBTT and HVCTS each move by under £2m a year, and nothing moves the other way. That's the expected direction, because house prices grow more slowly than GDP per capita in the OBR forecast. But neither the description nor the changelog mentions a revenue effect, so I'd add one line with those figures.
What I checked
- Fresh worktree at
bd41642d3with its own uv venv. pytest test_residential_property_uprating.py test_projection_horizon.py: 39 passed. Council tax, stamp duty and LTT YAML: 33 passed.ruff checkandruff format --checkon the six changed Python files: clean.- The two revert controls above, and the HVCTS boundary probe on synthetic London households.
- Read the Aggregate impact comment (base
8b12bce949against the merged head18d239bf49): it shows 0 checks broken and 22 flagged moves, all of them the SDLT change above and what follows from it. - CI is green at this head, including Aggregate impact.
- Not checked: the SDLT change against OBR's SDLT forecast.
🤖 Generated with Claude Code
Fixes #2392
Residential property values were projected with GDP per capita. Use the existing OBR house-price series for main and other residential property values in both household input uprating and dataset projections. Assess current-period main-residence values against the High Value Council Tax Surcharge's fixed 2026 bands expressed on the same annual house-price basis.
Dataset projections use one cumulative ratio from the original observation year, with the model variable dtype. The surcharge copies the current charge scale and expresses its fixed 2026 thresholds in the property value's storage precision before comparison. This preserves exact and £1-below band classifications in later charge years, without rounding household valuations or mutating parameter tables. Include the cumulative index in the dataset cache fingerprint so index overrides invalidate cached projections.
Projected additional-dwelling purchase prices also use house-price growth. Non-residential purchases, owned land and secured debts retain their existing GDP mappings.
The official documents specify values in 2026; they do not establish an April 2026 valuation date. The national annual OBR index is a modelling proxy for property valuations. The official OBR forecast ends in 2030; 2031–32 values follow the existing model continuation convention. Forecast assumptions, surcharge bands/rates and existing ownership, geography and main-home coverage are unchanged.
Sources: government policy publication, consultation, Annex B, OBR March 2026 forecast, Table A.1.
Reproducer: policyengine_uk/tests/test_residential_property_uprating.py::test_projection_preserves_supplied_2026_band_boundaries
Validation:
Local validation used frozen Python 3.13 / Core 3.33.2 with checkout imports and SysMonitor coverage. The unchanged scale-copy/calc source contract also matches the existing Core 3.32.27 environment; this repair was not executed in that minimum environment. The full model suite and private population replay were not run locally.
axiom: n/a: residential-value data uprating and annual price-basis modelling; charge eligibility, rates and valuation year are unchanged.