Repository navigation
Stop counting rent paid by boarders and lodgers as their property income - #503
Merged
Merged
Conversation
FRS CVPAY is the rent a boarder or lodger pays the householder, after deducting any state benefits to help with rent (FRS question CvPay, asked about each person not related to the HRP in the second and later benefit units of a conventional household). frs.py added it to the payer's own property_income. Move the property income calculation into a tested helper, frs_property_income, that keeps SUBRENT and ROYYR1 and drops CVPAY. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #503: the seeded cases only draw non-negative amounts, so the floor at zero was never active, and every fixture had a unique index while create_frs stacks the adult and child tables. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 1, 2026
Open
21 of 52 tasks
MaxGhenis
marked this pull request as ready for review
October 4, 2026 10:28
Contributor
Author
|
Handing this PR to the UK hub. Its original session is gone, and the session that owns #509 (stacked on this one) took it over on 2026-10-02. It lands only in Max's uk-data release batch (d833), first in its stack (#503, then #506 and #509).
|
Contributor
Author
|
Queued in release PR #544 for the 10/8 uk-data batch. It lands only on Max's go (d833). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
frs.pybuilds each person'sproperty_incomefrom three FRS amounts: SUBRENT, CVPAY and ROYYR1. CVPAY is not rent received. It is the rent a boarder or lodger pays the householder, and it sits on the boarder's or lodger's own adult record. So the build counted an expense as income for the person paying it.This PR removes CVPAY from
property_incomeand moves the calculation into a tested helper,frs_property_income.Evidence that CVPAY is rent paid
Source: the documentation shipped with the FRS 2024-25 release this repo builds from (UK Data Service SN 9563).
The other inputs were checked against the same documents and are unchanged:
property_incomemiscellaneous_incomeproperty_incomefor the HRP of owner householdsThe FRS quality report says most monetary amounts are converted to weekly values, which matches the
WEEKS_IN_YEARannualisation here.Invariants and tests
frs_property_income(person, household)is meant to have these properties.test_frs_property_income.pychecks the first three on 200 seeded random sets of households with non-negative amounts, which is all the FRS records for these variables (Hypothesis is not a dependency of this repo):WEEKS_IN_YEAR× (SUBRENT of owner households + all ROYYR1), so each amount is counted once.WEEKS_IN_YEAR× £x and nobody else's.Five example tests cover a lodger's rent, rent from other property for a non-HRP adult, subletting rent going to the HRP, the floor at zero, and the repeated index labels that
create_frsproduces by stacking the adult and child tables. Putting CVPAY back into the helper fails 398 of the 605 tests.Differential check. I built the base FRS on main (
b45c373) and on this branch (db089ce; the later commit only adds tests) and compared every column of every table. Onlyproperty_incomediffers, on 43 records, and each of those falls to zero. The helper is otherwise the old inline code: the one behavioural difference is that a person whose household is missing from the household table now gets no SUBRENT where the old code raisedKeyError.Measured impact
All figures are aggregates. Simulations use policyengine-uk main (
44240bd8).Base FRS 2024-25 (survey weights, no imputation or calibration)
Stored values in the two base builds, before uprating:
property_incomefalls from £16.98bn to £16.18bn (−£0.81bn, −4.8%). People with any property income fall from 2.01m to 1.87m (−138k, from 43 survey records). Summing CVPAY in the raw tables gives the same £0.81bn for 2024-25, and £1.23bn for 2023-24.Means-tested benefits rise slightly for some of the people affected, and poverty rates barely move. Each of those changes rests on fewer than ten survey benefit units or households, so the figures are not shown.
Enhanced FRS (full rebuild)
I built main (
b45c373) four times and this branch twice. All six builds used production settings (512 epochs,PE_UK_DATA_OA_CLONES=1), the same raw inputs, the same cached trained models (income, wealth, consumption, VAT, public services, salary sacrifice) and the repo'suv.lock(policyengine-uk 2.93.0).A rebuild does not isolate the fix. Four things differ between a main build and a branch build:
impute_capital_gainshas stacked its copy of the dataset).impute_wealthpredicts wealth from household income, anduprate_property_by_regionthen rescales every household with a positive imputed home value in a region by one regional factor. Imputed property wealth differs for 21,722 households.impute_frs_only_variablesis fitted afresh in each build withproperty_incomeamong its predictors. On the SPI-donor half, imputed benefit reports and pension contributions differ (for example reported Universal Credit on 878 person rows).stack_cgt_band_donorspicks 270 donor households with a seeded draw whose probabilities depend on each first adult's total income. Changing a few incomes changes the draw. All four main builds stack the same 270 households, and both branch builds stack another set. Only 58 of the 270 are common to both.So the table gives the range of the four main builds beside each branch build.
Calibration targets
Each build's fit to the national targets, evaluated at the calibration year (2025) with
get_loss_results:hmrc/cgt_taxpayers_band_1000000: 12% to 14% over target on main, 8% under on the branch) and the DWP Universal Credit payment bands. A different donor draw would move the capital gains bands.Not in this PR
Merge note
This PR lands only in the single uk-data release batch that Max approves (d833), first in its stack (#503, then #506 and #509). Every merge to uk-data main builds and publishes a release, so nothing here merges on its own.
#498 edits the lines just above the property income block, so the two PRs conflict textually in
frs.py. Whichever merges second keeps both one-line calls:frs_dividend_income(...)andfrs_property_income(...).axiom: n/a: data pipeline change (FRS variable mapping), no rule change.
🤖 Generated with Claude Code