Repository navigation
Update recent SDLT purchase schedules and inclusive first-time-buyer cap - #2477
Conversation
vahid-ahmadi
left a comment
There was a problem hiding this comment.
Fine once the SDLT docs page gets its chart outputs back. The law and the code look right.
@juaristi22, the schedules match the legislation. The only real problem is on the docs page.
- should:
docs/book/programs/gov/hmrc/stamp-duty.ipynb, cells 2 and 4. Almost all of the -6,300 lines are stored outputs being removed. Bothmyst.yml:58anddocs/book/_config.yml:7setexecute_notebooks: off, so the published page shows stored outputs only. On this branch the rate chart (cell 2) and the old marginal-rate chart are gone, and the new £625,000/£625,020 cash table (cell 4) has no output either. Only the statistics chart in cell 6 still renders. Please run the notebook and commit the outputs, or the page will lose its illustrations. - nit:
stamp-duty.ipynb, cells 1 to 3. The page now uses the 2023 temporary schedule as its worked illustration. Most readers will expect current law (from 1 April 2025). A 2025 chart, with the temporary period in the table, would read better. - nit: issue #2245 also flags the 2021 holiday dates (£500,000 nil band to 30 June 2021, £250,000 to 30 September 2021, while the scale returns to £125,000 on 2021-03-31). The PR body says this is left open, and it uses "Refs" rather than "Fixes", so the issue should stay open for that part. It is worth saying so on the issue.
- nit: annual sampling on 30 April means FY2024-25 uses the 3-point surcharge for the whole year, although 5 points applied from 31 October 2024. This is documented, and it is the sampling the issue asked for. I am noting it only so the FY2024 numbers are read in that light.
What I checked
- Rates and thresholds against primary sources on legislation.gov.uk:
- SDLT (Temporary Relief) Act 2023 s.1: £250,000 nil band; 5/10/12%; 3/8/13/15% for additional dwellings; first-time buyers' nil band £425,000; maximum £625,000.
- FA 2025 s.50: 5/10/15/17% from 31 October 2024 to 31 March 2025.
- FA 2025 s.51 and FA 2003 Sch 4ZA: 5/7/10/15/17% from 1 April 2025.
- FA 2003 Sch 6ZA para 1: "not more than £500,000", so
<=is correct. - The £40,000 floor for additional dwellings applies at exactly £40,000 under the existing
< mintest.
- All the YAML parameter values and dates match these sources. The
nullbrackets correctly drop the 2% band and the 5% additional band during the temporary period. - Hand-computed expectations:
- NI 2024: £925,000 main plus £400,000 additional = £33,750 + £19,500 = £53,250.
- 2027: £300,000 main plus £400,000 additional = £5,000 + £30,000 = £35,000.
- £625,020 first-time buyer = £18,751.
- Tests:
policyengine-core testonstamp_duty_land_tax_history.yaml,stamp_duty_land_tax.yamlandproperty_purchased_default.yaml: 29 passed.- pytest on
test_sdlt_purchase_schedules.pyandtest_property_transaction_tax_purchase_properties.py: 15 passed. - With the parameter and variable changes reverted, 10 YAML cases and 9 pytest cases fail.
ruff checkandruff format --checkare clean on the changed Python files.- Repo process:
- The
fixedchangelog fragment,Reproducer:andaxiom:lines are present. - All CI checks are green on the current head.
- The
- Overlaps:
- The branch includes the 2.134.1 purchase-input fix, and its tests use those input semantics. It does not duplicate that fix.
- No file overlap with the other open SDLT PRs. Their 2026 expectations (£15,000 on a £500,000 non-first purchase) are unchanged by this PR.
- No overlap with any other open PR on these paths.
- Not checked: protected pre-31 October 2024 contracts, population impact, and a run of the notebook code.
🤖 Generated with Claude Code
3716fcd to
07ce4c5
Compare
|
Regenerated the current notebook’s rate-chart and cash-table outputs and committed their execution results. The 2023 table gives £10,000 SDLT at £625,000 and £18,751 at £625,020. Notebook code, Markdown, metadata and the retained statistics-chart output are unchanged. HTML conversion passed without executing notebook code; the inherited statistics MIME warning remains recorded. The earlier 2020/2021 holiday scope remains open. The current cells also passed fresh execution after integration with main (16.71 seconds, Core 3.33.2/microdf 1.5.11), and independent captured-head code/policy review verified the output fix. Axiom-needed follow-up remains open; current-head hosted CI and your review are pending. |
Aggregate impact on certified data: passBase Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 0 (thresholds in Notes
Moves flagged for reviewNone. Spending by benefit and service
Caseloads
Household net income by decileNo household's net income changes in any year. No change in any year: receipts by tax head; government balance, each component counted once; model totals; components the model counts twice; household income totals; population; poverty rates; people in poverty; inequality; mean household net income in each side's own deciles; standard reform costings (change in gov_balance); standard reforms: change in each reform's target. Checks failing on both base and head (1)
Counted-once checkEach of 84 components was raised by £1 per unit in 2026-27, and every head of its totals was read household by household: its own head must rise by exactly £1, no other tax head may move, no other benefit may rise, and the model's own total must move by what its heads moved. A head that breaks a rule is measured again twice: with every other head held at its baseline value, and with every other head held at its value after the first £1 while the component rises again. It fails where either still shows the response. 0 failed; 0 were skipped.
Provenance
Dataset: Receipts by tax head: head levels
Spending by benefit and service: head levels
Caseloads: head levels
Government balance, each component counted once: head levels
Model totals: head levels
Components the model counts twice: head levels
Household income totals: head levels
Population: head levels
Poverty rates: head levels
People in poverty: head levels
Inequality: head levels
Mean household net income in each side's own deciles: head levels
Standard reform costings (change in gov_balance): head levels
Standard reforms: change in each reform's target: head levels
|
vahid-ahmadi
left a comment
There was a problem hiding this comment.
The notebook outputs are back, so my earlier should is fixed. One should is left, on the axiom: line. I missed it in my first review.
@juaristi22, status of my earlier points:
- should, missing notebook outputs: Fixed.
stamp-duty.ipynbcell 2 now stores the rate chart (6 traces) and cell 4 stores the cash table. I re-ran the cell 4 code on this head and got £10,000 at £625,000 and £18,751 at £625,020, the same as the stored output. - nit, use a 2025 illustration: Not done. The page still uses the 2023 temporary schedule. Fine to leave.
- nit, 2021 holiday dates in #2245: Partly done. The PR body says this is left open, but there is no note on #2245 yet. A short comment there would stop the issue being closed by mistake.
- nit, FY2024-25 sampling: no action needed.
New findings
- should, PR body:
axiom: needed. In the shared guide this option is for external contributors who can't do the Axiom work, so a maintainer can follow up. Here it leaves the parity step with no owner. Please use one of the three standard options instead. rulespec-uk has no SDLT module onmain(it has LBTT and LTT underuk/policies/govuk/), and its umbrella issue TheAxiomFoundation/rulespec-uk#63 says SDLT is not encoded, soencoded-correctisn't open to you. That leaves<rulespec-uk PR> encodedif you can run the encoder, or<issue> queuedif it is blocked. CONTRIBUTING.md asks for the blocker to be recorded in the issue and thepe-paritylabel. The legislation-sourced values instamp_duty_land_tax_history.yamlwould do as companion cases. - nit,
stamp-duty.ipynbcell 2 outputs. The first stored output inlines the whole plotly.js bundle, so the file grows from 175 KB on main to 4.7 MB. The cell also stores a tqdm stderr warning that shows your local path (/Users/mariajuaristi/Documents/Codex/...). The PIP, Pension Credit and LBTT pages also inline plotly.js, so the size follows existing practice. The stderr output with your path is worth removing, though. Dropping the bundle too may be worth a try if the chart still renders in a docs build.
What I checked
- The only new commit is
07ce4c589, which touches only the notebook.git range-diffshows the two earlier commits unchanged after the rebase onto main. Code, Markdown and the cell 6 output are unchanged. policyengine-core test policyengine_uk/tests/policy/baseline/gov/hmrc/stamp_duty: 30 passed.- pytest on
test_sdlt_purchase_schedules.pyandtest_property_transaction_tax_purchase_properties.py: 15 passed. - Overlaps: no conflict with main. No conflict in this PR's files with the other open SDLT PRs (#2235, #2315, #2322, #2363). Those branches conflict with current main in
fiscal_partition.yaml, which this PR doesn't touch. - All 16 CI checks pass on
07ce4c589. The aggregate-impact report shows no change for 2025-26 to 2031-32.
🤖 Generated with Claude Code
07ce4c5 to
13a4442
Compare
|
Removed the stored stderr warning containing my local path. All notebook code, Markdown, metadata, the Plotly bundle and six chart traces, the cash table and every other output are preserved. The Axiom process request is recorded in rulespec-uk#471, OPEN with All 16 applicable current-head checks passed on |
vahid-ahmadi
left a comment
There was a problem hiding this comment.
@juaristi22 round 3, at 13a4442f9.
Nearly there. The local path is gone and the notebook still runs. One should is left, and it sits in rulespec-uk#471, not in this PR: the operative tables for the two surcharge changes are paraphrased rather than quoted. With those added to #471, this is ready to approve.
Round-2 points
- should 5,
axiom:line: partly fixed. The body now readsaxiom: TheAxiomFoundation/rulespec-uk#471 queued, the same format as merged #2458, and Fix evidence passes. #471 is open withpe-parity, module paths and corpus selectors, required outputs, companion cases and the blocker (no approved billed encoder run). The gap is point 7 below. - nit 6, stderr output with your local path: fixed.
13a4442f9deletes only those five lines. No/Users/path is left in the notebook. The plotly bundle is still inlined, which is fine. - nit 3, note on #2245: not done. There is no new comment on #2245 since 18 Oct. Still optional.
- nit 2, 2025 illustration: unchanged, fine to leave.
New findings
-
should, rulespec-uk#471: quote the operative tables verbatim. The issue paraphrases FA 2025 s.50 ("the table is 5%, 10%, 15%, 17% at the temporary bands") and s.51, and does not quote TRA 2023 s.1(3) or s.1(5)(a) at all. Those four provisions drive the additional-dwelling rows and the £625,000 cap in the companion table, so the encoder needs their text. The figures in the paraphrase are right; only the form is short of the queued standard, and #472 already does it this way. A comment on #471 with the following would close it (text taken from the enacted versions on legislation.gov.uk):
Schedule 4ZA (higher rates of stamp duty land tax for additional dwellings etc) has effect as if for the Table A in section 55(1B) mentioned in paragraph 1(2) there were substituted—
So much as does not exceed £250,000 | 3%
So much as exceeds £250,000 but does not exceed £925,000 | 8%
So much as exceeds £925,000 but does not exceed £1,500,000 | 13%
The remainder (if any) | 15%TRA 2023 s.1(5)(a):
in paragraph 1(3), for “£500,000” there were substituted “£625,000”, and
In subsection (3) (which deals with purchases of additional dwellings), for the Table A mentioned there substitute—
So much as does not exceed £250,000 | 5%
So much as exceeds £250,000 but does not exceed £925,000 | 10%
So much as exceeds £925,000 but does not exceed £1,500,000 | 15%
The remainder (if any) | 17%In Schedule 4ZA to FA 2003 (higher rates of stamp duty land tax for additional dwellings etc), for the Table A in section 55(1B) mentioned in paragraph 1(2) substitute—
So much as does not exceed £125,000 | 5%
So much as exceeds £125,000 but does not exceed £250,000 | 7%
So much as exceeds £250,000 but does not exceed £925,000 | 10%
So much as exceeds £925,000 but does not exceed £1,500,000 | 15%
The remainder (if any) | 17% -
nit, #471 companion arithmetic. The table gives values with no working. I re-derived all six vectors and the first-buyer cases and they hold, e.g. 2024-10-31 additional at £925,000: 250,000 × 5% + 675,000 × 10% = 80,000; 2023 first buyer at £625,020, above the cap so ordinary rates: 375,020 × 5% = 18,751. One worked line per regime would let the encoder check them quickly. The other quotes I checked (s.55(1B) at 2022-09-22, Sch 6ZA paras 1, 4 and 6 at 2025-04-01) match the source. The closing "retain the Axiom-needed follow-up" wording predates the switch to
queuedand could go. -
nit, the stderr line comes back on a fresh run. I re-executed the notebook at this head: cell 2 regenerates the tqdm warning with whatever path runs it. A
warnings.filterwarnings("ignore", message="IProgress not found")before the imports in cell 2 (or clearing stderr before committing) would stop it returning next time. -
nit, stale PR body. It still ends "Current-head hosted CI remains to be checked". All 16 checks pass at
13a4442f9.
What I checked
git range-diff: the three earlier commits are identical after the rebase onto0b8af54ca; the only new commit is13a4442f9, notebook only.- Fresh worktree and uv venv at the head; executed
stamp-duty.ipynbwith nbconvert. It ran cleanly: cell 2 gives 6 chart traces, cell 4 gives £10,000 at £625,000 and £18,751 at £625,020, cell 6 gives 27 traces, the same as the stored outputs. - Fetched TRA 2023 s.1, FA 2025 ss.50 and 51, FA 2003 s.55 (2022-09-22) and Sch 6ZA (2025-04-01) from legislation.gov.uk and compared them with #471.
- Overlaps: merges cleanly with current main (
47642d1ee). #2235, #2315, #2322 and #2363 are still open and share no files with this PR. Nothing merged to main since0b8af54catouches stamp duty. - CI at the head: all 16 checks pass, including Fix evidence and the aggregate-impact report.
🤖 Generated with Claude Code
|
Added the four operative source excerpts requested in item 7 to rulespec-uk#471. The PR description now records the captured current-head CI result and requires fresh Fix evidence after this description update. Optional worked-arithmetic and warning-filter nits remain deferred. No billed encoder run is approved or executed; the underlying Axiom-needed follow-up remains open. |
vahid-ahmadi
left a comment
There was a problem hiding this comment.
@juaristi22 round 4, at 13a4442f9 (no code change since round 3).
Approving. The one open should, the verbatim law in rulespec-uk#471, is fixed, and CI is green.
Round-3 points
- should, quote the operative tables verbatim in #471: fixed. Your #471 comment quotes TRA 2023 s.1(3), TRA 2023 s.1(5)(a), FA 2025 s.50(2) and FA 2025 s.51(1). I fetched the enacted XML for all three sections from legislation.gov.uk again today. The SHA-256 of each file matches the one in your comment. Every quoted line matches the source word for word, including the curly quotes around “£500,000” and “£625,000”. I also checked all 16 table rows whole, band and rate together, so each rate sits against the right band.
- nit, worked arithmetic in #471: deferred, fine. I re-derived the values in round 3 and they hold.
- nit, the tqdm stderr comes back on a fresh run: deferred, fine.
- nit, stale "remains to be checked" line in the body: fixed. The body now records the hosted CI result at
13a4442f9. One new stale clause: it ends "fresh Fix evidence is still required after the body update", but Fix evidence has rerun since and passed. Drop it next time you edit the body.
The PR body still reads axiom: TheAxiomFoundation/rulespec-uk#471 queued. You last edited the body at 08:56:18Z, and Fix evidence ran again at 08:56:22Z on 13a4442f9 and passed.
What I checked
- Head is still
13a4442f9, so round 3's notebook run and tests still apply. - CI at the head: all 16 checks pass, including Fix evidence (rerun after the body edit), Test / Result and Aggregate impact.
- Merges cleanly with current main (
42c01db91). No stamp duty file has changed on main since round 3.
🤖 Generated with Claude Code
Refs #2245.
Adds recent ordinary residential SDLT purchase schedules for England and Northern Ireland: the temporary standard/first-time-buyer thresholds from 23 September 2022, the additional-dwelling surcharge increase from 31 October 2024, and the threshold reversion from 1 April 2025. First-time-buyer relief now includes the exact maximum price. For example, a £300,000 main-home purchase in the annual 2023 simulation falls from £5,000 to £2,500 SDLT.
Reproducer: policyengine_uk/tests/policy/baseline/gov/hmrc/stamp_duty/stamp_duty_land_tax_history.yaml::Annual 2023 main-home purchase uses temporary standard bands
Sources: SDLT (Temporary Relief) Act 2023, section 1, Finance Act 2025, sections 50 and 51, and Finance Act 2003, Schedule 6ZA. The cached packet contains eight originals and eight extracts.
Annual simulations retain the existing 30 April parameter sampling: 2022 uses the pre-September schedule; 2023/2024 use temporary thresholds and the three-point surcharge; 2025 uses restored thresholds and the five-point surcharge. Separate raw-scale tests cover the legal date boundaries. Existing purchase inputs cannot select protected pre-31 October contracts, substantial-performance exceptions or a transaction day within a year. This partial change leaves earlier 2020/2021 holidays and older history open; it does not certify ownership classification, rental/lease, corporate/nonresident or SDLT-return rounding rules, or estimate population impacts.
Validation:
Review follow-up: the missing rate-chart and cash-table outputs are now saved from genuine execution of the current notebook code. After integration with main at
8b12bce, the two current cells executed successfully in 16.71 seconds on Core 3.33.2/microdf 1.5.11, with six chart traces and the 2023 cash-table values verified. Code, Markdown, metadata and the retained statistics-chart output are unchanged. Changed-notebook HTML export and independent captured-head code/policy review passed. The 63-case model evidence above remains historical; the output check is not a fresh full model suite or full-site build. Hosted CI on the unchanged code head13a4442f96629e28499f9c97b98616713429efa5passed at 2026-10-20T08:30:41.338655+00:00 (16 effective checks, includingLintandTest / Result). This observation predates this description-only correction; fresh Fix evidence is still required after the body update.axiom: TheAxiomFoundation/rulespec-uk#471 queued