Repository navigation
Council tax integration: Nuffield Workstream 2 deliverable tracker #1854
Description
Update, 24 Oct 2026: #1855 and #1864 merged on 22 Oct 2026, so gross liability and the statutory discounts are now computed (boxes ticked below). council_tax is still the dataset input, so CTR results have not moved. PolicyEngine/policyengine-uk-data#482 and #484 and TheAxiomFoundation/rulespec-uk#346 are still open.
Tracking issue for the council tax workstream committed in the Nuffield R&D 2025 application (Workstream 2, "Council Tax Integration", £32,000 / 4 person-months, Year 1 Q1 kickoff).
Application text: https://policyengine.github.io/nuffield-rda-2025
What we promised
We will add council tax to microsimulation, enabling combined local and national tax burden analysis. This addresses a significant gap—existing models omit local taxation despite £40bn annual revenue.
Method committed (test-driven, citing the childcare precedent):
- Implement council tax bands and local authority rates from MHCLG data
- Validation test cases
- Compare against administrative totals
- Validate distributional impacts
Deliverables committed:
- Council tax by band and local authority
- National model integration
- Validation report
- Policy examples
Current state
More exists than the deliverable list suggests — the data layer is substantially built, the liability calculation is not.
Already in place:
policyengine-uk-data:policyengine_uk_data/storage/la_council_tax.csv— 360 LAs (England, Scotland, Wales) withband_d_amount, VOA dwelling counts for bands A–I, and net council tax requirement.policyengine-uk-data: band assignment to households indatasets/enhanced_cps.py(_assign_council_tax_bands), usingstorage/council_tax_bands_2024.csvregional shares.policyengine-uk-data: calibration targetsons/council_tax_band_d/{code}andvoa/council_tax/{code}/{band}emitted fromtargets/sources/la_council_tax.py.policyengine-uk: the full Council Tax Reduction stack undervariables/gov/local_authorities/council_tax_reduction/, with bespoke schemes for Kingston upon Thames, Merton, Newham, Oxford and Westminster, plus England pensioner / Scotland / Wales parameters.TheAxiomFoundation/rulespec-uk: the national England pension-age CTR scheme (SI 2012/2885) and 100 local authority CTR schemes encoded with proof citations, plus a 297-row LA registry.
Not in place:
- Council tax liability is not computed anywhere.
variables/input/consumption/property/council_tax.pyis an input variable whose own docstring says it is "supplied by the household dataset rather than recomputed from local authority council tax schedules".council_tax_bandis likewise an input defaulting to Band D. - No statutory band-ratio parameters (A=6/9 … H=18/9 relative to Band D).
- No
council_tax_band_d_amountvariable in policyengine-uk, despite the data repo emitting a calibration target against that name (separate issue to follow). - No discounts, exemptions or premiums: single-person 25%, student/SMI exemptions, empty-home and second-home premiums.
- No parish/precept handling.
- Liability sourcing is England-only — Wales (StatsWales) and Scotland (Scottish Government) band amounts are not sourced.
- No validation against the MHCLG administrative total.
Work items
Deliverable 1 — council tax by band and local authority
- Refresh
la_council_tax.csvto MHCLG 2026-27 and extend Band D to all eight bands (Table 9 ofTables_1-9_2026-27.odsgives ONS code + Band A–H for 296 English authorities) - Alias map for the 12 authorities whose MHCLG name does not exactly match the
LocalAuthorityenum: Bristol, Cumberland, Durham, Herefordshire, Kings Lynn and West Norfolk, Kingston upon Hull, North Northamptonshire, North Yorkshire, Somerset, St Helens, West Northamptonshire, Westmorland and Furness - Source Wales band amounts (StatsWales). Done in Compute gross council tax from LA Band D amounts and statutory band ratios #1855 as Band D amounts in
gov.local_authorities.council_tax.band_d.amounts(gov.wales tables), other bands via the statutory ratios - Source Scotland band amounts (Scottish Government council tax datasets). Done in Compute gross council tax from LA Band D amounts and statutory band ratios #1855 the same way (gov.scot Band D tables)
Deliverable 2 — national model integration
-
council_tax_band_d_amountvariable (Compute gross council tax from LA Band D amounts and statutory band ratios #1855) - Statutory band-ratio parameters, including Band I for Wales (Compute gross council tax from LA Band D amounts and statutory band ratios #1855;
band_ratios/england.yaml,scotland.yaml,wales.yamlwith I = 7/3) - Computed gross liability = Band D amount × band ratio (Compute gross council tax from LA Band D amounts and statutory band ratios #1855,
simulated_council_tax) - Single-person discount (25%) (Add statutory council tax discounts across Great Britain (LGFA 1992 ss.11 and 79; Welsh Regulations 2026) #1864,
council_tax_discount_rateandsimulated_council_tax_less_discounts, across GB). Disregarded persons are not modelled yet, so the discount is understated where a household has disregarded adults - Exemptions: students, severe mental impairment, Class A–W exempt dwellings
- Empty-home and second-home premiums
- Decide and document the relationship between computed liability and the existing
council_taxinput, including the effect on downstream CTR results
Deliverable 3 — validation report
- Aggregate computed liability vs MHCLG administrative total (~£40bn England)
- Per-LA comparison against
total_council_tax_net - Band distribution vs VOA dwelling counts
- Distributional validation (decile incidence) against an external benchmark
- Write up as a published validation note
Deliverable 4 — policy examples
- Band revaluation scenario
- Proportional property tax / council tax replacement
- Single-person discount reform
- Band D rate change by LA
Reference data
- MHCLG council tax levels 2026-27: https://www.gov.uk/government/statistics/council-tax-levels-set-by-local-authorities-in-england-2026-to-2027
- MHCLG council tax statistics collection: https://www.gov.uk/government/collections/council-tax-statistics
- Statutory band proportions: Local Government Finance Act 1992 s.5
Notes
Band amounts in MHCLG Table 9 are area figures — they include county, police, fire and parish precepts, not just the billing authority's own requirement. Any comparison against a billing-authority-only total needs to account for that.
Activity
vahid-ahmadi commentedon Sep 15, 2026
Statutory findings from the Axiom side — these change the Wales items above
Investigated in parallel via TheAxiomFoundation/rulespec-uk (see TheAxiomFoundation/rulespec-uk#344). Three corrections to the scope as originally written in this issue:
1. Band I for Wales comes from LGFA 1992 s.5(1A), not separate Welsh legislation. s.5(1) prints the England proportions as
6 : 7 : 8 : 9 : 11 : 13 : 15 : 18for bands A–H. s.5(1A) substitutes, for Wales and for financial years beginning on or after 1 April 2005,6 : 7 : 8 : 9 : 11 : 13 : 15 : 18 : 21— so Band I = 21/9. Both sets are printed in the Act as ratios relative to each other; the "relative to Band D" form (A = 6/9 … H = 18/9) is a derivation, not Act text.2. The operative provision for gross liability is s.10 (Basic amounts payable), which the original scope above omitted. s.5 gives the proportions; s.10 gives the amount payable.
3. s.12 was omitted with effect from 1 April 2026 by the Local Government Finance (Wales) Act 2024 (asc 6), ss.18(6) and 23(7). Anything modelling Welsh discounts needs to account for this — and 2026-27 is the first year affected, which is the year the data refresh targets.
Further detail relevant to the discount/premium work item:
Schedule 1 paragraph numbers for the student and severe-mental-impairment disregards are not stated here deliberately — the headings were confirmed to exist but the numbering was not verified. To be checked against the Act before encoding.
Axiom will not be the venue for liability
For the record, since it affects where this work lands: Axiom's omission of council tax liability is deliberate, not a gap. 82 of its 100 encoded CTR modules carry an explicit
module.deferred_outputsblock, several naming liability deferral directly (Sandwell: "council-tax charging, statutory discounts, joint-liability apportionment, and calendar-day calculation are future outputs"). 68 of 100 use a locally-prefixed liability variable and 30 declare the slot in a module-levelinputs:block. Axiom encodes the reduction and expects liability injected by the caller.So the liability modelling committed to Nuffield belongs here, in policyengine-uk, not upstream in Axiom. Issue #344 asks them whether they would want an LGFA 1992 Part I charging encoding contributed; that is a separate question from this deliverable.
vahid-ahmadi commentedon Sep 18, 2026
Microcosm compatibility — constraints on everything in this tracker
PolicyEngine/microcosm consumes both policyengine-uk and policyengine-uk-data, and maintains a formal parity register against uk-data's target inventory. It already has a council tax surface, and in places a richer one than uk-data. Anything built for this deliverable has to hold to that contract, so recording the constraints here.
1. Band amounts are rates. They must never be wired as additive loss-matrix targets.
packages/microcosm-build/src/microcosm/build/uk/uk_data_target_parity.jsoncarrieslocal_council_tax_band_d_rateat statusreviewed_exclusion, classificationnon_linear: "Band D currency amounts are per-rate, not additive household controls", withverdict_basis"Keep excluded until a rate-aware non-linear objective exists". Microcosm reached this independently of PolicyEngine/policyengine-uk-data#483.This binds the eight new
band_A_amount..band_H_amountcolumns from PolicyEngine/policyengine-uk-data#482 as well — they are amounts, therefore rates, therefore not additive targets. #482 emits no targets from them, which is correct and should stay that way.2. Band counts are the surface that legitimately calibrates.
local_council_tax_band_countsisported_local_declaredand actively bound — Microcosm'scouncil_tax/band_a..icontract rows "bind 2,511 authority cells on the taxbase basis with the 296 English band-H cells and Shetland's band-H cell signed deferred (microcosm#929)". Sovoa/council_tax/{code}/{band}stays. Counts are additive; amounts are not.3. Net council tax at LA grain is blocked upstream, not just here.
local_council_tax_netsits atblocked_source: "The pinned feed has no comparable 2025 local-authority council-tax net series across the 361-area roster", with an explicit fence against combining unlike country totals, 2026 Welsh budgets, or gross dwelling stock. So retargeting ontototal_council_tax_netis not an available escape hatch for #483.4. New policyengine-uk variables must be engine-computed, not supplied inputs.
packages/microcosm-frame/src/microcosm/frame/adapters/policyengine_uk.pyclassifies variables via_is_engine_computed, which tests foradds/subtracts/formula/formulas. A new variable with a formula is adapter-safe. One that has to be supplied as an input column is not, and the adapter has precedent for requiring explicit input handling (seevalidate_uc_claimant_input).This is a live consideration for #1855:
council_tax_band_d_amountreads an LA-keyed parameter rather than being a dataset input, which keeps it computed and therefore adapter-safe. It is also another argument against resolving #1855 by making liability a supplied input.5. There is an existing Axiom adapter too.
adapters/axiom.pysits alongside the policyengine ones, so Microcosm is the point where the rulespec-uk charging encoding (TheAxiomFoundation/rulespec-uk#346) and the policyengine implementation would meet. Worth keeping the two consistent in naming and entity level rather than letting them diverge.Action: @juaristi22 added as reviewer on #482, #1855 and TheAxiomFoundation/rulespec-uk#346, and on the two PRs opened against #483 and the discounts work.
🤖 Generated with Claude Code
vahid-ahmadi commentedon Sep 21, 2026
Council tax workstream — status for review
@MaxGhenis @juaristi22 — everything open on the Nuffield WS2 council tax line, in one place. Four PRs are reviewable; two items need a decision, one needs an action only Max can take.
Reviewable now
CT-CHGworklist entries (ss.5, 10, 11, 11A, 11B)#482 is purely additive — 361 rows unchanged, 16→24 columns, and all 294 directly-matching England rows reconcile to the MHCLG source at £0.00. All 296 authorities obey the statutory proportions (worst deviation £0.0044, per-band rounding). Note
band_d_amountwas already on 2026-27 figures, so this adds the other seven bands rather than refreshing anything.#484 resolves #483. María — your parity register already answered this:
local_council_tax_band_d_rateis areviewed_exclusion, classificationnon_linear, "Band D currency amounts are per-rate, not additive household controls". So the fix is to drop the target, not to add a mean-returning compute route — a mean would stop the number being wrong but would still bind a rate into an additive objective, which is the thing the fence exists to prevent. Band counts (voa/council_tax/{code}/{band}, 2,563) are untouched and still bound. Retargeting ontototal_council_tax_netwas the other option and is closed off too, sincelocal_council_tax_netis atblocked_sourceon your side. Tell me if dropping rather than fencing-in-place is the wrong shape for your register.#1864 encodes s.11(1)/(2)/(3) with the 25% as the parameter and the 50% derived as twice it, since "twice the appropriate percentage" is what the Act prints. Microcosm-safe: both new variables define a
formula, so_is_engine_computedclassifies them as engine-computed and neither can be requested as a supplied input column.Decision needed — #1855
Computed liability gives England £61.21bn against the ~£40bn we cited to Nuffield. Most of that is an artefact, and I think it's a design question rather than a bug: the variable looks up Band D via
household("local_authority"), but no dataset builder populateslocal_authority, so every household decodes to the enum default (Maidstone). LA analysis in uk-data runs through per-LA reweighting (local_authority_weights.h5), not per-household tagging — so a household-level enum lookup may be the wrong mechanism entirely.This gates the validation report and policy examples, so I'd rather not build further on it until it's ruled on.
council_taxitself is untouched — still the input, so CTR results don't move.Action only Max can take — TheAxiomFoundation/rulespec-uk#346
Blocked on corpus ingest for ss.5, 10, 11, 11A, 11B. Write access to axiom-corpus doesn't carry the ed25519 ingest key: its Actions secrets hold
AXIOM_CORPUS_RELEASE_SIGNING_KEYand no ingest private key, the only ingest key in variables is the public verification one, and no workflow signs a manifest. Detail and the three options are on #344.Two open questions on #344
extract-uk-legislationcalls yourself, or is there a contributor path I've missed?policyengine-uk-rustdoes have the band multipliers and the 25% discount, but on unmerged branches (vahid/council-taxand ten others), notmain, wherecouncil_taxis still an FRS input. Build the axiom-oracles mapping against that branch, wait for it to land, or has this moved to 10ds-microsim?Also filed
data/councils/registry.csvdrift: 98 of 99 encoded councils still saypending, and only 5 of the 99 have ascheme_url. The roster is correct and the layout test only uses it as an allowlist, so nothing catches this. Asked whether those columns are still meant to be live before rewriting 98 rows.Two things I'd like a steer on
Double-discount risk. FRS-reported council tax is generally the billed amount, already net of any single-person discount, while uk-data documents the input as "gross liability before CTR" — silent on statutory discounts. If that reading is right, applying #1864's discount to the FRS figure would discount twice. This is my inference, not something the repo asserts, and one of you will know outright. It matters for how #1855 and #1864 compose.
Naming alignment. Microcosm has an
adapters/axiom.pyalongside the PolicyEngine ones, so Microcosm is where the rulespec charging encoding and the PolicyEngine implementation actually meet. Worth agreeing variable naming and entity levels now, while both are unbuilt, rather than reconciling later.Still open against the Nuffield commitments
Schedule 1 disregards, s.11A determinations, s.11B/11C premiums, exemptions, Wales and Scotland liability, the validation report, and policy examples. All itemised in #1854.
Three statutory findings that moved scope along the way: Wales Band I comes from LGFA 1992 s.5(1A) itself, not separate Welsh legislation; s.10 is the operative provision for liability and I'd originally missed it; and s.12 was omitted with effect 1 April 2026 by the Local Government Finance (Wales) Act 2024, which matters because 2026-27 is the year our Band D figures come from. Scotland is also not on flat ninths — SSI 2016/123 raised E–H to 473/360, 585/360, 705/360 and 882/360.
🤖 Generated with Claude Code
vahid-ahmadi commentedon Sep 26, 2026
Correction: I cited the wrong instrument for the Scottish band proportions, in this thread and in several others.
I wrote that SSI 2016/123 raised the Scottish E–H proportions. That is wrong. SSI 2016/123 is the Local Authority (Capital Finance and Accounting) (Scotland) Regulations 2016 and has nothing to do with council tax.
The correct instrument is SSI 2016/368 — the Council Tax (Substitution of Proportion) (Scotland) Order 2016. Its article 2 substituted the proportions
into LGFA 1992 s.74(1) for financial years beginning on or after 1 April 2017.
Two things that follow, beyond the reference itself:
Caught while addressing review feedback on #1855, where the same wrong citation had been carried into the parameter file. Corrected there, and in the
bulk/worklist.yamlnote on #346 (commited3830c).Apologies for the noise — a wrong statutory citation is worth more than a footnote in this repo.
🤖 Generated with Claude Code
vahid-ahmadi commentedon Oct 24, 2026
Status, 24 Oct 2026 (main at 4ed874f):
council_tax_band_d_amount(Band D amounts for England, Wales and Scotland, 2025-26 and 2026-27), band ratios for all three nations including Welsh Band I, andsimulated_council_tax.council_tax_discount_rateandsimulated_council_tax_less_discounts(LGFA 1992 ss.11 and 79, and the Welsh 2026 Regulations).council_taxinput: documented but not decided.council_taxis still the input.LocalAuthorityenum.council_tax_band_d_amountneeds a dataset that supplieslocal_authority. The Enhanced FRS does not, so every household defaults to Maidstone. Validation therefore needs Microcosm UK.🤖 Generated with Claude Code