Skip to content

Use published LHA determinations and apply Sch 3B paras 3 and 3A - #2022

Merged
MaxGhenis merged 10 commits into
mainfrom
lha-published-rates
Oct 4, 2026
Merged

MaxGhenis merged 10 commits into
mainfrom
lha-published-rates

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2012

What changes

Local Housing Allowance rates now come from the published determinations: every year from April 2014 (England, Wales) or April 2015 (Scotland, Northern Ireland) to April 2026. They replace the 30th percentile of lha_list_of_rents.csv.gz (2019 and 2020 rows), which was uprated by the private rent index for later years.

Nation Housing Benefit (weekly) Universal Credit (monthly)
England VOA tables, April 2014 to April 2026; 30th percentile rents every year DWP
Wales Rent Officers Wales (gov.wales), April 2014 to April 2026; 30th percentile rents every year from 2014 except 2020 DWP
Scotland Scottish Government (Rent Service Scotland), April 2015 to April 2026; 30th percentile rents every year DWP
Northern Ireland NIHE, April 2015 to April 2025, from Internet Archive captures of nihe.gov.uk (no April 2026 table was retrievable; SR 2026/2 holds the April 2024 rates, which the model applies); 30th percentile rents 2015 to 2018 nidirect, April 2024 to April 2026
  • Data. parameters/gov/dwp/LHA/lha_published_rates.csv.gz has one row per year, BRMA and category. scripts/build_lha_published_rates.py builds it from the files listed in lha_published_rates_sources.csv, with each file's URL and SHA-256. Every BRMA has rates for every year from 2020 to 2025, and every GB BRMA for 2026. No NIHE table for April 2026 could be retrieved; SR 2026/2 holds Northern Ireland's rates at the April 2024 determination, which the model applies. NI's monthly UC rates are published (nidirect) from April 2024; earlier ones are converted from the weekly percentile.

  • Rules. policyengine_uk/utils/lha.py recomputes each determination from April 2020 from the published 30th percentile rents, following Rent Officers (Housing Benefit Functions) Order 1997 Sch 3B and Rent Officers (Universal Credit Functions) Order 2013 Sch 1:

    1. the lower of the percentile rent and the national maximum (para 2(2));
    2. the anomalous-rate rule (para 3), which the model lacked;
    3. the March 2020 minimum (para 3A, inserted by SI 2024/11; new parameter gov.dwp.LHA.march_2020_minimum), which the model also lacked;
    4. rounding to the penny, halves up: the percentile rent, and the allowance after the maximum (so a half-penny maximum under reform rounds up).

    The March 2020 minimum applies to UC in Northern Ireland too (SR 2016/222 Sch 1 para 6). NI's April 2020 monthly rates were not published, so the floor there is the April 2020 weekly rate converted to a month.

    The NI rules are the same (SR 2016/222 Sch 1, SR 2008/100, and the NI modification and amendment regulations). While gov.dwp.LHA.freeze is true, the last unfrozen determination holds. Before April 2020, the published rates are used as they stand: they follow CPI and 1% uprating, then the 2016-2020 freeze with targeted affordability uplifts, none of which the model encodes.

  • Universal Credit gets its monthly determination. Before, it took 52 weeks of the weekly rate, which ran 1.8% low in April 2020 against DWP's tables.

  • Reforms.

    • Lifting a freeze uses that year's published percentile rents where they exist (NI has none after 2018 except via the reset-year rates, and three Welsh frozen-year cells are missing; those use the latest earlier percentile grown with the private rent index). The VOA, Rent Officers Wales and the Scottish Government publish them for frozen years too: for example, Maidstone two-bedroom April 2025 is £230.14, against the held £208.27.
    • Beyond the last table, the latest percentile grows with gov.indices.private_rent_index.
    • A non-30th percentile scales the published one by the ratio of the two percentiles in the list of rents (statutory positions, Sch 3B para 2(8)). Every Welsh and Northern Irish list in lha_list_of_rents.csv.gz (300) is a copy of an English BRMA's list, and the Scottish ones were too (all 480 checked; see policyengine-uk-data#515). Welsh and Northern Irish BRMAs therefore take the median English ratio for the category. For Scotland, Use Rent Service Scotland's own lists of rents for Scottish percentile ratios #2037 (merged into this branch; fixes Scottish, Welsh and NI lists of rents are copies of English BRMAs' lists #2036; independently reviewed) replaces the copies with Rent Service Scotland's own list-of-rents records, released under FOI 202200303624. They reproduce 173 of 180 published April 2019 and April 2020 30th percentiles exactly. Scottish BRMAs now use their own ratios. Welsh and Northern Irish BRMAs keep the English median, which now excludes Scotland.

Freeze timing was already right

The issue suggested that calendar 2025 was treated as unfrozen. It is not. convert_to_fiscal_year_parameters reads every parameter at 30 April, so year 2025 takes the freeze from 6 April 2025, held at the January 2024 determination (checked at 7b9fc37: freeze(2025) is true, anchor 2024). The new test_years_map_to_april_determinations pins this.

One publisher inconsistency, kept as published

Rent Officers Wales's April 2022 and April 2023 tables say their rates are "fixed at the April 2020 rate". In 14 Housing Benefit cells, though, they differ from its own April 2020 and April 2021 tables (for example, Blaenau Gwent one-bedroom: £66.39, then £66.74). DWP's monthly Wales tables restate the 14 cells' monthly counterparts plus three more by 1p or 2p (Monmouthshire C, Newport E, Pembrokeshire E): 17 UC cells. Each restated figure is a round rent (16 of the 17 monthly figures are multiples of £5; the other, Vale of Glamorgan one-bedroom at £434.52, is £100 a week), which reads as a correction. The model takes each table as published. A held year adjusts the held determination's percentile rent by the published restatement (restatement) before the maximum, anomalous-rate and minimum rules, so a reform to those rules still binds. For example, a £60 maximum on Blaenau Gwent one-bedroom in 2020 holds at £60 through 2022, not £60.35. The March 2020 minimum uses the restated figures too (no baseline effect: every affected cell's April 2024 rate is above both). test_published_frozen_years_repeat_the_last_determination pins the exception to those Welsh cells.

Interaction with #2021

#2021 (the default BRMA follows the region) moves the same two test pins. Whichever PR merges second needs to re-pin them to Inner South East London, London's default under #2021. Computed on this branch with that BRMA:

  • LHA.yaml "BRMA default value" (2020, category C): BRMA_LHA_rate 16,155.36. That is the VOA April 2020 rate of £310.68 a week.
  • entitledto_scenarios.yaml Add contributory JSA #1 (2025, shared accommodation): uc_LHA_cap 7,800, which is DWP's April 2024 UC rate of £650.00 a month, held for 2025-26. universal_credit becomes 6,001.68 and household_net_income 16,627.14.
  • Drop the comment that the default (Maidstone) applies.

from policyengine_uk.parameters.gov.dwp.LHA import lha_list_of_rents still works here (module __getattr__), which #2021's test_brma_region_default.py uses.

Housing Benefit's own category of dwelling (#2006)

#2006 (on main) gave Housing Benefit its own category of dwelling, housing_benefit_LHA_category (HB Regs 2006 reg 13D), and a housing_benefit_LHA_rate that the HB maximum rent (LHA_cap) reads. Each determination has one rate per BRMA and category, so housing_benefit_LHA_rate now reads the weekly determination for the HB category (benunit_lha(..., category_variable="housing_benefit_LHA_category")). BRMA_LHA_rate reads the same weekly determination for the UC category, and uc_LHA_cap reads the monthly determination (Rent Officers (Universal Credit Functions) Order 2013) for the UC category. #2006's list-of-rents helper (lha_rate_for_category) and the per-category maximum lookup go with the rest of the list-of-rents code: the maximum is applied inside the determination, before the anomalous-rate rule and the minimum.

Before and after

At 7b9fc37, against the published tables:

Determination Nation Housing Benefit cells exact, before Mean absolute error, before UC mean absolute error, before
April 2024 (held 2025-26, 2026-27) England 11 of 760 6.3% (−26.2% to +21.7%) 6.2%
Wales 0 of 110 7.5% (−22.8% to +16.2%) 7.6%
Scotland 0 of 90 10.8% (−37.5% to +21.7%) 10.9%
Northern Ireland 0 of 40 14.3% (−30.6% to +2.5%) 14.5%
April 2020 (held 2021-22 to 2023-24) England 649 of 760 0.1% 0.3%
Wales 3 of 110 7.3% 7.5%
Scotland 5 of 90 9.9% 10.1%
Northern Ireland 0 of 40 8.8% not published
April 2019 England 39 of 760 11.0% 10.9%

Rates fell with dwelling size in 25 BRMA-years before (5 BRMAs in April 2024: Carmarthenshire, Lough Neagh Lower, North (NI), North West (NI), Taff Rhondda), and in none after.

After this change, every published rate is reproduced exactly, 2014 to 2026, in every nation: 12,830 Housing Benefit cells and 12,600 Universal Credit cells. The same holds end to end through BRMA_LHA_rate and uc_LHA_cap for every BRMA and category in 2019, 2020, 2023, 2024, 2025 and 2026, and through housing_benefit_LHA_rate for every published HB cell from 2019 to 2026. test_model_reproduces_every_published_rate is the differential test. Where a publisher gives no separate percentile for a reset year (Wales and NI in April 2020, NI in April 2024), and for UC in reset years wherever the weekly rate equals its percentile, the published rate stands in for the percentile; for those cells the match shows only that the rules leave an unadjusted rate alone. The law-derived regression tests and Hypothesis properties cover the rules themselves.

Invariants

  • Never falls with dwelling size. Every published table, in every nation and year, is non-decreasing from A (shared) to E (four bedrooms). That is Sch 3B para 3. The model's rates are too: in baseline for 2015 to 2040, and in a Hypothesis property over random freeze patterns, percentiles of 5% to 90%, maxima scaled by 0.25 to 1.5, and the minimum on or off.
  • Bounds. A rate is never above the larger of the category's (cumulative) maximum and the March 2020 minimum. While the minimum applies, it is never below it. It is never below min(percentile, maximum). It is in whole pence.
  • Freeze consistency. A frozen year's rates equal its determination year's, except where a published table restates them (property).
  • Monotone in the percentile. A higher percentile never lowers any rate (property).
  • Published freezes repeat. In the data, every held table repeats its determination, apart from the pinned Welsh restatements.

Impact

Real microsimulations of the released enhanced FRS 2024-25 (policyengine-uk-data 1.57.4, sha256 03fe15e4…): main at 6ae9c5e (4 October) against this PR's merged head 088addb. Aggregates only; any figure from fewer than 10 survey households is suppressed.

Three real runs per model (fiscal years 2025-26, 2026-27 and 2029-30); every figure below comes from one of them.

£bn a year 2025-26 2026-27 2029-30
Universal Credit paid −0.438 −0.454 −0.493
Housing Benefit −0.210 −0.227 −0.230
Household net income −0.648 −0.681 −0.725

2026-27 by nation, Universal Credit paid:

  • England: −£0.481bn (247 survey households);
  • Northern Ireland: +£0.038bn (72);
  • Scotland: −£0.003bn (28);
  • Wales: −£0.008bn (29).

The UC housing costs element before taper and take-up changes by −£1.82bn, +£0.16bn, +£0.06bn and +£0.01bn respectively.

Across LHA-eligible benefit units, the weekly Housing Benefit LHA rate (housing_benefit_LHA_rate) changes on average by −£8.36 in England (higher for 16%), +£20.82 in Northern Ireland (higher for 98%), +£3.26 in Scotland and +£0.92 in Wales. The direction follows the errors above: the list-of-rents model overstated English rates on average and understated Northern Irish ones.

1.34m households lose more than £1 a year (275 survey households), and 0.29m gain (147).

Poverty changes rest on only 12 to 18 survey households per figure, so treat them as indicative. Before housing costs: +33k people in 2026-27 (12 survey households change status). After housing costs: +24k (18).

The first runs (base 7b9fc37 against 43ef96f, before main's HB changes) gave nearly the same totals: −£0.668bn household net income in 2026-27.

Tests

  • test_lha_published_rates.py:
    • data coverage and monotonicity;
    • held tables repeat (with the pinned Welsh exception);
    • differential test against every published cell, 2014-2026, for Housing Benefit and UC;
    • fiscal-year mapping;
    • statutory percentile positions;
    • Hypothesis properties over reforms;
    • simulation-level reforms: unfreeze 2025, unfreeze 2027, the minimum, freeze 2024.
    • regression tests from the independent review: the NI UC minimum under a binding cap, a reformed maximum binding through a restated Welsh held rate, and half-penny maxima rounding up. Each fails on the earlier code.
    • the exact 14 HB and 17 UC restated Welsh cells, pinned with their amounts.
    • housing_benefit_LHA_rate and BRMA_LHA_rate each follow their own category (HB and UC), for every BRMA and category, with the other category set differently. Pointing the HB variable at the UC category makes it fail.
  • lha_published_rates.yaml: rates pinned to published figures, England, Wales, Scotland and NI, across reset, frozen and pre-2020 years. Includes the Durham anomalous-rate case and the central London maximum.
  • Updated to published figures:
    • LHA.yaml: 2020 Maidstone and Guildford;
    • test_lha_freeze.py: Maidstone April 2020 £187.56 (was the list-of-rents £187.91);
    • test_lha_uc_maximum.py: the pre-2020 UC rate is DWP's published monthly rate;
    • entitledto_scenarios.yaml Add contributory JSA #1: a pinned PolicyEngine output. Maidstone shared accommodation UC is £444.83 a month, so UC is £285.32 lower.

Commands run:

  • uv run pytest policyengine_uk/tests/test_lha_published_rates.py policyengine_uk/tests/test_lha_freeze.py policyengine_uk/tests/test_lha_maximum.py policyengine_uk/tests/test_lha_uc_maximum.py
  • the Hypothesis properties under six seeds
  • uv run policyengine-core test policyengine_uk/tests/policy -c policyengine_uk
  • the full Python suite in CI's Test job on each pushed head (local logs, stamped with the commit, are kept with the review)
  • ruff format and ruff check on the changed files

The data build was re-run from the cached source files. The make test-microsimulation tests were not run (they need the private dataset). The impact figures above come from runs at this PR's current head. The dataset is uk-data 1.57.4's enhanced_frs_2024_25.h5 (sha256 03fe15e4…, per the release manifest; 1.57.4 is still the latest release).

axiom: n/a for the published rates themselves (rent-officer determinations, which rulespec-uk takes as inputs). The determination rules in Sch 3B paras 2(2), 3 and 3A (and UC Order Sch 1 paras 2, 5 and 7) are queued: TheAxiomFoundation/rulespec-uk#415 queued

🤖 Generated with Claude Code

LHA rates came from the 30th percentile of the 2020 list of rents, uprated
by the private rent index. They now come from the published tables (VOA,
Rent Officers Wales, Scottish Government, NIHE, and DWP and nidirect for
monthly Universal Credit rates), April 2014 to April 2026. Determinations
from April 2020 are recomputed from the published 30th percentile rents with
the national maxima, the anomalous-rate rule (para 3) and the March 2020
minimum (para 3A), which reproduces every published rate.

Fixes #2012

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every Welsh, Scottish and Northern Irish list in lha_list_of_rents.csv.gz is
a copy of an English BRMA's list (all 480, checked), so a percentile reform
scaled those nations' published rates by a copied list's shape. They now take
the median English ratio for the same category. Baseline rates are unchanged:
the ratio is one at the 30th percentile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 2, 2026
The list of rents' Scottish, Welsh and Northern Ireland lists are copies of
English lists (policyengine-uk-data#515), so their entry counts say nothing
about where people rent. Each region's default is now its BRMA with the most
private-rented households in the 2021 (England, Wales, Northern Ireland) and
2022 (Scotland) censuses, mapped to BRMAs. Scotland moves to Lothian,
Yorkshire to Leeds and the East of England to Central Norfolk & Norwich.

The new YAML tests no longer pin LHA rates, which #2022 changes; a Python
test checks instead that each default gives the same rates as inputting it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Scottish lists in lha_list_of_rents.csv.gz were copies of English
BRMAs' lists (#2036). Replace them with Rent Service Scotland's records
released under FOI 202200303624: the list for April Y is the sheet for
the year to September Y-1 (sheets 2018 and 2019 for 2019 and 2020).
Those sheets reproduce the published 30th percentiles to the penny in 87
and 86 of 90 cells respectively.

Scottish BRMAs now take percentile-reform ratios from their own lists;
Welsh and Northern Irish BRMAs, still copies, keep the median English
ratio, and the English median no longer includes Scotland. The build
script pins the workbook by sha256 and leaves every other row unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 3 commits October 2, 2026 03:24
From review: choose the latest list year per region so a newer sheet for
one nation cannot drop the others; define English regions once
(NON_ENGLISH_REGIONS) for the code and tests; compute the test's English
median the way the code does; pin two Scottish P50 ratios so the test
catches a return to copied data (both Scottish tests fail on aef9c24's
file); assert the number of BRMA-less rents per sheet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ding

- The March 2020 minimum now applies to Northern Ireland's UC rates
  (SR 2016/222 Sch 1 para 6). NI's April 2020 monthly rates were not
  published, so the floor is the April 2020 weekly rate converted to a month;
  before, a missing value silently dropped the floor.
- Welsh restatements of held April 2020 rates now adjust the held
  determination's percentile rent before the maximum, anomalous-rate and
  minimum rules, rather than adding cash afterwards, so a reformed maximum
  still binds. The minimum uses the determinations as originally published.
- The allowance after the maximum is rounded to the penny (para 2(10)).
- Tests pin the exact restated Welsh cells, check whole pence exactly, use
  fractional-penny maxima, bound held years, use an independent NI floor,
  and add a regression test for each counterexample.
- Docs: NI UC sources, missing-percentile fallback, devolved ratios.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rent Officers Wales's April 2022 and 2023 tables restate 14 weekly (17
monthly) of the April 2020 rates they hold. Each restated monthly figure is a
round monthly rent, which reads as a correction, so the para 3A minimum now
uses the latest held table's figures (no baseline effect: every affected
cell's April 2024 rate is above both). The test computes that floor
independently from the pinned restatements. Docs state the rounding order,
the reset-year percentile fill, the extra three monthly restatements, and
nidirect as Northern Ireland's UC source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 4 commits October 3, 2026 17:15
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed rates

Main's #2006 gives Housing Benefit its own category of dwelling
(housing_benefit_LHA_category) and a housing_benefit_LHA_rate that the
HB maximum rent reads. Rent officers determine one rate per BRMA and
category, so that variable now looks up the same determined table as
BRMA_LHA_rate through benunit_lha, which takes the category variable to
read. The list-of-rents helper main added (lha_rate_for_category) and
the helpers left in LHA_category.py go, as before; LHA_category keeps
main's Universal Credit-only rule and documentation.

A new test sets every BRMA and category with the UC category set to a
different one, and checks each variable follows its own category and
matches the table and every published cell; pointing the HB variable at
LHA_category makes it fail.

Also from the delta review: the Welsh restatement wording (16 of the 17
monthly figures are multiples of GBP 5; Vale of Glamorgan one bedroom
is GBP 100 a week) and a stale comment in housing_benefit_lha_order.yaml
(the model's 2026 Maidstone one-bedroom rate is 8,975.20; the test keeps
its 9,467.64 input).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 4, 2026 13:10
@MaxGhenis
MaxGhenis merged commit c004e53 into main Oct 4, 2026
7 checks passed
@MaxGhenis
MaxGhenis deleted the lha-published-rates branch October 4, 2026 13:10
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Merged at reviewed head 088addb under Max's ruling d829 (merge on green CI at the reviewed head).

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

Labels

None yet

Projects

None yet

1 participant