UK: model landlord property income on the taxable (net of expenses) concept, not rent received
Maintainers usually reply within 1 day
@juaristi22 is already working on this.
Since Oct 5, 2026.
Assessment
This issue has not been assessed yet.
Description
The question
HMRC has confirmed to an external user of its statistics that the Property Rental Income Statistics report property income as declared, before allowable expenses (repairs, insurance, legal and letting fees and so on). Net of those expenses, the totals line up with HMRC's other property-income figures and with the SPI public-use tape. The published PRIS amounts are therefore a gross concept, while income tax is charged on landlords' profit after allowable expenses.
This raises two questions:
- What property-income concept does Microcosm UK hold, and what does it calibrate against?
- How should property income be modelled, so that property-tax and income-tax analyses use the taxable concept at the right level?
Where Microcosm UK stands today (main)
- The spine's
property_incomeis FRS rent received, not landlord profit.frs_spine.py:585-599builds it from the household head's sub-let rent (subrent, tenure types 5–6), pluscvpay(lodgers) androyyr1(royalties), annualised. Landlords' income from letting other properties isn't in it as a profit concept. - No property-income target is bound. All 26 HMRC SPI property-income rows (13 amounts, 13 counts, by total-income band) are excluded.
docs/uk-income-anchors-280.md("Not done here") explains why: the SPI concept is landlords' net income after expenses, and the spine doesn't hold that.hmrc_income_replay_report.jsonfences the rows (full_frs_tei_band_unavailable, blocked onhmrc_spi_assessable_income). - There is no PRIS target anywhere.
- WAS round 8's
DVNetRentAmtAnnualR8(net rent) is read only as a predictor inwas_wealth, never as a target.
So the release neither overstates property income through a gross target nor corrects the FRS's known under-reporting of it. It is close to raw FRS, which is likely too low for landlords.
Related, outside this repo: the Enhanced FRS pipeline (policyengine-uk-data) calibrates property income to the PRIS amount (about £55.5bn for 2023-24). Given HMRC's clarification, that is a gross target, and it overstates taxable property income in analyses built on the Enhanced FRS. That should get its own issue in policyengine-uk-data; this one covers Microcosm UK.
What we should do
The target concept is taxable property profit after allowable expenses, the SPI concept. PRIS should be used for counts of landlords, not for amounts.
1. Put a landlord-profit variable on the spine
- Keep sub-lets, lodgers and royalties as they are, under a name that says what they are, and add landlord net property profit as its own person-level input. Then the engine's
property_incomecan be the taxable concept without mixing in other things. - Check what the engine treats as taxable property income before choosing names:
- the £1,000 property allowance;
- Rent-a-Room;
- the s.24 finance-cost restriction. Residential finance costs aren't deducted from profit and get a 20% tax reduction instead, so "profit after expenses" in the SPI may or may not be before finance costs. Pin down which before binding anything.
2. Impute landlord profit from the SPI
- Draw it through the existing SPI channel. Use a QRF on the SPI property-profit field, conditioned on:
- age;
- region;
- total income and the other income components;
- tenure;
- WAS other-property wealth (the buy-to-let value that #1089 now places).
- Keep it coherent with wealth. A household with landlord profit should hold other residential property, and the reverse should mostly hold too. The WAS coherence gate added in #1089 is the natural place for that check.
- Use identity-keyed draws, as the newer stages do, so later stages don't reshuffle it.
3. Bind the right targets
- Amounts: un-exclude the 26 SPI property-income rows once the spine holds the matching concept. They are net of expenses, which is the taxable concept.
- Counts: the PRIS landlord count is fine to bind (or keep as a diagnostic beside the SPI counts), because expenses change the amount per landlord, not the number of landlords.
- PRIS amounts: only as a diagnostic, reported against the modelled gross equivalent (profit plus imputed expenses) if we model expenses. Never as a bound amount.
4. Acceptance checks (receipts)
- The aggregate net property profit against the SPI total, and against HMRC's net figures.
- The landlord count against PRIS.
- The distribution across the SPI income bands, inside the usual fit.
- Income tax on property income against HMRC's estimate, if one is available.
- A short note quantifying the gross-to-net gap (PRIS against SPI), so the size of the concept difference is on record.
5. Downstream
- Flag in the release notes that property-tax analyses (LVT, high-value property charges, property CGT) should read the new landlord-profit variable once it lands.
- Once a fix is decided, open the matching issue in policyengine-uk-data.
Suggested order
- Confirm the engine's taxable property-income definition (allowance, Rent-a-Room, finance costs).
- Pin down the SPI field and its concept (before or after finance costs).
- Add the spine variable and the SPI-channel imputation behind a stage, with the coherence check.
- Un-exclude the SPI amount rows, add the PRIS count, and run a licensed arm with receipts.
This can go on the #1095 tracker if that's simpler.
- Dominant language
- Python
- Stars
- 0
- Forks
- 4
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 105
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from PolicyEngine/microcosm
-
Update two stale comments about the export-mass reviewed-exclusion registerPossibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 1/5 Under an hour Newbie friendliness 88/100
PolicyEngine/microcosm#1108 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
PolicyEngine/microcosm#475 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
PolicyEngine/microcosm#1117 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
PolicyEngine/microcosm#1116 ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 65/100
PolicyEngine/microcosm#1114 ·
Maintainers usually reply within 1 day
All issues in PolicyEngine/microcosm
Similar issues
-
Quantized sample scoring and slicing discard the configured epsilon gapPossibly taken @sylvesterkaczmarek claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
google-deepmind/distrax#364 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 1-3 hours Newbie friendliness 66/100
suitenumerique/conversations#798 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 83/100
Maintainers usually reply within 1 day
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
fabriziosalmi/certmate#1207 ·
Maintainers usually reply within 1 day
-
[work-item] adam-adae-onset-emergence: document the minute-precision datetime coercion (ASTTMF not derivable)Possibly taken @muse-yamaa-bot claimed this today. Openwork-item
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day