diff --git a/changelog.d/social-rent-target-vintage.fixed.md b/changelog.d/social-rent-target-vintage.fixed.md new file mode 100644 index 00000000..4a859926 --- /dev/null +++ b/changelog.d/social-rent-target-vintage.fixed.md @@ -0,0 +1 @@ +Refresh the social rent calibration target to the English Housing Survey 2024-25 mean (GBP 129/week, from GBP 118/week in EHS 2023-24). The target is set for 2025 but was anchored to a 2023-24 vintage while the private rent target used ONS data from February 2026, understating the social basis by roughly 10% relative to its own target year. diff --git a/policyengine_uk_data/targets/sources/housing.py b/policyengine_uk_data/targets/sources/housing.py index 4a11198a..724db7d6 100644 --- a/policyengine_uk_data/targets/sources/housing.py +++ b/policyengine_uk_data/targets/sources/housing.py @@ -2,12 +2,24 @@ Total mortgage payments, private rent, and social rent. +All three targets are set for 2025 and should be anchored to comparable +vintages. The social rent basis previously used EHS 2023-24 while the +private basis used ONS PRHI from February 2026, understating the social +target by roughly 10% relative to its own year. + Sources: - ONS PRHI Feb 2026: UK avg private rent £1,374/month https://www.ons.gov.uk/economy/inflationandpriceindices/bulletins/privaterentandhousepricesuk/march2026 -- English Housing Survey 2023-24: avg social rent £118/week - https://www.gov.uk/government/statistics/english-housing-survey-2023-to-2024-rented-sectors +- English Housing Survey 2024-25: avg social rent £129/week (local authority + £120, housing association £134) + https://www.gov.uk/government/statistics/chapters-for-english-housing-survey-2024-to-2025-headline-findings-on-demographics-and-household-resilience/chapter-2-housing-costs-and-affordability - EHS + devolved stats: ~5.4m private renters, ~5.0m social renters UK-wide + +Known limitation: these are totals only, so an error in the household count +and an offsetting error in the mean cannot be detected. At the 1.40.3 +dataset the private target is met (1.04x) with 6.99m renters at £256/week +against a basis of 5.4m at £317/week — the total matches by cancellation. +See PolicyEngine/policyengine-uk-data#454. """ from policyengine_uk_data.targets.schema import Target, Unit @@ -18,12 +30,17 @@ # Mortgage: avg £1,100/month × 7.5m owner-occupiers with mortgage _MORTGAGE_TOTAL = 1_100 * 12 * 7.5e6 # ~£99bn -# Social rent: EHS 2023-24 mean £118/week × 52 × 5.0m UK social renters -_SOCIAL_RENT_TOTAL = 118 * 52 * 5.0e6 # ~£30.7bn +# Social rent basis, kept as named components so the arithmetic is auditable +# and the vintage is explicit rather than buried in a product. +_SOCIAL_RENT_WEEKLY_MEAN = 129 # EHS 2024-25 (was 118 in EHS 2023-24) +_SOCIAL_RENT_HOUSEHOLDS = 5.0e6 # UK, derived: share x ONS household total +_SOCIAL_RENT_TOTAL = _SOCIAL_RENT_WEEKLY_MEAN * 52 * _SOCIAL_RENT_HOUSEHOLDS _EHS_REF = ( "https://www.gov.uk/government/statistics/" - "english-housing-survey-2023-to-2024-rented-sectors" + "chapters-for-english-housing-survey-2024-to-2025-headline-findings-on-" + "demographics-and-household-resilience/chapter-2-housing-costs-and-" + "affordability" ) _ONS_RENT_REF = ( "https://www.ons.gov.uk/economy/inflationandpriceindices/" diff --git a/policyengine_uk_data/tests/test_housing_targets.py b/policyengine_uk_data/tests/test_housing_targets.py index 15bdb8df..496ea1a0 100644 --- a/policyengine_uk_data/tests/test_housing_targets.py +++ b/policyengine_uk_data/tests/test_housing_targets.py @@ -5,6 +5,8 @@ from policyengine_uk_data.targets.sources.housing import ( _MORTGAGE_TOTAL, + _SOCIAL_RENT_HOUSEHOLDS, + _SOCIAL_RENT_WEEKLY_MEAN, _PRIVATE_RENT_TOTAL, _SOCIAL_RENT_TOTAL, get_targets, @@ -20,10 +22,23 @@ def test_private_rent_total_in_range(): def test_social_rent_total_in_range(): - """Social rent total should be £20bn-£40bn (5.0m × ~£118/wk).""" + """Social rent total should be £20bn-£40bn (5.0m × ~£129/wk).""" assert 20e9 < _SOCIAL_RENT_TOTAL < 40e9 +def test_social_rent_basis_components(): + """Pin the documented EHS basis so a silent edit is visible in review. + + This does NOT detect a newer EHS release — it only fails if someone + changes the constant without changing this pin. A real staleness check + would have to fetch EHS, as ons_tenure.py and ons_households.py do for + their sources. Tracked as future work in the module docstring. + """ + assert _SOCIAL_RENT_WEEKLY_MEAN == 129 # EHS 2024-25 + assert _SOCIAL_RENT_HOUSEHOLDS == 5.0e6 + assert _SOCIAL_RENT_TOTAL == 129 * 52 * 5.0e6 + + def test_mortgage_total_in_range(): """Mortgage total should be £80bn-£120bn (7.5m × ~£1,100/mo).""" assert 80e9 < _MORTGAGE_TOTAL < 120e9