Repository navigation
Description
Summary
shareholding, corporate_land_value and consumption_shareholding each divide a household's key by the key's weighted total over the households in the simulation. So a household's value depends on which other households are simulated. Only a run over the whole UK at UK weights gets it right.
The most visible case is a bug. Since #1296 (August 2025), a household situation with any corporate wealth gets shareholding 1, and since #1824 (2.92.0) so does one with any private pension wealth. The household then pays all UK business rates (£36.20bn in 2026-27) and all corporate SDLT in England and Northern Ireland (£4.57bn). The household below ends up with household_net_income of −£40.77bn.
policyengine-api and policyengine.py's household calculator build households this way. The app's household builder offers private_pension_wealth under Assets.
What each formula does:
shareholdingis a household's share ofcorporate_sector_wealth.business_ratesandcorporate_sdltmultiply it by UK receipts. Both levels are inhousehold_tax, and so inhousehold_net_income;gov_taxlists them too.- Under a reform,
corporate_incident_tax_revenue_changemultiplies it by the reform's revenue change.
corporate_land_valueis the same share times the corporate land parameter (£2,058.6bn, its 2024 value held flat).- The land value tax
LVTreads it directly at its corporate rate, and throughland_valueat its full rate. - All LVT rates are 0 at current law.
hbai_household_net_incomesubtractsLVT, so under an LVT reform the share reaches HBAI incomes too.
- The land value tax
consumption_shareholdingis a household's share of consumption. No formula reads it.consumer_incident_tax_revenue_changeandemployer_ni_response_consumer_incidencecompute their own copies of the share.
The same thing happens in any simulation of part of the UK: a filtered region, a set of axes, an extract, a subsample, or Microcosm UK's per-clone engine blocks.
Separately, three modelling choices are open: the key, the incidence, and where the levels sit. These are not bugs.
Each proposal below can land as its own PR:
- Household situations stop using the weighted total. This is the bug fix.
- A national total of each key that the data can carry, so any part of the UK gets its own share.
- A decision on where business rates and corporate SDLT sit.
- A review of the key.
- Remove
consumption_shareholding, or have the formulas that copy it read it.
File and line references are to policyengine-uk 2.174.1. On main (2.176.1) the formulas are unchanged, and household_tax takes its terms from programs.yaml (#2809).
What happens
policyengine_uk.Simulation(situation=...) gives the household the default household_weight of 1. Here is a household with private pension wealth (the comments are the outputs on 2.174.1):
from policyengine_uk import Simulation
situation = {
'people': {'adult': {'age': {2026: 45}, 'employment_income': {2026: 40_000}}},
'benunits': {'bu': {'members': ['adult']}},
'households': {'hh': {'members': ['adult'], 'region': {2026: 'LONDON'},
'private_pension_wealth': {2026: 50_000}}},
}
sim = Simulation(situation=situation)
print(sim.calculate('shareholding', 2026)) # [1.]
print(sim.calculate('business_rates', 2026)) # [3.620134e+10]
print(sim.calculate('household_net_income', 2026)) # [-4.0774574e+10]
situation['axes'] = [[{'name': 'employment_income', 'count': 5,
'min': 0, 'max': 80_000, 'period': 2026}]]
print(Simulation(situation=situation).calculate('shareholding', 2026)) # [0.2 0.2 0.2 0.2 0.2]| variable | 2026 |
|---|---|
shareholding |
1 |
business_rates |
£36.20bn |
corporate_sdlt |
£4.57bn |
corporate_land_value |
£2,058.6bn |
household_net_income |
−£40.77bn |
hbai_household_net_income |
£32,420 |
- Axes. The axis copies share the totals. Five copies each get
shareholding0.2 and £7.24bn of business rates, so the result depends on the number of axis points. - Reforms. The household takes the whole change.
- With
gov.contrib.policyengine.budget.corporate_incident_tax_changeat 1 (£1bn), itscorporate_incident_tax_revenue_changeis £1bn. - Under a 1% land value tax (
gov.contrib.ubi_center.land_value_tax.rate), itsLVTis £20.59bn and itshbai_household_net_incomefalls from £32,420 to 0.
- With
- Zero weight. Setting
household_weightto 0 shows the fallback that proposal 1 builds on: the key over household financial net worth. It charges this household about £383 of business rates and corporate SDLT. - Who builds households this way.
- policyengine-api (
policyengine_api/country.py) and policyengine.py's household calculator (src/policyengine/tax_benefit_models/uk/household.py) both build throughpolicyengine_uk.Simulation(situation=...). - policyengine-api runs policyengine-uk 2.151.0, which has the same code.
- PolicyEngine/policyengine-app-v2's household builder (
app/src/libs/flagship/householdVariableGroups.ts) hidescorporate_wealthas a dataset-only input, but offersprivate_pension_wealthunder Assets. - Not run end to end in the app.
- policyengine-api (
Expected: a household's shareholding does not depend on which other households are simulated, or on its own weight.
Any simulation of part of the UK hands the UK totals to whichever of its households hold the key:
- Regions filtered from a UK dataset. Nations come from the national data; constituencies and local authorities come from the local-area release. This is Scoped UK runs give the region UK-wide business rates and region-relative ranks policyengine.py#567.
- Runs that replace the weights with an area's weights, such as policyengine.py's legacy
WeightReplacementStrategy. The area's households carry the whole total. filter_dataset(data/filter_dataset.py). An extracted household keeps its weight w, so on its own itsshareholdingis 1/w. The extract already carriesattends_private_schoolandmonths_since_last_birthdayfrom the whole population (lines 47-57), but not these shares.- Microcosm UK's per-clone engine blocks.
- They keep the UK totals by rescaling weights. But once clones differ (UK graph: move geography assignment ahead of enrichment (geography-first reordering) microcosm#931), each block's share of a total follows its weight, not its key.
- Make the dense role run on a current spine: identity branch, scratch aliases, per-block national problem, compiled-row axis, holdout shape, engine blocks that represent the pool microcosm#1115 already accepts a block run only when every block carries the same weighted key.
- Microcosm will correct for this in its own build. A total carried by the data (proposal 2) would make that correction unnecessary.
Cause, read in the code
- The weighted branch.
variables/household/wealth/shareholding.py:12-23takes it whenhousehold.simulation.dataset is not None.- Add OBR labour supply response elasticities #1296 made
build_from_situationstore a dataset for every situation (simulation.py:1182-1202). household_weightdefaults to 1 (variables/household/demographic/household_weight.py:11).
- Add OBR labour supply response elasticities #1296 made
- Other formulas.
variables/household/wealth/corporate_land_value.py:13-27has no such check.variables/household/consumption/consumption_share.py:12-19andvariables/contrib/policyengine/consumer_incident_tax_revenue_change.py:11-22use the same gate asshareholding.- So do
pre_budget_change_ons_household_income_decileand the NHS, education and other public spending budget changes, so situations take their data branch too.
- Tests.
- Adjusting carbon tax incidence changes the budgetary impact of a carbon tax #774's closing comment (April 2026) treats bare situations as taking the fallback, and suggests a narrower issue if that path matters. Add OBR labour supply response elasticities #1296 had already sent situations to the weighted branch eight months earlier.
- Guard weighted incidence calculations against zero totals #2448 builds its fallback test through policyengine-core for that reason (
tests/test_weighted_incidence.py:63-64). - The YAML tests and
tests/test_fiscal_partition.pysetshareholdingdirectly. The latter says why (tests/test_fiscal_partition.py:230-232): derived from wealth, it would split all UK corporate taxes across the test's few households. - Two tests rely on the weighted branch in situations, treating a two-household situation as the whole UK:
tests/test_corporate_land_value.py:5-43(Improve corporate land allocation #1583);- check 5 of
tests/test_sdlt_counted_once_properties.py(lines 176-180).
- No test checks a one-household situation.
- The fallback. It divides by household financial net worth at its 2021 value.
parameters/household/wealth/national_balance_sheet.yamldeclares the uprating on the parent node, and it does not reachfinancial_net_worth. Uprate benefits by the previous September's CPI #2557 noted this and kept it as an exception in its uprating test.
Open modelling choices
These are not bugs. Proposals 3 and 4 ask for a decision on each.
The weighted total keeps the allocations summing to the receipts on any full dataset. #774's closing comment credits #840 with that. What the formulas spread, and onto whom, are choices the code calls modelling conventions (parameters/gov/hmrc/business_rates/statistics.yaml:17-20; parameters/gov/hmrc/stamp_duty/statistics.yaml:21-24).
- The key.
corporate_sector_wealthaddsprivate_pension_wealthtocorporate_wealth, because pension funds hold corporate equity (Add private_pension_wealth as an explicit capital disregard; corporate_wealth keeps the share-like holdings #1824).corporate_sector_wealth.py:6-16calls the addition a compatibility proxy.private_pension_wealthincludes retained defined benefit rights and pensions in payment, valued at the SCAPE rate (variables/input/private_pension_wealth.py:6-31). Defined benefit rights are promised amounts that do not move with company returns, and most public service schemes are unfunded.- There is no overseas share. Account for foreign ownership of corporations in land value tax distribution #224 (2021) kept it out so that the accounts add up. Overseas investors held 58.8% of UK quoted shares at the end of 2024 (ONS, Ownership of UK quoted shares: 2024, 29 January 2026).
- The rating lists include public bodies, charities and unincorporated businesses. Corporate SDLT payers include partnerships and collective investment schemes.
- The incidence.
- The ONS's Effects of taxes and benefits counts rates on commercial and industrial property, and stamp duties, among intermediate taxes. It assumes they fall on consumers, allocates them through household spending, and deducts them in post-tax income, not disposable income (technical report, financial year ending 2019, section 7).
- HM Treasury's distributional analysis excludes business taxes (Impact on households: distributional analysis to accompany Budget 2026, paragraph 1.2).
- Bond, Denny, Hall and McCluskey (Fiscal Studies, 1996) find that much of the burden of business rates shifts to property owners through lower rents in the long run, while occupiers bear more of it in the short run.
- The placement.
- The levels of business rates and corporate SDLT are in
household_tax, and so inhousehold_net_income. - VAT, and since Charge VAT on private school fees at current law #2319 private school VAT, enter
household_taxonly as changes. The employer NICs level is only ingov_tax(data/fiscal_partition.yaml:797-804, 811-817). - Fuel, alcohol, tobacco and gambling duties enter
household_taxas levels. hbai_household_net_incomealready leaves business rates and corporate SDLT out (variables/household/income/hbai_excluded_income.py).
- The levels of business rates and corporate SDLT are in
- Corporate land. Ownership of corporate equity is a reasonable first attribution for a tax on corporate land. Its caveats (overseas owners, housing associations, public corporations) are scoped as D7 in Project scope: land value tax results for every constituency uk-land-value-tax#20.
History
The denominator.
- December 2021.
- e89fd37 ("Ensure land value calculation works when individual") moved land value to parameter totals.
- 7f98371, 23 minutes later in the same PR (Add Stamp Duty #398), went back to weighted totals, with a parameter fallback when the total is zero.
- 51757e8 (Add Land Transaction Tax, Land and Buildings Transaction Tax and business rates #402), the next day, added
shareholdingthe same way, falling back to household financial net worth.
- April 2022: regions.
- Calculate land/carbon using parameters, not in-model totals #578 moved land value and carbon to parameter totals "so that when we filter to regions, we don't retain the same land value".
- 8223275 (in Begin refactoring and adding statistics #597, "Fix business rates when countries are filtered") did the same for
shareholdinga week later.
- April 2024. f813a36 (OBR March EFO update #840) went back to the weighted total for
shareholding.- OBR March EFO update #840 is an OBR forecast update, and its description does not mention the change.
- Adjusting carbon tax incidence changes the budgetary impact of a carbon tax #774's closing comment credits it with making the weighted shares sum to one, so that a carbon tax's revenue stopped moving with its incidence split.
- Assorted fixes #845 then guarded a zero total (Original FRS simulations error due to no corporate wealth #843).
- 2026.
- Improve corporate land allocation #1583 (2.79.2) moved
corporate_land_valueback to the weighted total, because its parameter total of corporate wealth was stale. It does not discuss Calculate land/carbon using parameters, not in-model totals #578's reason. - Add private_pension_wealth as an explicit capital disregard; corporate_wealth keeps the share-like holdings #1824 (2.92.0) moved both keys to
corporate_sector_wealth. - Guard weighted incidence calculations against zero totals #2448 guards a zero weighted total.
- Impute UC deductions in constituency and local-authority runs #1905's caveats report the constituency case.
- Improve corporate land allocation #1583 (2.79.2) moved
- So each denominator has a known failure. A parameter total does not match the data (Adjusting carbon tax incidence changes the budgetary impact of a carbon tax #774, Improve corporate land allocation #1583). A weighted total gives any part of the UK the UK totals (Calculate land/carbon using parameters, not in-model totals #578, 8223275, Scoped UK runs give the region UK-wide business rates and region-relative ranks policyengine.py#567, this issue).
The placement.
- Add business rates to income #413 (December 2021) put the business rates level in
household_tax. - f5a4b6b (Improve calibration and imputations #559, April 2022, "Improve calibration and imputations") kept only the change from baseline for business rates, corporate SDLT, and SDLT, LTT and LBTT.
- 9ecc9dc (Migrate to policyengine-uk-data #946, 2.0.0, September 2024, the move to policyengine-uk-data) restored the levels.
- Count corporate SDLT once and let SDLT abolition remove all of it #2235 (October 2026) counts corporate SDLT once.
- Update corporate SDLT and business rates statistics and project them with OBR receipts #2322 (October 2026) wrote the "modelling convention" text and states the identity.
Proposals
-
Situations (the bug; can land on its own).
- Take the weighted branch only when
built_from_data(simulation)(utils/data_source.py), asattends_private_schooldoes. Givecorporate_land_valuethe same fallback. - Base the fallback on a parameter holding the key's national total, uprated with the key, in place of household financial net worth at its 2021 value. That also removes Uprate benefits by the previous September's CPI #2557's exception.
- The other choice is 0 in situations, which is what
attends_private_schoolreturns. The household calculator would then show no corporate incidence. - A multi-household situation with weights set would no longer act as a population.
tests/test_corporate_land_value.py:5-43and check 5 oftests/test_sdlt_counted_once_properties.pywould build small datasets instead, astests/test_weighted_incidence.pydoes. - Test through
policyengine_uk.Simulation(situation=...), with and without axes: a household'sshareholdingdoes not depend on its own weight or on the number of axis points. - Nothing changes on data.
- Take the weighted branch only when
-
A national total the data can carry.
- Add a household input that holds the national weighted total of each key, the same on every row:
corporate_sector_wealth, andconsumptionifconsumption_shareholdingstays. The formulas divide by it when it is supplied, and keep today's weighted total otherwise. - Uprating:
- both parts of
corporate_sector_wealthuprate with OBR GDP per capita, andhousehold_weightwith ONS population; - uprating the input by the product of the two keeps it equal to the projected weighted total;
- a variable takes one uprating index today, so this needs a combined index;
- a builder that sets weights year by year writes the input year by year.
- both parts of
- As a column it survives row filters,
filter_dataset, household subsets, subsamples and weight replacement. Each part of the UK then gets its own share of the UK total, and the full dataset keeps the identity OBR March EFO update #840 was after. - Microcosm UK would write it at its release weights, and at its measurement weights inside the build. policyengine-uk-data would need to write it too, for Scoped UK runs give the region UK-wide business rates and region-relative ranks policyengine.py#567's regional runs.
- This is option 2 of Scoped UK runs give the region UK-wide business rates and region-relative ranks policyengine.py#567, without carrying formula values. It is the same route as the national income rank that
attends_private_schoolwaits for (attends_private_school.py:72-78).
- Add a household input that holds the national weighted total of each key, the same on every row:
-
Where business rates and corporate SDLT sit. The options:
- keep the levels, and document the incidence;
- count only the change from baseline, as for VAT and, since Charge VAT on private school fees at current law #2319, private school VAT. This was the rule for business rates and corporate SDLT from April 2022 to September 2024;
- carry them in a separate income measure.
The first two both keep the revenue identity in
docs/book/usage/simulations.mdfor reforms; they differ only in the baseline level ofhousehold_net_income. The third takes reforms to these taxes out ofhousehold_net_income. -
The key. Decide it alongside D7 in Project scope: land value tax results for every constituency uk-land-value-tax#20, which covers overseas owners, housing associations, public corporations and corporate SDLT. Add the defined benefit part of
private_pension_wealthand the ratepayers outside the corporate sector. That project leaves business rates out of scope, so business rates need their own decision. -
consumption_shareholding. No formula reads it in 2.174.1, nor in the commit that added it (Add employer NI incidence #961). Remove it, or haveconsumer_incident_tax_revenue_changeandemployer_ni_response_consumer_incidenceread it in place of their own copies of the share.
Related
- Scoped UK runs give the region UK-wide business rates and region-relative ranks policyengine.py#567: regional runs, the same cause.
- Adjusting carbon tax incidence changes the budgetary impact of a carbon tax #774: the revenue identity behind the weighted total.
- Original FRS simulations error due to no corporate wealth #843, Wealth and consumption shares divide by a weighted total that can be zero #2296 and Guard weighted incidence calculations against zero totals #2448: zero weighted totals only.
- Charge VAT on private school fees at current law #2319: private school VAT rejected a share measured on each simulation's population, partly because a household calculator would measure its own charge against itself.
- Move the engine's random draws into the data build #2874 and Read stored draws for UC, student loans and PIP #2877: the data build stores the engine's random draws. Proposal 2 takes the same route for national totals.
- Roadmap: complete, interaction-aware UK tax–benefit coverage (2000-onward) #1775 (coverage roadmap): its business rates item asks for reliefs and a rateable-value basis.
- Compare property allowance routes on only the households with a choice #2732:
household_subsetandWHOLE_POPULATION_VARIABLES.- The property allowance election never works these formulas out (
utils/household_subset.py:28-29). - The Universal Credit deductions subset from Keep Tax-Free Childcare over a smaller UC award, and take no deductions from awards only a reform creates #2754 is not covered by that comment or its test.
- The property allowance election never works these formulas out (
Duplicate check
On 6 November 2026 I searched open and closed issues and PRs for shareholding, business rates, corporate SDLT, corporate land value and household situations, in policyengine-uk, policyengine.py, policyengine-uk-data, policyengine-api and policyengine-app-v2, and pe-uk's changelog.
- Nothing tracks the situation case.
- Scoped UK runs give the region UK-wide business rates and region-relative ranks policyengine.py#567 tracks regional runs.
- Calculate land/carbon using parameters, not in-model totals #578, Adjusting carbon tax incidence changes the budgetary impact of a carbon tax #774, Corporate SDLT is counted twice in household and government tax totals #2159, Wealth and consumption shares divide by a weighted total that can be zero #2296 and Corporate SDLT and business rates statistics are stale and held flat #2320 are related and closed.
🤖 Generated with Claude Code
Activity
vahid-ahmadi commentedon Nov 9, 2026
Review of the issue as of 9 November 2026, checked against policyengine-uk main e050200 (2.176.1). I reran the reproducer, the axes, zero-weight, LVT and corporate-incident cases in a fresh install, read each cited file and line, and spot-checked the history.
The reproducer gives the same figures on main.
shareholdingis 1,business_rates£36.20bn,corporate_sdlt£4.57bn,household_net_income−£40.77bn andhbai_household_net_income£32,420. Five axis points give 0.2 each, and eleven give 1/11 each. At zero weight the household pays £339.78 of business rates and £42.92 of corporate SDLT, £383 in all. Under the 1% LVT,LVTis £20.59bn and HBAI income is 0. The corporate incident change is £1bn. It is live too: the same household sent to api.policyengine.org/uk/calculate today (2.151.0) returnsshareholding1,business_rates£31.73bn andhousehold_net_income−£34.86bn.Should
Proposal 1 should cover every formula with this dependence, not only the two keys.
WHOLE_POPULATION_VARIABLESinutils/household_subset.py:39-61already lists them. Three cases the proposals leave unfixed:employer_ni_response_capital_incidenceandemployer_ni_response_consumer_incidence. Both arehousehold_taxterms (programs.yaml:1169-1170). Both divide by the simulation's own weighted totals of the employer cost change and ofcorporate_sector_wealthorconsumption. Their guard at line 17 of each,if not hasattr(person.simulation, "dataset"), is meant to return 0 "in single-household simulations". It never fires, becauseSimulationalways has the attribute. Take the household in the issue, withgov.contrib.policyengine.employer_ni.employee_incidenceat 0 and the employer rate at 25%. It gets £1,750 of capital incidence, which is half of its own £3,500 rise in employer cost. Given £20,000 ofconsumption, it also gets £1,750 of consumer incidence. Over five axis points, each copy gets £1,800 of capital incidence, which is half of the copies' mean rise. Proposal 5's second option would not fix the consumer side. Readingconsumption_shareholdingchanges only the share, andamount_paid_by_employers(line 25) still sums the simulation's own cost change.carbon_tax. Lines 16-21 multiplyshareholdingby the simulation's weighted total ofcarbon_consumption, with no gate. Take 10 tonnes at £100 a tonne, withconsumer_incidence0. The household pays £1,000, because its own emissions stand in for the UK total. At zero weight it pays £0, because the weighted emissions total is then 0. If onlyshareholdingwere fixed, the corporate part for a weight-1 household would become its own emissions times a very small national share. So this formula needs a national emissions total on the situation path too.nhs_budget_change,education_budget_change,other_public_spending_budget_changeandpre_budget_change_ons_household_income_decile, but no proposal changes them. Each already has a situation branch that the dataset gate skips: fixed decile bounds atpre_budget_change_ons_household_income_decile.py:21-31, and 2.8m households per decile atnhs_budget_change.py:37(education line 38, other spending line 39).gov.contrib.policyengine.budget.nhsat 1 (£1bn), the household without pension wealth ranks in decile 10 against itself and gets £70m.Suggested fix: in the same PR, gate each weighted branch in that set on
built_from_data. Add one test that runs each of them throughpolicyengine_uk.Simulation(situation=...)and checks the result depends on neither the household's weight nor the number of axis points.The two fallbacks in proposal 1 are not equivalent next to the consumer side.
consumer_incident_tax_revenue_change.py:13already falls back to a national total, consumption over a literal £846bn. Suppose situations returned 0 for corporate incidence. A reform split between capital and consumers would then show only the consumer half in the household calculator. So the 0 option means changing the consumer fallback as well. The national-total option should replace the £846bn literal with the same kind of uprated parameter. Whichever is chosen, both sides should move together.Nit
consumption_shareholdingalso means taking it out ofWHOLE_POPULATION_VARIABLES(utils/household_subset.py:44),SHARESintests/test_variable_units.py:20, and the cases intests/test_weighted_incidence.py(lines 96, 113, 129 and 145).Checked and fine:
shareholding.py:12-23,build_from_situationatsimulation.py:1182-1202,household_weight.py:11,corporate_land_value.py:13-27,consumption_share.py:12-19andconsumer_incident_tax_revenue_change.py:11-22match. So doattends_private_school.py:42and72-78,filter_dataset.py:47-57, the cited test lines and the "modelling convention" text in both statistics files.fiscal_partition.yaml. Lines 797-804 and 811-817 match at 2.174.1. On main those guards have moved to 811-818 and 825-831.householdnode and never reachesfinancial_net_worth. At zero weight,shareholdingis 50,000 / £5,327bn, the 2021 value.build_from_situationsetsbuilt_from_dataset=False(simulation.py:1188), and the axes case reads False too. policyengine.py's household calculator importspolicyengine_uk.Simulation(household.py:173), and policyengine-api builds throughcountry_package.Simulation(situation=...)(country.py:565-577).uprating. The indices are generated fromyoy_growthincreate_economic_assumption_indices.py, so a product of the per-capita GDP and population indices can be generated in the same pass. Both parts of the key uprate withindices.obr.per_capita.gdpandhousehold_weightwithindices.ons.population. There is no nominal GDP index to use instead.self.dataset = UKSingleYearDataset.from_simulation(...). 8223275 is in Begin refactoring and adding statistics #597. OBR March EFO update #840 merged on 12 April 2024. Improve corporate land allocation #1583 replaced the parameter total with the weighted one.Verdict: the diagnosis and the reproduction hold on main. Widen proposal 1 to the whole-population set, and choose its fallback together with the consumer-incidence one.
🤖 Generated with Claude Code
juaristi22 commentedon Nov 9, 2026
Findings from the land value tax work, checked against policyengine-uk main e050200 (2.176.1), PolicyEngine/microcosm main 3db65154b, PolicyEngine/policyengine-uk-data main ed19e336b and PolicyEngine/uk-land-value-tax main 371e2b1. They add one more caller, one case for proposal 3, and the consumers outside this repository that proposals 2, 4 and 5 would move.
One more caller of the situation path (proposal 1)
PolicyEngine/uk-land-value-tax's pipeline builds an example household through
Simulation(situation=...)(src/uk_land_value_tax/pipeline.py:400-442). The household has a £400,000 home and £50,000 ofcorporate_wealth. Indashboard/public/data/lvt_results.json:2986-2994, itscorporate_land_valueis £2,058.6bn and its LVT at 1% is £20.6bn. The dashboard does not show this block, but the file is in the dashboard's public folder. Proposal 1 fixes it once the pipeline runs again.Proposal 3 should cover the corporate part of
LVThbai_household_net_incomesubtracts the whole ofLVT(variables/household/income/hbai_household_net_income.py:100).LVTchargescorporate_land_valueat the full rate throughland_value, and again atcorporate_rate(variables/contrib/ubi_center/land_value_tax.py:13-16).variables/household/income/hbai_excluded_income.py:14).lvt_results.json:1972). On £2,058.6bn of corporate land, that takes about £17bn from HBAI incomes, shared out bycorporate_sector_wealth.Proposal 2: carry the total, not the shares
Writing
shareholdingorcorporate_land_valueinto the data as inputs would not do what proposal 2 does:aggregate_corporate_land_valueor the key.So the data should carry the parts of the key and its national total. The shares, the levels and the incidence should stay in the formulas. Until proposal 2 lands, PolicyEngine/uk-land-value-tax's seat results have to come from one UK-wide run grouped by constituency, not from runs filtered to each seat.
Proposal 4: what the data can give
WAS round 8 records directly held UK shares apart from overseas shares. It also records pension wealth by type: workplace DB and DC schemes, AVCs, personal pensions, retained DB and DC rights, pensions in payment, and pensions from a former partner.
Microcosm's key already uses part of this (
packages/microcosm-build/src/microcosm/build/uk_runtime/was_wealth.py:562-570):corporate_wealthcounts UK shares, employee shares, collective investments and stocks and shares ISAs. It leaves overseas shares out.private_pension_wealthis total private pension wealth less current-employment DB rights. So it keeps retained DB rights and pensions in payment.The pension part changes the key a lot. Microcosm's
experiments/452-uk-pension-wealth-split.md:92-96puts 54.4% of the key in the top tenth of households when the key includes pension wealth, and 86.7% when it does not.A weight for each part, such as 0 for the DB-type parts, needs
private_pension_wealthsplit into columns by type. That would follow the split of direct shares and trusts written for Itemise corporate_wealth's share-like components for the means tests #1974.WAS cannot give the UK-owned share of UK companies, or how much of a fund, an ISA or a pension scheme is in UK companies. Published aggregates can:
They would come in through Chronicle as facts.
aggregate_corporate_land_valueis described as the land of non-financial and financial corporations (parameters/household/wealth/land/value.yaml:25). Microcosm binds its target to ONS's non-financial corporations' land (E43B). Workstream 2 of Epic: UK land value data for land value tax results by constituency microcosm#1521 checks which one the value is. Its 2025 and 2026 values repeat the 2024 value.Consumers outside policyengine-uk (proposals 2, 4 and 5)
UK_WEIGHT_SHARE_FORMULA_INPUTS(packages/microcosm-build/src/microcosm/build/uk_runtime/full_measure.py:50) namesshareholding,corporate_land_valueandconsumption_shareholding, with the columns thatcorporate_sector_wealthandconsumptionadd.packages/microcosm-build/tests/engine/uk/test_uk_weight_share_formula_inputs.py:32-48checks them against the installed engine.consumption_shareholding(proposal 5), or changing whatcorporate_sector_wealthadds (proposal 4), fails that test at Microcosm's next engine bump. So each needs a Microcosm change in the same bump. This adds to nit 3 of the review above.corporate_land_value: Microcosm'sons.land.corporate_land_value(packages/microcosm-build/src/microcosm/build/uk/uk_population_targets.json:16319) and theons/corporate_land_valuerow of uk-data's loss matrix (policyengine_uk_data/targets/build_loss_matrix.py:408). Both also targetland_value, whose corporate half is the same quantity.corporate_land_valuedivides by the weighted total it is computed with. So its weighted total always comes back toaggregate_corporate_land_value, and a target on it says nothing about households.corporate_sector_wealthup or down, by the ratio of the target to the parameter. Computed again at the solved weights, the total is the parameter again. Microcosm's check of frozen against recomputed values lists this row among the bound rows that differ by more than 1% (experiments/929-council-tax-taxbase-receipts.md:188-190).experiments/762-uk-rowwise-candidate-receipts.md:315-321). This is the issue's partial-UK case inside a build. As the issue says, proposal 2 would make that scaling unnecessary.🤖 Generated with Claude Code