Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fddad49
Draft Autumn Budget 2026 savings/property and trading explainers
hua7450 Oct 28, 2026
7f90092
Add provisional dashboard population results to draft explainers
hua7450 Oct 28, 2026
f581840
Clarify income bands and prepare draft review handoff
hua7450 Oct 28, 2026
cdeb356
Add a line chart type for blog posts, and valueLabels for bar charts
PavelMakarchuk Oct 28, 2026
5a70185
Keep savings/property post and shared analysis in base draft
hua7450 Oct 28, 2026
932ae46
Keep line chart axis labels, axis title and legend apart
PavelMakarchuk Oct 28, 2026
b2a1836
Pin Budget paragraph citations and record latest review decisions
hua7450 Oct 28, 2026
6d3b480
Round savings/property worked table to whole pounds
hua7450 Oct 28, 2026
9d88f94
Flag pending replacement of regenerated national results
hua7450 Oct 28, 2026
1ecce9e
Merge branch 'pavel/blog-line-chart' of https://github.com/PolicyEngi…
hua7450 Oct 28, 2026
4e6f0b1
Align budget explainers with PTA forecast and chart methodology
hua7450 Oct 28, 2026
e6714df
Merge main and address savings/property publication feedback
hua7450 Oct 28, 2026
fc41785
Add illustrated savings and property cover
hua7450 Oct 28, 2026
c65a52f
Clarify cover image provenance
hua7450 Oct 28, 2026
5ea52ab
Merge main into the savings and property post (keep both posts.json e…
MaxGhenis Oct 28, 2026
e7e2e32
Split property income tax explainer from savings draft
hua7450 Oct 28, 2026
be65300
Clarify property sources and shared household methodology
hua7450 Oct 28, 2026
0bf4f73
docs: clarify budget household generator scope
hua7450 Oct 28, 2026
18bc5f7
docs: add property microsimulation to Budget explainer
hua7450 Oct 28, 2026
3f1cf06
docs: address property microsimulation review feedback
hua7450 Oct 28, 2026
0c6f7c8
docs: remove withdrawn microsimulation previews
hua7450 Oct 28, 2026
5772c91
docs: remove internal review-status wording
hua7450 Oct 28, 2026
2afba85
docs: compare property estimate with the OBR's income tax line
MaxGhenis Oct 28, 2026
4796551
docs: say the OBR income tax line is the closest comparison, not the …
MaxGhenis Oct 28, 2026
91f812f
docs: broaden property explainer key figures heading
hua7450 Oct 28, 2026
d17842f
docs: say 'exceeds' rather than 'is above' (style)
MaxGhenis Oct 28, 2026
0620d73
docs: dashboard line covers the Budget measures we model
MaxGhenis Oct 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions analysis/uk-budget-2026-income-tax/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Autumn Budget 2026 income tax explainers

This shared directory supports three standalone posts: the property income rate increase ([PR #1460](https://github.com/PolicyEngine/policyengine-app-v2/pull/1460)), the savings income rate increase ([PR #1466](https://github.com/PolicyEngine/policyengine-app-v2/pull/1466)) and the trading allowance increase ([PR #1463](https://github.com/PolicyEngine/policyengine-app-v2/pull/1463)). Property and savings were split at the author’s request on 28 October 2026; savings remains a separate draft pending its dashboard data release. The articles compare the newly announced measures with the already legislated 2027–28 baseline. The shared `SAVINGS_PROPERTY` reform in `generate_households.py` changes savings and property rates together; it is not a separate property-only reform.

## Reproduce the household calculations

From the repository root, using Python 3.13:

```sh
uv venv --python 3.13 analysis/uk-budget-2026-income-tax/.venv
uv pip install --python analysis/uk-budget-2026-income-tax/.venv/bin/python -r analysis/uk-budget-2026-income-tax/requirements.txt
analysis/uk-budget-2026-income-tax/.venv/bin/python analysis/uk-budget-2026-income-tax/generate_households.py
```

The generator uses hypothetical adults, without population microdata. It records inputs and outputs and checks the results against independent arithmetic. The reform parameters match [dashboard PR #290](https://github.com/PolicyEngine/uk-autumn-budget-dashboard-2026/pull/290) at the immutable commit recorded in `provenance.json`. Both the baseline and reform use the same October 2026 forecast as the [Pension Tax Allowance analysis, PR #1457](https://github.com/PolicyEngine/policyengine-app-v2/pull/1457) (dashboard commit `640426575270224db9b04d6c94d30e264a347be2`). Supplied income amounts remain fixed in 2027–28; the forecast updates statutory and other model parameters. Fixed nominal incomes do not remove the need to use the agreed forecast.

The checked outputs include 23 household comparisons and 93 displayed points across the two income curves. The displayed lines use £100 intervals and the exact policy breakpoints. All four series are independently checked against the model at every £2 from £500 to £5,000, including a comparison of the plotted interpolation with the engine results; `curve-validation.json` records counts and maximum errors. The non-integer £1,333⅓ expense-choice breakpoint is also calculated with the model. To also verify the original dashboard parameter builder, pass `--dashboard-checkout /path/to/checkout` with that checkout at the recorded commit. This check is optional and performs no download.

The `landlord_*` records in `households.json` and `households.csv` support the property article. They have no savings income, so the combined reform's savings rate changes do not affect their results. The example with a £30,000 salary, £6,000 of taxable property profit and no eligible finance costs was checked separately with the property-only reform. The `saver_*` and mixed `property_then_savings_order` records, savings curves, and savings-rate and Treasury row 62 metadata in `provenance.json` remain shared records for savings draft #1466; they are not property-only results.

The savings draft (#1466) reproduces `savings-interest-chart.json`; the trading article (#1463) reproduces `trading-allowance-chart.json`. The property article's native bar chart uses the verified 2027 and 2031 decile means in `property-population/`. Reinsert each chart's contents only into its corresponding article when regenerating it.

## Current article scope

The property draft now includes national revenue and decile averages from the approved property-only snapshot in dashboard PR #290. `property-population/` retains the immutable source record, original receipt, three aggregate CSVs and the verification summary. Reach, poverty and inequality figures are omitted pending separate disclosure clearance. It is an approved branch snapshot, not independently verified as the production deployment. Recheck its identity and figures against the final released dashboard before merging.

The savings and trading posts retain household calculations and Treasury costings only. Withdrawn combined national outputs are not published in this directory.

## Dataset decision

Retain the dashboard's adopted `policyengine` 6.11.1 bundle, with UK 2.151.0, core 3.33.3 and national data cut `a6299504`. The certificate, full dataset ID and checksum are recorded in `provenance.json`. The newer candidate in [policyengine.py PR #725](https://github.com/PolicyEngine/policyengine.py/pull/725) is awaiting certification/adoption. A future update must change the package and dataset provenance together and regenerate the analysis.

The household generators need no population microdata. The property national results reuse the approved single-measure dashboard artifact recorded in `property-population/`; they were not generated locally. Both baseline and reform use the same October 2026 OBR forecast. Series not updated by the overlay retain the model's March forecast path; the underlying calibration remains pre-Budget.

Treasury forecasts are labelled separately. Compare fiscal-year Treasury receipts with the model's annual government-balance effects, documenting behavioural, timing and coverage differences. Do not attribute a particular discrepancy to one of those factors before reconciliation. No separate winner/loser shares or absolute affected-person counts are provided. Reach, poverty and inequality figures require separate disclosure clearance before publication.

## Checks before publication

- Recheck the property draft's `property-population/` artifact identity, figures and comparison flags against the final released dashboard. Restore national scope in the other posts only from their own reconciled sources. Add affected-person counts or shares only when the producer exports them and they have disclosure clearance; do not infer them from average changes.
- Confirm the treatment of Scottish landlords' finance-cost relief against the final Budget implementation. The pinned model links that relief to the UK property basic rate even for Scotland.
- Check trading allowance coverage: gross receipts and actual expenses are needed to model the deduction choice; the pinned model does not apply the allowance to its separate miscellaneous-income input.
- Verify the final public dashboard link and add links to these explainers within the dashboard. The source checkout's README supplies the current Vercel dashboard URL.
- Have the policy interpretation and calculations reviewed before merging. Draft status and publication approval are tracked on each article’s PR.

The three articles use the site's native tables, chart blocks and cover assets. Household curves use the shared numeric line renderer from [PR #1462](https://github.com/PolicyEngine/policyengine-app-v2/pull/1462); no duplicate chart implementation or country-model code is added.

## Validation on 28 October 2026

`make format`, `make lint`, `make typecheck` and `make test` passed. The tests ran on Node 26.12.1: 6,042 app tests and 508 website tests passed, with 10 app tests skipped by the existing suite. After inserting the final chart data, the chart-parser and post-metadata checks passed again (18 tests). All 23 household comparisons and 20 curve points passed independent arithmetic checks.

Cover assets and native chart specifications have been validated. The rendered page layout has not been checked at desktop or mobile widths.


## Additional trading and calculator examples

```sh
analysis/uk-budget-2026-income-tax/.venv/bin/python analysis/uk-budget-2026-income-tax/generate_trading_extensions.py
```

This checks five additional synthetic pairs requested in the [trading allowance review](https://github.com/PolicyEngine/policyengine-app-v2/pull/1460#issuecomment-6472758764), including UC, Class 4 and missing-receipts fallbacks, on the same pinned October forecast as the main generator. `trading_extensions.json` records complete inputs, raw outputs and arithmetic checks. `dashboard_salary_comparison.json` records the calculator's March-index salary comparison. Household examples use no population data. Shared analysis is kept in the property base PR #1460 so the trading article can be reviewed in a separate stacked PR. The savings article is a separate draft PR based on main; its shared-analysis link resolves after #1460 lands.

## Alignment with the Pension Tax Allowance analysis

The exact forecast input is retained as `obr_october_2026.json`; `forecast.py` verifies its Git blob before use and reconstructs the source’s rounded fuel-duty path. Its complete eight-path parameter mapping was checked for exact equality with the immutable dashboard source’s `with_forecast(None).parameter_changes`. Both synthetic generators pass that mapping to `pe.uk.calculate_household`. The savings/property generator uses the combined savings and property reform; its savings changes have no effect on the landlord records because those households have no savings income. The trading generator uses the trading allowance reform. There is no population data load to precede, and no other Budget measure is activated.

The Pension Tax Allowance analysis uses £100 chart sampling plus the true breakpoints and verifies the results on a denser model grid. These drafts follow that method: numeric income axes, explicit £ formats, named threshold markers and independent validation at every £2. Reader-facing tables use whole pounds under the [rounding review](https://github.com/PolicyEngine/policyengine-app-v2/pull/1460#issuecomment-6473972686); raw analysis retains precision.

The household forecast pin and property population forecast pin are recorded separately. Applying the household overlay does not regenerate or validate national results. The property article uses an approved property-only source with execution-bound provenance in `property-population/`.

The October-forecast rerun passed all 23 household comparisons and all 5 trading extension pairs. All policy deltas remain unchanged. Some absolute levels change: the three Scottish cases’ income-tax levels fall by £2.93 on both sides, and the parent’s total benefits/net income rise by about £20.10 on both sides. These do not change the article’s reported tax or household gains. The 93 displayed chart points passed 18,008 model-liability comparisons and 9,004 interpolation comparisons over 2,251 income points per series. The largest interpolation difference is £0.0033, below the £0.01 tolerance.

## Editorial cover images

The posts use original teal editorial illustrations generated with the built-in image tool. Property and savings reuse the original combined-draft cover unchanged under their own asset paths. `cover-prompts.json` records the complete prompts, output paths, encoding settings, dimensions and checksums. The WebP files retain the generated 1672 × 941 pixel dimensions and are selected by each post's `image` metadata, supplying the article hero, research card and social preview. The unused combined-draft SVG cover was removed when the article was split. Article text, charts and calculations are unchanged by the cover update.
30 changes: 30 additions & 0 deletions analysis/uk-budget-2026-income-tax/cover-prompts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"tool": "built-in image_gen",
"intent": "Original editorial cover illustrations",
"reference_style": "PolicyEngine Autumn Budget 2026 energy and Pension Tax Allowance covers; deep teal, mint, white, restrained dimensional illustration.",
"assets": [
{
"path": "app/public/assets/posts/uk-autumn-budget-2026-property-income-tax/cover.webp",
"prompt": "Use case: stylized-concept.\nAsset type: original editorial cover illustration for PolicyEngine's UK Autumn Budget 2026 article on savings and property income tax.\nCreate a polished wide 16:9 landscape illustration, intended final size 1600x900. Match a coherent nonprofit policy research illustration series: deep dark teal background, soft subtle teal vignette, pale mint and turquoise objects, clean vector-like shapes rendered as a raster image, restrained dimensional depth, gentle shadows, crisp edges, professional calm neutral tone.\nScene: a simplified British terraced house and a savings coin stack arranged together beside a large white income-tax statement with a teal header and a few muted grey abstract lines. One mint coin bears a clear British pound symbol (£). House, savings and statement should read as one coherent still life about taxing rental income and savings interest.\nComposition: main objects within the central 65 percent of the canvas, clear at thumbnail size, generous breathing room on every edge, balanced wide layout, a subtle floor line. Avoid tiny details.\nText: only a single £ symbol on the coin; no words, no tax rates, no numbers, no labels, no title, no logos, no watermark.\nConstraints: original illustration, no people, no flags, no political symbolism, no arrows or data charts, no claims about gains or losses. The image should look like a refined flat editorial illustration with subtle depth, not a photograph or a glossy toy render.",
"width": 1672,
"height": 941,
"format": "WebP",
"encoding_quality": 85,
"pixels_resized": false,
"bytes": 59420,
"sha256": "fcaa9776fa6ebfab449034a0423a166f413a9b4a4d5041747ed4610b20e111b6",
"reuse_note": "Originally generated for the combined savings/property draft; retained unchanged for the property article when the articles were split."
},
{
"path": "app/public/assets/posts/uk-autumn-budget-2026-trading-allowance/cover.webp",
"prompt": "Use case: stylized-concept.\nAsset type: original editorial cover illustration for PolicyEngine's UK Autumn Budget 2026 article about the trading allowance for small businesses and side income.\nCreate a polished wide 16:9 landscape illustration, intended final size 1600x900. Match a coherent nonprofit policy research illustration series: deep dark teal background, soft subtle teal vignette, pale mint and turquoise objects, clean vector-like shapes rendered as a raster image, restrained dimensional depth, gentle shadows, crisp edges, professional calm neutral tone.\nScene: a small-business desktop still life with two simple unbranded parcels, a tidy calculator, a white business receipt or income ledger with a teal header and grey abstract rows, and a small stack of mint coins. One mint coin bears a clear British pound symbol (£). Convey modest self-employment or side-business receipts and expenses. It must not suggest stock-market trading or cryptocurrency.\nComposition: main objects within the central 65 percent of the canvas, readable at thumbnail size, generous breathing room on every edge, balanced wide layout, a subtle floor line. Avoid tiny details.\nText: only a single £ symbol on one coin; no words, no allowance amounts, no numbers on calculator keys, no labels, no title, no logos, no watermark.\nConstraints: original illustration, no people, no flags, no political symbolism, no charts, no arrows or promises of wealth. The image should look like a refined flat editorial illustration with subtle depth, not a photograph or a glossy toy render.",
"width": 1672,
"height": 941,
"format": "WebP",
"encoding_quality": 85,
"pixels_resized": false,
"bytes": 45038,
"sha256": "67f66a172051edf23372d3df5de577fd3724eed21dbb84036bf5cef106b3a9f0"
}
]
}
30 changes: 30 additions & 0 deletions analysis/uk-budget-2026-income-tax/curve-validation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"range_gbp": [
500,
5000
],
"validation_interval_gbp": 2,
"points_per_series": 2251,
"series": 4,
"liability_checks": 18008,
"interpolation_checks": 9004,
"chart_interval_gbp": 100,
"savings_breakpoints_gbp": [
500,
1000
],
"trading_breakpoints_gbp": [
1000,
1333.3333333333333,
3000,
4000
],
"chart_rows": {
"savings": 46,
"trading": 47
},
"maximum_model_error_gbp": 2.2737367544323206e-13,
"maximum_chart_interpolation_error_gbp": 0.0033000000000242835,
"tolerance_gbp": 0.01,
"method": "All four series checked against pe.uk at every £2; both scenarios compared with independent tax arithmetic; plotted linear interpolation compared with the engine tax changes. The non-integer expense-choice breakpoint is additionally calculated with pe.uk."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"scope": "Synthetic salary-uprating comparison; no population data",
"versions": {
"policyengine": "6.11.1",
"policyengine-uk": "2.151.0",
"policyengine-core": "3.33.3"
},
"year": 2027,
"salary_input_year": 2026,
"salary_growth_basis": "Pinned UK March OBR average earnings index, Jan1 to Jan1, matching calculator earnings_growth",
"growth_factor": 1.0240009985556604,
"inputs": {
"age": 35,
"employment_income": 46080.04493500472,
"property_income": 6000,
"savings_interest_income": 2000
},
"baseline": {
"income_tax": 9014.02,
"savings_income_tax": 630.0,
"savings_allowance": 500.0,
"savings_starter_rate_income": 0.0,
"basic_rate_savings_income": 0.0,
"higher_rate_savings_income": 1500.0,
"add_rate_savings_income": 0.0,
"property_income_tax": 1682.01,
"property_finance_cost_relief": 0.0,
"taxable_property_income": 6000.0,
"trading_allowance_deduction": 0.0,
"taxable_self_employment_income": 0.0,
"national_insurance": 2680.81,
"ni_class_4": 0.0,
"household_benefits": 0.0
},
"reform": {
"income_tax": 9164.02,
"savings_income_tax": 660.0,
"savings_allowance": 500.0,
"savings_starter_rate_income": 0.0,
"basic_rate_savings_income": 0.0,
"higher_rate_savings_income": 1500.0,
"add_rate_savings_income": 0.0,
"property_income_tax": 1802.01,
"property_finance_cost_relief": 0.0,
"taxable_property_income": 6000.0,
"trading_allowance_deduction": 0.0,
"taxable_self_employment_income": 0.0,
"national_insurance": 2680.81,
"ni_class_4": 0.0,
"household_benefits": 0.0
},
"income_tax_change": 150.0,
"reference": "https://github.com/PolicyEngine/uk-autumn-budget-dashboard-2026/pull/292#issuecomment-6473170340"
}
Loading
Loading