Repository navigation
VAT grossing property tests and later-cut provenance; coverage re-derived on the next certified cut - #2634
VAT grossing property tests and later-cut provenance; coverage re-derived on the next certified cut#2634MaxGhenis wants to merge 4 commits into
Conversation
survey_consumption_coverage was derived in #2187 on Microcosm f9d1922c. The 6cba5d71 and a133f37a cuts record about 10% more standard-rated consumption, so with 0.67 total vat ran 7.5% to 10.3% above OBR receipts in 2024-25 to 2026-27. The doc's own calculation on a133f37a gives 0.739 for the latest outturn year; it is used as 0.74 (product 0.518), inside the 0.720 to 0.756 bound from receipts and the ready reckoner. Adds Hypothesis properties for the grossing factor and for vat being statutory liability over the shipped product. Totals at the new product and the reform-regression fixture wait on runs in the hub's next reserved window. Fixes #2633 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The deprecated combined factor has one undated value, so every year, 2024 included, takes the two factors' product. A YAML case pins vat in 2024; adding a dated entry to the deprecated factor makes it fail. The doc's inputs now give the Hugging Face revisions of the a133f37a and 6cba5d71 tags, and the reproduction snippet pins a133f37a's revision. Refs #2633 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aggregate impact on certified data: passBase Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 49 (thresholds in Notes
Moves flagged for review
9 more flags are in the report artifact. Receipts by tax head
Spending by benefit and service
Caseloads
Government balance, each component counted once
Model totals
Standard reform costings (change in gov_balance)
Standard reforms: change in each reform's target
Household net income by decileNo household's net income changes in any year. No change in any year: household income totals; population; poverty rates; people in poverty; inequality; mean household net income in each side's own deciles. Checks failing on both base and head (1)
Counted-once checkEach of 86 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
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
|
…p.isclose Review r1 of #2634 (Sol, REQUEST_CHANGES at b6d8af5) found: - The £9.94bn one-point figure was described as a reform run without the runs being cited. The doc now names them: reform minus baseline `vat` and `gov_balance` on 6cba5d71 (revision bb225848), policyengine-uk 2.135.7 and 2.152.6, £9.94bn in 2026-27 and £9.68bn in 2025-26. - The moved-legacy property classified closeness with pytest.approx, which takes the larger tolerance, while the helper uses np.isclose, which adds them. A legacy value of 0.518005185 failed the property. The band is now stated once (1e-8 + 1e-5 x the default), the moved property draws values outside it, a new property draws values inside it, and fixed cases sit at 0.99 and 1.01 bands either side. Changing the helper to exact equality fails the inside cases. - The helper properties kept Hypothesis's 200 ms deadline and flaked on a loaded host; they now have no deadline. - The doc attributed both cuts' rows to main and core 3.33.2; it now gives each cut's recorded versions. - The parameter said 6cba5d71 matches a133f37a to three decimal places; it now says the 2024-25 coverage (0.739) matches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review r1 (GPT-6.1 Sol, REQUEST_CHANGES at b6d8af5): all five findings are fixed in e1ff493.
Local runs at e1ff493:
Still PENDING, and the PR stays a draft until they are done:
These run in the hub's next allowed host window. A delta review follows them. |
|
Plan change (24 Oct): this PR no longer lands on
So the value is re-derived on Monday's final cut, after its fit, with the formula on main. The 2pp fixture is updated from a run on the same code, and a delta review follows before this is marked ready. If that run puts VAT within ±2% of receipts at 0.67, this keeps 0.67. At #1383's head The figures run today are a reference only, on
|
Takes main's survey coverage (0.67) and derivation doc, and keeps this branch's property tests, the 2024 pin test and the record of the later Microcosm cuts. Test expectations go back to the 0.469 product. The coverage is re-derived with #2189's formula on the next certified cut. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged main (with #2189) at The coverage is re-derived with #2189's formula on the next certified cut, after its fit. Title and body updated to match. |
Fixes #2633
Draft. WIP: the coverage value is re-derived on the next certified Microcosm cut before this lands. This branch now carries main, including #2189 (energy-bill VAT is added after grossing and is not grossed up; the coverage is derived against receipts net of energy VAT). It ships main's coverage, 0.67, plus test, doc and provenance fixes. The value it lands with comes from a run with #2189's formula on the cut that follows microcosm#1383's rebuild, after that cut's fit:
At #1383's merged head,
obr.vatis held out of the fit (María's ruling of 24 October;calibration_measure_exclusions.json), so that measurement is not circular. Every figure marked PENDING comes from a run, not from arithmetic on other runs.What changed and why
gov.simulation.vat.survey_consumption_coveragewas derived in #2187 on the Microcosm UK 2024-25 cutf9d1922c(2 Oct) and re-derived with the energy split in #2189. Its metadata says to re-derive it when the dataset it should match changes.The certified
6cba5d71(policyengine.py 6.10.2) anda133f37a(the current default; policyengine.py#715) cuts record about 10% more standard-rated consumption: £435.60bn against £396.15bn in 2024-25. Before the energy split, with 0.67, totalvatona133f37a(mainc0252415a) came out as follows:vatOn
6cba5d71, a reform run that raises the standard rate from 20% to 21% changed totalvatandgov_balanceby £9.94bn in 2026-27 (PolicyEngine-UK 2.135.7 and 2.152.6 agree), 12.9% above HMRC's £8.8bn ready reckoner. These pre-split runs are recorded in the doc as the reason to re-derive; they do not set the value.Changes in this branch against main:
test_vat_grossing_properties.py; a 2024 case invat_grossing.yaml(2,050 / 0.469 = 4,371.00, the same product as later years).docs/engineering/vat-coverage.mdgains a "Later Microcosm cuts (24 October 2026)" section with thea133f37aand6cba5d71inputs (tags, revisions, SHA-256), versions and the pre-split rows, and a pointer from the "Which datasets" paragraph.survey_consumption_coveragestays 0.67 andmicrodata_vat_coverage0.469 until the run above.Impact
With the parameters unchanged, this branch moves no model output: it adds tests and docs. PENDING, if the run above moves the coverage, runs at the new value of:
vaton the new cut and on Enhanced FRS 1.58.1, 2024-25 to 2026-27;vatandgov_balance);Raise VAT standard rate by 2ppregression fixture (reforms_config.yaml), updated from that run.Invariants
These hold for every input:
survey_consumption_coverage × household_share_of_receipts.isclosetolerance) overrides the two; a value inside the band counts as untouched.vatwith no energy consumption equals (standard rate ×full_rate_vat_consumption+ reduced rate ×reduced_rate_vat_consumption) / shipped product. It is linear in each household's consumption, with no cross-household term.vat_grossing.yaml, 2024 case). Adding a dated entry to it, which would send earlier years down the legacy path, fails that case.Invariants 1–3 are Hypothesis tests in
policyengine_uk/tests/test_vat_grossing_properties.py. Invariant 4 is intest_vat_grossing_legacy.py(main). A mutation that drops the household share fromvat_grossing_factorfails invariant 1. For invariant 2, fixed cases sit at 0.99 and 1.01 bands either side of the declared value; changing the helper'snp.iscloseto exact equality fails the inside cases. The helper properties have no Hypothesis deadline, since they check algebra, not speed.The dataset-level check (total
vatwithin a few percent of receipts on the certified Microcosm cut) can't run in CI, because the tests' certified dataset is Enhanced FRS 1.58.1. It is reproduced by the doc's snippet.Interaction with open work
PolicyEngine/microcosm#1383 (merged) locks policyengine-uk 2.151.0 and holds
obr.vatout of the fit as a diagnostic (commit94d4102fd; exclusion approved 2026-10-24, expiring 2027-01-24). The exclusion says the row rebinds once policyengine-uk re-derives the factor on a file that does not bind it. If a later cut bindsobr.vatunder 0.67, its fit would absorb the factor, so this PR's value is paired only with a cut on which a run supports it. Any lock bump is María's call.Reproducer: n/a: tests and docs only; model source and dependencies are unchanged until the coverage is re-derived
axiom: n/a: a microsimulation calibration factor for survey under-recording, not law
🤖 Generated with Claude Code