Skip to content

Stop discounting LTT and LBTT twice - #2315

Draft
MaxGhenis wants to merge 2 commits into
fix/corporate-sdlt-double-countfrom
fix/ltt-lbtt-expected-2246
Draft

MaxGhenis wants to merge 2 commits into
fix/corporate-sdlt-double-countfrom
fix/ltt-lbtt-expected-2246

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2246

Summary

expected_ltt and expected_lbtt multiplied Land Transaction Tax (Wales) and Land and Buildings Transaction Tax (Scotland) by a 4.5% property sale rate. The liabilities already charge only the year's purchases, so this discounted them a second time. This PR follows the convention #2235 sets for SDLT: the purchase draw is the expectation, so each expected value equals its liability. It also removes property_sale_rate, which no longer has any reader.

National effect on certified data, 2026-27:

All of this is measured by real runs, below. Stacked on #2235; land after #2235 and after #2241 (see "Merge order").

The bug

  • expected_ltt = property_sale_rate × land_transaction_tax and expected_lbtt = property_sale_rate × land_and_buildings_transaction_tax, with gov.hmrc.stamp_duty.property_sale_rate = 0.045. That parameter was a 2021 placeholder ("TODO add proper calculations").
  • The liabilities are already annual. They charge the prices of properties bought in the year, plus the tax on each year's addition to cumulative rent:
  • So the 4.5% applied the purchase probability a second time. On 1.58.0 in 2026-27, LBTT is £2.310bn but expected_lbtt was £0.104bn. LTT is £0.070bn, and expected_ltt was £0.003bn.
  • The totals sum the expected values. So LTT and LBTT entered gov_tax, household_tax and pre_budget_change_household_tax at 4.5% of their value, and so did any LTT or LBTT reform.

The fix

Invariants

  1. Expected is realised. expected_ltt is exactly land_transaction_tax, and expected_lbtt is exactly land_and_buildings_transaction_tax, for every household. So they also agree in weighted total.
  2. Geography and sign. LTT is zero outside Wales and LBTT zero outside Scotland, and both are non-negative.
  3. Once, at full value. Let Z set every LTT and LBTT rate to zero, including first-time buyer, additional dwelling, non-residential and rent rates. For each total, T(baseline) − T(Z) equals the liabilities land_transaction_tax + land_and_buildings_transaction_tax, independently of 1. The old scaling gave 0.045 × that; counting a head twice would give 2 ×.
  4. Zeroing removes them and nothing else. Both expected values are 0 under Z and SDLT is unchanged, so with 3 nothing else in the totals moves.
  5. Statute, differential. The model's expected LBTT and LTT equal an independent marginal-band calculation from the statutory tables, wherever the model's schedule is up to date. The schedules that are stale are recorded as strict expected failures.

#2235's partition invariants (heads = lists, traced overlap guard, coefficient one, identity) still hold.

Tests

File Covers
tests/policy/baseline/gov/revenue_scotland/expected_lbtt.yaml (9 cases) Hand-computed LBTT for purchases in Scotland, 2026; expected_lbtt = liability = household_tax = gov_tax. Cases: £400k, £1m, band tops £145k and £250k, a first-time buyer at £200k, non-residential £300k, plus zero outside Scotland.
tests/policy/baseline/gov/wra/land_transaction_tax/expected_ltt.yaml (8 cases) Hand-computed LTT for purchases in Wales; same identities. Cases: main residence £300k and £2m and the band top £180k (2022), an additional dwelling at £200k (2022), non-residential £1.2m (2026), plus zero outside Wales.
tests/test_ltt_lbtt_expected_properties.py Invariants 1–4 (Hypothesis: 12 examples of 3–5 households, all four nations, 2022–2030, purchases, rents, cumulative rents, earnings), a check that the zero-rate reform covers every schedule, and invariant 5: 6 statutory cases plus 3 strict xfails.

Rate bands cited (read on legislation.gov.uk 2026-10-11):

  • LBTT: SSI 2015/126 schedule.
    • Table A residential: 0% to £145k, 2% to £250k, 5% to £325k, 10% to £750k, 12% above. In force again from 1 April 2021; SSI 2020/215 art. 2's temporary nil band ran "until the end of the day of 31 March 2021".
    • Table B non-residential, as substituted by SSI 2018/372: 0% to £150k, 1% to £250k, 5% above.
    • First-time buyer relief takes the first £175,000 out of charge (LBTT(S)A 2013 sch. 4A para. 3).
  • LTT: WSI 2018/128 schedule.
    • Table 1 main rates as at 1 January 2022: 0% to £180k, 3.5% to £250k, 5% to £400k, 7.5% to £750k, 10% to £1.5m, 12% above.
    • Table 2 higher rates, as substituted by WSI 2020/1618: 4%, 7.5%, 9%, 11.5%, 14%, 16% on the same thresholds from £0.
    • Table 3 non-residential, also from WSI 2020/1618 and still in force: 0% to £225k, 1% to £250k, 5% to £1m, 6% above.
  • The model samples parameters at 30 April (utils/parameters.py:113).
  • Why the Welsh residential cases are in 2022. The model's main residential schedule still has the pre-10 October 2022 bands (Welsh LTT residential rates stale (missing 10 October 2022 main and 11 December 2024 higher-rate changes) #1796), and its LBTT additional dwelling supplement is 6% rather than 8% from 5 December 2024 (Scottish LBTT Additional Dwelling Supplement stale at 6% (should be 8% from 5 December 2024) #1795). So the residential LTT cases are in 2022, when the model matches the law. The 2026 schedules are strict xfails citing those issues: WSI 2022/1027 Table 1, WSI 2024/1311 Table 2, and the LBTT(S)A 2013 sch. 2A para. 4(2) supplement as amended by SSI 2024/367. Fixing either issue turns its xfail into a failure, which prompts moving that case into the statutory set.

Cross-check against Axiom. The test's statutory tables reproduce every value in rulespec-uk's companion tests, computed:

  • uk/policies/govuk/lbtt.test.yaml: £200k → 1,100; £300k → 4,600; £500k → 23,350; £800k → 54,350; additional £300k → 4,600 + 24,000.
  • uk/policies/govuk/ltt.test.yaml, current main rates: £300k → 4,500; £500k → 18,000; £800k → 41,750; £2m → 171,750. Higher rates: £300k → 19,950.

Red on base, green here. Run against #2235's head (41e970b):

  • 9 of the 17 new YAML cases fail: every case with a non-zero tax.
  • The property test fails at invariant 1: expected_lbtt 6,373.53 vs liability 141,633.98.
  • With invariant 1 deleted, invariant 3 alone still fails ("household_tax: LTT and LBTT not counted once at full value").

On this branch all pass.

Local runs (Python 3.13, policyengine-core 3.33.0):

  • The 17 new YAML cases: 17 passed.
  • The 9 YAML files that test expected_lbtt, expected_ltt, the LTT/LBTT liabilities, gov_tax or household_tax: 60 passed.
  • Stamp duty, WRA and surcharge YAML: 41 passed.
  • test_ltt_lbtt_expected_properties.py: 8 passed, 3 xfailed.
  • test_fiscal_partition.py and test_sdlt_counted_once_properties.py: 40 passed.

CI. The PR workflow runs only on PRs into main, so for this stacked PR I dispatched it on the branch with workflow_dispatch. It runs again when the PR is retargeted to main.

National impact (real runs)

Setup.

Current law, £bn: on #2235 alone

2025-26 2026-27 2027-28 2028-29 2029-30 2030-31
expected_ltt, base → head 0.003 → 0.065 0.003 → 0.070 0.003 → 0.076 0.004 → 0.082 0.004 → 0.088 0.004 → 0.095
expected_lbtt, base → head 0.099 → 2.211 0.104 → 2.310 0.109 → 2.424 0.114 → 2.539 0.119 → 2.654 0.125 → 2.780
Change in gov_tax, household_tax, pre_budget_change_household_tax, gov_balance +2.174 +2.273 +2.387 +2.503 +2.619 +2.746
Change in household_net_income −2.174 −2.273 −2.387 −2.503 −2.619 −2.746

Current law, £bn: with #2241 merged into both

2025-26 2026-27 2027-28 2028-29 2029-30 2030-31
expected_ltt, base → head 0.003 → 0.065 0.003 → 0.070 0.003 → 0.076 0.004 → 0.082 0.004 → 0.088 0.004 → 0.095
expected_lbtt, base → head 0.017 → 0.367 0.017 → 0.385 0.018 → 0.405 0.019 → 0.427 0.020 → 0.448 0.021 → 0.471
Change in gov_tax, household_tax, pre_budget_change_household_tax, gov_balance +0.413 +0.435 +0.460 +0.486 +0.512 +0.541
Change in household_net_income −0.413 −0.435 −0.460 −0.486 −0.512 −0.541

In every run, land_transaction_tax, land_and_buildings_transaction_tax, expected_sdlt and hbai_household_net_income are unchanged by this PR.

Where the LBTT comes from, 2026-27.

Reform scoring. An illustrative reform raises the top residential band by 1pp in both countries: LBTT over £750k from 12% to 13%, and LTT main rates over £1.5m from 12% to 13%. The change in gov_tax from current law, £bn:

Code 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31
base (#2235) +0.0013 +0.0015 +0.0018 +0.0021 +0.0023 +0.0026
head +0.0282 +0.0335 +0.0396 +0.0457 +0.0517 +0.0584
base + #2241 +0.0006 +0.0007 +0.0008 +0.0008 +0.0009 +0.0010
head + #2241 +0.0143 +0.0156 +0.0171 +0.0185 +0.0200 +0.0216

Accounting checks (every year 2025-26 to 2030-31, current law):

Check base head base + #2241 head + #2241
max per-household |expected_ltt − land_transaction_tax| £25,277 £0 £25,277 £0
max per-household |expected_lbtt − land_and_buildings_transaction_tax| £127,212 £0 £112,548 £0
households with ≥2 of SDLT, LTT, LBTT 0 0 0 0
max per-household |gov_tax − sum of its list| (float32) £0.12 £0.12 £0.12 £0.12
non-finite outputs none none none none

Distribution. Head − base in household net income, weighted mean £ per household, 2026-27:

D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 All
#2235 alone −8.49 −0.50 −1.33 0.00 −54.32 −1.10 −5.69 −80.25 −278.20 −305.07 −72.48
with #2241 −8.49 −0.50 −0.98 0.00 −54.32 −0.94 −5.69 −69.89 −2.97 −4.68 −13.86

The payers are few and the deciles are lumpy.

Poverty. BHC and AHC, absolute and relative, are unchanged to four decimal places in every year and every pair. hbai_household_net_income does not move.

Evidence and scripts: ~/reviews/uk-ltt-lbtt-2246/ (impact.py, compare.py, impact.md, runs/, shas.txt).

Merge order

Land after #2235 (this PR's base) and after #2241.

Without #2241, this PR moves the £1.838bn a year of LBTT that #2241 removes from 4.5% into the totals at full value, until #2241 lands. That LBTT is on Scottish property stocks charged as purchases (#2238). Landing #2241 first means the totals only ever gain the £0.435bn on real main-residence purchases.

If #2241 lands first, the LBTT data_note stays accurate: it gives both figures. When #2235 merges, GitHub retargets this PR to main and CI runs on it.

Not in this PR

  • Stale schedules, recorded as strict xfails:
  • LBTT lease rates. lbtt/rent.yaml charges 5% above £2m. SSI 2020/24 art. 2 made that band 2%. The model also applies the lease table to residential rent. On 1.58.0 no household has a rent charge, so the impact is zero there. Split into its own task.
  • Component variables are not country-gated. ltt_on_residential_property_transactions and lbtt_on_residential_property_transactions are computed for every UK purchaser: £22.4bn and £29.2bn nationally in 2026-27. Only land_transaction_tax and land_and_buildings_transaction_tax multiply by ltt_liable / lbtt_liable. The totals are right, and the partition lists the components as exclusions, but don't sum the components.
  • Purchase data. 1.58.0 draws its purchasers UK-wide at 3.85%, which gives 0.027m Welsh and 0.065m Scottish purchasers a year. Imputing purchases by nation belongs in policyengine-uk-data, with the d833 batch. See the benchmark below.

Against official receipts

These figures were read from the official pages on 2026-10-11. The model figures are 2025-26 from the runs above; the outturn is 2024-25.

Model, expected_lbtt / expected_ltt before → after this PR (with #2241) Outturn
LBTT on residential conveyances, excluding ADS £0.017bn → £0.367bn £484.6m
LBTT ADS (net) £0 (no additional-dwelling purchases on 1.58.0 after #2241) £204.3m
LBTT on non-residential conveyances and leases £0 £197.2m and £34.3m
Scottish residential purchases 0.065m households 102,100 residential returns
LTT, residential £0.003bn → £0.065bn a year £67.2m in January–March 2025 alone

Sources:

After this PR, the model's main-residence LBTT is about three quarters of Revenue Scotland's residential (non-ADS) receipts; before it, it was about 3.5%. Welsh LTT stays well below outturn, because the data has few Welsh purchasers. The remaining gaps are the purchase data: ADS, non-residential and lease transactions, and the purchaser count. They are not this PR's convention.

axiom: n/a: microsim-only. This changes the expected-value convention by which the model's tax totals count LTT and LBTT. The statutory liabilities are unchanged; rulespec-uk encodes them in uk/policies/govuk/ltt.yaml and lbtt.yaml, and this PR's statutory tables reproduce their companion tests.

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 11, 2026 12:24
expected_ltt and expected_lbtt multiplied land_transaction_tax and
land_and_buildings_transaction_tax by property_sale_rate (0.045). Those
liabilities already charge only the year's purchases (on FRS-based data,
the seeded annual purchaser draw) and rent increments, so the sale rate
discounted them a second time. Follow #2235's SDLT convention: the
purchase draw is the expectation, and each expected value equals its
liability.

property_sale_rate now has no reader, so remove it and the leftover
test overrides of it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
YAML cases hand-compute LBTT (SSI 2015/126 Tables A and B, first-time
buyer relief) and LTT (WSI 2018/128 Tables 1 to 3) on purchases in
Scotland and Wales and check expected = liability = the household's
tax totals. The Hypothesis test checks expected equals realised and,
independently, that zeroing every LTT and LBTT rate lowers each total
by exactly the liabilities. A differential test compares the model with
the statutory tables; the schedules it has stale (issues 1795, 1796) are
strict expected failures.

On the #2235 head (41e970b), 9 of the 17 YAML cases and the property
test fail; here all pass.

The partition's data notes now give the measured 1.58.0 figures.

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

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant