# Methodology

This document is the source of truth for every number, source and assumption in
**California Tax Trades**. The app renders it on its Methodology tab, and the
per-view notes under the plot are pulled out of the sections below, so there is
one copy of the truth and two renderings of it. If a data source changes, an
imputation changes, or a view changes, this file changes in the same commit.

Everything here is checkable. Each section ends with the URLs it used. Where a
number is an estimate, a calibration or an outright guess, it says so in the
place where a reader would otherwise assume it was measured.

## What this tool is, and what it is not

It is a **static incidence microsimulation**: a sample of real California
households, weighted to the state, with real state-specific tax bases,
calibrated to what the state actually collects, and every incidence assumption
exposed as a control you can move. That is the same design the Institute on
Taxation and Economic Policy uses for its *Who Pays?* state reports.

What it can support is a **first-instance, static distributional claim under
stated assumptions**: if these five rates were these numbers tomorrow, and
nobody changed what they earn, own, buy or sell, this is roughly who would pay
more and who would pay less, and this is roughly what the state would collect.
The one price that does move is the price of land, because a land tax changes
it mechanically; see *Capitalisation: land prices move with the land tax*.

It is not a revenue estimate, not a forecast, and not a policy proposal. It has
no behavioural response of any kind, no general equilibrium beyond the land
price and a crude rent response, no year-by-year path, and no account of what
happens to the money once it is collected. Two numbers it deliberately keeps
apart are what the state **collects** and what households **bear**; see
*Incidence and pass-through*.

Sources: [ITEP, Who Pays? 7th edition](https://itep.org/whopays/)

## The two baselines: a flat rate, or Prop 13 as billed

Every trade in the app is measured against a "today". There are two, and the
**Compare against Prop 13 as billed today** switch in Assumptions picks one.
Your proposal is always the same thing: the levers' rates on **market value**.

**The flat baseline (default).** Proposition 13 does not exist: the property
tax is one flat rate on today's market value, split into a land half and a
buildings half, at the rate that raises what California's property tax
actually raises. $100.026B of 2024-25 levies (BOE Table 4) over $13.69T of
market value (CLE) is **0.7306%**, which is where both the land lever and the
buildings lever start. This is what makes the five levers comparable: a land
value tax is a rate on market value, so the property tax it trades against has
to be one too. Against it, a change on the page is a change in the *mix* of
taxes and nothing else.

**Prop 13 as billed.** Today is what people actually pay:

- **Owners pay the bill they report.** ACS PUMS asks every owner for their
  yearly property tax (`TAXAMT`), which is Prop 13's own answer for that
  household: purchase price plus at most 2% a year, times about 1%, plus
  voter-approved debt. Over the sample that is **$51.19B on $7.22T of owned
  homes, 0.709%** of market value. Owners who moved in within the last two
  years pay **0.810%**, and longer-tenured owners pay less, which is Prop 13
  showing up in the data.
- **Everyone else pays one rate.** Nothing reports the bill on a rented home or
  a shop, so the rest of the levy, $48.83B, is spread over the market value of
  rented homes ($3.61T) and non-household property ($2.86T) at one effective
  rate: **0.7554%**.

Both baselines raise the same $100.026B (to within $0.01B of rounding), so the
revenue bar and the Balance target do not move with the switch. What moves is
who paid it. Against Prop 13, every change shown **includes replacing Prop 13
with market value** even with the levers untouched: on its own that shifts an
average $887 a year onto owners 65 and over and takes $489 off owners under 65,
while 70% of households pay less and the total barely moves.

Three cautions on the Prop 13 baseline:

- `TAXAMT` is **self-reported and bracketed** (PUMS publishes a bracket
  midpoint), and some owners will include special assessments and Mello-Roos
  charges that the BOE levy does not count. Recent movers' 0.81% is below the
  statutory ~1.1% on purchase price, which suggests reported bills run low or
  reported values run high; either way the residual rate on everything else
  absorbs the difference, because the total is pinned to the BOE levy.
- The residual rate treats a 1978 apartment block and a 2024 warehouse alike.
  Rented and commercial property is Prop 13-assessed too, and nothing
  statewide says how far below market each one sits.
- About $3.5B of the levy falls on business personal property (equipment), not
  real estate. The model folds it into the non-household property bill.

Sources: [BOE Table 4](https://www.boe.ca.gov/dataportal/dataset.htm?url=PropTaxAssessedValueSummary) ·
[ACS PUMS 2023 housing file](https://www2.census.gov/programs-surveys/acs/data/pums/2023/1-Year/csv_hca.zip) ·
[Center for Land Economics](https://landeconomics.org/reports/california-billionaire-wealth-tax)

## Data sources

Every external input, exactly where it comes from, what is taken from it, and
whether the number that comes out is pinned to a primary document. Six are data
files the pipeline downloads; three are printed figures typed into the
pipeline as constants, with the page they are on. Flagged inputs also carry
`approximate: true` and a reason in `data/baseline.json`, which the app's
Sources disclosure renders directly, so the list on the page cannot fall behind
the model.

### Downloaded data files

The pipeline fetches each file into `data/raw/` (gitignored) and writes its
size and SHA-256 into `data/baseline.json` under `rawFiles`. The ones below are
the bytes this build read.

| file | URL | vintage | what is taken from it | bytes | SHA-256 |
| --- | --- | --- | --- | ---: | --- |
| ACS PUMS, California housing | [csv_hca.zip](https://www2.census.gov/programs-surveys/acs/data/pums/2023/1-Year/csv_hca.zip) | 2023 1-year | `SERIALNO`, `PUMA`, `WGTP`, `TYPEHUGQ`, `TEN`, `HINCP`, `ADJINC`, `VALP`, `GRNTP`, `ADJHSG`, `BLD`, `HHT`, `R65`, `TAXAMT`, `MV` | 25,995,268 | `7263d141323bca4d53b56a537ea278dd1c57eee08beb818f2b4cf42f7f787f9f` |
| ACS PUMS, California persons | [csv_pca.zip](https://www2.census.gov/programs-surveys/acs/data/pums/2023/1-Year/csv_pca.zip) | 2023 1-year | `SERIALNO`, `INTP`, `SEMP`, `ADJINC` | 69,791,730 | `b46811cca68b8df7019ab7ce6ef86ba82397ea30507231b6e2df25a8d06dcd76` |
| FHFA land prices | [land-prices_2024_20_june.xlsx](https://www.fhfa.gov/document/land-prices_2024_20_june.xlsx) | v4.0, June 2024 | sheet `Cross-Section Counties `, column "Land Share of Property Value" (as-is, standard single-family home), 54 California counties by FIPS | 17,160,123 | `3db67f331d609117ef52adab6068f18eb1184f821ed750af2517d03f047b618b` |
| BOE Table 4 (JSON API) | [Summaries_of_Assessed_Values_by_Property_Class](https://www.boe.ca.gov/dataportal/api/odata/Summaries_of_Assessed_Values_by_Property_Class) | 2024-25 row | "Totals all property": `PropertyTaxLevies` $100,025,871,000, `StateAverageTaxRates` 1.152, and the assessed land, improvements and personal property quoted above | 24,697 | `6cddb2920e58fd5f616d826811dad2590c8e68418ac530577589055c69383fdd` |
| FTB personal income tax by ZIP | [2024_personal_income_tax_statistics_by_zip_code.csv](https://data.ca.gov/dataset/71b7f174-eee9-45fa-ac87-5dd533640878/resource/7091fcca-e695-49ab-aa44-6e0c6f49c9c1/download/2024_personal_income_tax_statistics_by_zip_code.csv) | tax year 2023 (latest in file) | `TotalTaxLiability`, `Returns`, `County` where `State` is CA: $96.4B on 17,671,904 returns, the external check on the bracket walk | 13,017,192 | `aaeb63161e951b599413c2437fe814f806b1b576d96a596ff0ef60a227b52238` |
| IRS SOI Historic Table 2, California | [22in05ca.xlsx](https://www.irs.gov/pub/irs-soi/22in05ca.xlsx) | tax year 2022 | rows "Number of returns", "Net capital gain (less loss)", "Total rental and royalty net income (less loss)", "Partnership/S-corp net income (less loss)", each by AGI class | 271,180 | `80805dc2b13a7adf219c1c749750b2df5ce7ba76ea5e25a45d0e2fd6c0be697f` |

The BOE endpoint is a **live** table that grows every year, so the exact bytes
read are committed as `data/snapshots/boe-table4.json` and the pipeline reads
that snapshot rather than the live URL. It also stops if the 2024-25 levy in
the file is not the constant it expects. The census, FHFA, FTB and IRS files
are fixed releases.

### Printed figures typed in as constants

| figure | value | where it is printed | constant in `build-microsim.py` | pinned |
| --- | --- | --- | --- | --- |
| California land at market value | $8.14T | [Center for Land Economics, "Land, the Wealth We Can Actually Tax"](https://landeconomics.org/reports/california-billionaire-wealth-tax) (2025). The conservative end of its own range: FHFA-benchmarked $8.76T, time-trended sales $10.12T | `LAND_VALUE` | yes |
| California real estate at market value | $13.69T | the same CLE report, same pipeline | `REAL_ESTATE_VALUE` | yes |
| Sales and use tax, 2023-24 | $79.4B | [CDTFA Publication 306, 2023-24 Annual Report](https://cdtfa.ca.gov/formspubs/pub306-2023-24.pdf), printed page 8: "California sales and use tax revenue totaled $79.4 billion in fiscal year 2023-24" | `SALES_REVENUE` | yes |
| Average combined sales tax rate | 8.85% | not pinned to a primary table | `SALES_RATE` | **no** |
| Household share of taxable sales | 60% | not pinned; the plan's number | `SALES_HOUSEHOLD_SHARE` | **no** |
| General Fund personal income tax, 2024-25 | $130B | not printed as one line the build could read: the Department of Finance revenue tables are images. The [State Controller's June 2025 cash report](https://lakeconews.com/news/business/82104-state-controller-issues-june-2025-cash-update) puts receipts $1.3B (1%) above the May Revision forecast, consistent with about $130B | `PIT_REVENUE` | **no** |
| Sales and excise tax as % of income, by income group | seven national shares | [ITEP, Who Pays? 7th edition](https://media.itep.org/ITEP-Who-Pays-7th-edition.pdf) (2024), national appendix; the California page is an image | `ITEP_GROUPS` | **no** (national) |

Two corrections to earlier versions belong in the record. The $13.69T was cited
to a BOE press release (NR-26-01); it is **CLE's** figure, and the BOE's own
number is *assessed* value, $9.1T, which Prop 13 holds far below market. And
sales tax was $75B, the plan's round number; CDTFA prints $79.4B.

### Modelling constants

Every number below is a choice, not a measurement, and each is either a
control on the page or named where it is used.

| constant | value | where it matters |
| --- | --- | --- |
| Gross rental yield, coastal counties | 4% | a renter's home is worth 12 × rent ÷ yield |
| Gross rental yield, other counties | 5% | the same |
| Coastal counties (FIPS) | 001, 013, 015, 023, 037, 041, 045, 053, 055, 059, 073, 075, 079, 081, 083, 085, 087, 095, 097, 111 | the twenty counties on the Pacific or San Francisco Bay |
| Condo land share | half the county's | owners in buildings of 2+ units (`BLD` ≥ 4) |
| Discount rate for land prices | 4% | capitalisation; a control |
| Land tax passed to renters | 0% | a control |
| Buildings tax passed to renters | 50% | a control |
| Rent response to renters' tax change | 0.5 | a control |
| Share of rented and business property owned outside California households | 35% | a control |
| Sample size, stratum floor | 8,000, 420 rows | the draw |

### A column-alignment trap

One correction belongs in the record, because it is exactly what a methodology
document is for. In the IRS SOI California spreadsheet a data row runs

```
label, all returns, NO ADJUSTED GROSS INCOME, then the nine AGI classes
```

and the no-AGI column carries **no label in the header**. Slicing the numbers
from the first one therefore shifts every class by one: the share belonging to
`$200-500k` gets printed against `$100-200k`, and the top class picks up the
class below it. The first reading of the rental and partnership rows for the
indirect allocation was shifted exactly that way, which made the concentration
at the top look far higher than it is (it read "97% of positive rental income
above $200k" where the corrected columns say 70%).

The rule that falls out of it: in these tables, **cells 3 to 11 of a data row
are the nine AGI classes**, and any vector read out of them should be checked
against a row whose shape you already know before it is trusted. The same trap
applies to the capital-gains rows this file also reads.

Sources: [IRS SOI Historic Table 2, California](https://www.irs.gov/pub/irs-soi/22in05ca.xlsx)

## Reproducing everything

Every number on the page is computed in the browser from two committed files,
`data/households.json` and `data/baseline.json`, plus the constants in
`taxes.js` that a test pins to `baseline.json`. Both files are written by one
script, which is deterministic: the same input bytes give the same
`households.json` byte for byte, and the same `baseline.json` except for its
`built` date.

```
# Python 3.11, standard library only; Node 22 for the tests
python3 lvt-explainer/data/build-microsim.py      # ~30s; downloads ~126MB into data/raw/
node --test lvt-explainer/test/*.test.js           # 231 tests
```

To check you read what this build read, compare each file in `data/raw/` with
the SHA-256 in the *Downloaded data files* table (the script also writes them
into `baseline.json` as `rawFiles`). The committed `households.json` has
SHA-256 `d52401009b1638c1dc3b4930fbae7fc4b089385bc6e6f6e4ddff464bfdd62a5a`.

The pipeline runs in this order, and every step prints what it measured:

1. Fetch the six files (the BOE table from `data/snapshots/`).
2. Read the BOE levy and check it is $100,025,871,000.
3. Read FHFA's county land shares.
4. Read every PUMS housing record in the universe below: income, home value,
   rent, tenure, reported property tax, and a first land share from FHFA.
   Impute each renter's home from the rent at the county's yield.
5. Join `INTP` and `SEMP` from the person file.
6. Draw the stratified sample.
7. Reconcile the land share with CLE's totals (`alpha`), then compute the
   Prop 13 residual rate.
8. Impute realised gains and taxable spending onto the sample; calibrate the
   income tax.
9. Read the IRS share vectors for the indirect burden.
10. Write `households.json` (money in $100 units) and `baseline.json`, and
    recompute the Prop 13 rate from the rows as written, so the browser's
    Prop 13 "today" adds to the levy.

## The sample: how it is built and weighted

`data/build-microsim.py` is the offline pipeline; `data/households.json` is its
committed artefact, and the app never re-runs the pipeline. Re-run it only to
refresh the sample.

- **Universe.** ACS PUMS 2023 1-year California housing records, restricted to
  occupied housing units (`TYPEHUGQ == 1`) with a positive household weight
  (`WGTP`) and a valid tenure (`TEN`): 140,143 records standing for 13,699,816
  households, of which 7,666,209 are owners and 6,033,607 are renters. Incomes
  and housing values are put on a common footing with the ACS adjustment factors
  `ADJINC` and `ADJHSG`.
- **Geography.** A PUMA's first three digits give a county FIPS, which puts each
  household in exactly one of eight **strata**: San Francisco, rest of the Bay
  Area, Los Angeles County, San Diego, Sacramento, Fresno, the Inland Empire,
  and the rest of California. The region chips are *sets* of strata, so "Bay
  Area" can contain "San Francisco" without any household being counted twice.
- **Sample size.** 8,004 rows against a target of 8,000, with a floor of 420
  rows per stratum so the small regions are drawable. Strata above the floor are
  scaled back to land near the target.
- **Draw.** Inside a stratum, rows are put in cells of owner/renter crossed with
  statewide income decile, each cell gets a share of the stratum's allocation
  proportional to its weight, and the draw inside a cell is a **systematic
  probability-proportional-to-size** pass over rows sorted by income, so the
  draw spans the cell's spread instead of clustering in it.
- **Weights.** Each drawn row carries the total weight of the households it
  stands for, so the sample re-weights to 13,699,816 households and every total
  in the app is a weighted total. Deciles are **weighted** quantiles of income
  (`wquantile` in `taxes.js`), not counts of rows.
- **Storage.** Money is stored in $100 units, which is what keeps the file
  small enough to ship. As committed it is **8,004 rows of seventeen fields,
  437,038 bytes (427KB)**, inside the ~450KB budget this app works to. The row
  format is

  ```
  [income, homeValue, land, renterLand, improvements, renterImprovements,
   spending, gains, tenure, age65, joint, regionIdx, weight, rent,
   capIncome, bizIncome, propTax]
  ```

  Fields past the fourteenth were **appended** (`capIncome` and `bizIncome` at
  14 and 15, the owner's reported property tax `propTax` at 16), so earlier
  fields keep their positions and `decode()` reads a missing one as zero. Any
  future field goes on the end for the same reason.
- **The person-file join.** `capIncome` and `bizIncome` come from the PUMS
  **person** file, summed per `SERIALNO` and joined to the housing records:
  **140,143 of 140,143 housing rows matched, 100.0%**, so the join drops no
  household and those two fields cover the same 13,699,816 weighted households
  as every other field. Over that universe `INTP` totals **$107.3B** and `SEMP`
  **$95.8B**. The phase 2 plan quoted $105.2B and $94.0B over 14.76M weighted
  households: that is the person file's own universe, which includes group
  quarters and records with no valid tenure, and this pipeline excludes both.
  The drawn sample itself re-weights to 13,699,515, 301 households (0.002%)
  short of the universe, because weights are rounded when they are written.

Sources: [ACS PUMS](https://www.census.gov/programs-surveys/acs/microdata.html)

## How each base is imputed

Four of the five taxes are struck on a base the survey does not report, so each
one is imputed. Every imputation below is a **statistical** assignment: it makes
the weighted totals right, not any individual household's own affairs right.

### Land under a home

A household's home value comes from PUMS (`VALP`). The land share of it starts
from the FHFA county cross-section: the land share of property value for a
standard single-family home in that county, with the median county share
standing in for households whose PUMA has no county prefix (none, in the 2023
file). A condo, an owner in a building of two or more units, gets **half** its
county's share, because it owns a slice of the lot rather than the whole one.

A renter's household does not own land, but its landlord does, and the app
needs the land under a rented unit to bill it. That comes from the rent
(`GRNTP`): a unit renting for $R a month is treated as property worth
`12R / yield`, of which the county's land share is land. The yield is **4% in
the twenty coastal counties** (on the Pacific or the San Francisco Bay, listed
under *Modelling constants*) and **5% everywhere else**, because coastal rents
are a much smaller fraction of what the property would sell for. Both are
conventions, not measurements, and they are the most leveraged assumption in
the renter half of the model. Over the sample, renters' homes come to
**$3.61T**.

**Reconciling the land share with CLE's totals.** Taken as they come, FHFA's
shares put **50.2%** of households' $10.83T of property in land, while CLE's
own totals put **59.5%** of all California real estate in land ($8.14T of
$13.69T). Used together as they were, that left the non-household residual,
every shop, office, warehouse, farm and vacant home, at about $2.8T of property
of which some 96% was land: no buildings to speak of. So one factor scales
every household's FHFA share,

```
alpha = s × Vh / Lh = 0.5946 × $10.83T / $5.44T = 1.1847
```

where `s` is CLE's statewide land share, `Vh` households' property and `Lh`
their FHFA land. It is the one value that gives the non-household residual the
same land share as the state as a whole. FHFA still decides the *pattern* (San
Francisco over Fresno, a house over a condo); CLE decides the *level*. No
household's share hits the 95% cap. CLE's own FHFA-benchmarked estimate is
$8.76T, above the $8.14T used here, which is consistent with FHFA's
single-family shares understating land when they are applied to survey values.

Measured over the sample after the reconciliation: **$4.19T** of land under
owned homes and **$2.25T** under rented ones, **79.1%** of the state's $8.14T.
The non-household residual is **$1.70T**.

### Improvements: the buildings half

`improvements = homeValue − land` for an owner, and
`renterImprovements = renterValue − renterLand` for a renter, both floored at
zero. Statewide, improvements are CLE's market value less its land:
$13.69T − $8.14T = **$5.55T**. Households hold $3.04T (owned) and $1.36T
(rented), **79.1%**, and the non-household residual is **$1.16T** of buildings
on its $1.70T of land.

That split replaces an earlier one in which households held 93% of buildings
and 63% of land, which had made the buildings lever regressive by
construction. The residual is still a residual: if CLE's $13.69T is low (its
land figure is the low end of its own range, and survey home values are
self-reported), the non-household share is understated for both halves alike.

### Taxable spending

Taxable spending is imputed from income: a household's sales-and-excise tax as a
share of income is read off the ITEP *Who Pays?* profile for its income group
and divided by the 8.85% rate to turn a tax share back into a spending share.
The seven national groups used are:

| income group | sales and excise as % of income | implied spending as % of income |
| --- | ---: | ---: |
| Lowest 20% | 7.0% | 79.1% |
| Second 20% | 5.7% | 64.4% |
| Middle 20% | 4.8% | 54.2% |
| Fourth 20% | 4.0% | 45.2% |
| Next 15% | 3.2% | 36.2% |
| Next 4% | 2.2% | 24.9% |
| Top 1% | 1.0% | 11.3% |

That shape implies $754B of taxable household spending in California. The
statewide base is $79.4B ÷ 8.85% = **$897B**, and the household share of it
(60%) is **$538B**, so every household's spending is multiplied by the
calibration factor **0.713789**. The *shape* is ITEP's and national; the
*level* is California's. The other 40%, **$359B**, is what businesses buy.

### Realised capital gains

Gains are lumpy, so smearing a class average over everybody would be the one
imputation guaranteed to be wrong. Instead, from the IRS SOI California table
for tax year 2022, each of the AGI classes gives two things: the share of
returns in that class that reported a net capital gain, and the total amount.
Each sample row is assigned to a class by income; a **deterministic hashed
subset** of each class, `crc32('lvt-gains:' + rowIndex)` sized by that class's
share of returns with a gain, is picked to carry the gains; and the amount
handed to the picked rows is whatever makes the class total come out right. The
subset is identical on every run, and the weighted class totals match the IRS by
construction rather than by a factor.

Statewide that is **$177.0B** of realised gains on 3,837,920 households in the
sample. The top class is nearly the whole story: **38,805 households at $3.29M
each, $127.5B of the $177.0B**.

Two things to distrust. 2022 was a **weak** year for realisations; a normal year
is nearer $150–200B, and no scale factor is applied. And no household in the
sample realised the gain it is carrying: the imputation is right about the class
and silent about the household.

### Capital and business income

These two fields exist only to place the indirect burden **inside** an income
class; see the next section. `capIncome` is PUMS `INTP` (interest, dividends and
net rental income) summed over a household's people and floored at zero;
`bizIncome` is `SEMP` (self-employment income) treated the same way.

Measured on the **shipped sample**, weighted: `capIncome` totals **$106.3B**
and `bizIncome` **$97.6B**, against $107.3B and $95.8B for the same two columns
over the whole person file. The sample is 0.9% light on one and 1.9% heavy on
the other, which is the draw, not a different definition.

Both are concentrated, and `capIncome` much the more so:

| decile | `capIncome` | share | % of households with any | `bizIncome` | share | % with any |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| 1 | $0.2B | 0.2% | 4.7% | $0.9B | 0.9% | 8.9% |
| 2 | $0.7B | 0.6% | 8.2% | $3.3B | 3.4% | 12.8% |
| 3 | $1.7B | 1.6% | 10.5% | $5.0B | 5.1% | 14.4% |
| 4 | $2.4B | 2.2% | 13.0% | $4.9B | 5.1% | 13.5% |
| 5 | $3.8B | 3.6% | 14.4% | $5.1B | 5.2% | 11.9% |
| 6 | $5.6B | 5.3% | 19.5% | $8.0B | 8.1% | 13.7% |
| 7 | $5.9B | 5.6% | 19.5% | $8.3B | 8.5% | 15.6% |
| 8 | $8.1B | 7.6% | 21.8% | $10.5B | 10.8% | 14.3% |
| 9 | $10.5B | 9.9% | 27.1% | $10.2B | 10.4% | 14.9% |
| 10 | $67.3B | 63.4% | 46.7% | $41.5B | 42.5% | 18.9% |

The top decile holds **63.4%** of `capIncome` and **42.5%** of `bizIncome`
(the plan measured 62.5% and 45.3% over the person file), and 46.7% of
top-decile households report any capital income against 4.7% of the bottom
decile. That is the shape the within-class split of the indirect burden
inherits, and it is flatter than the tax data's, for the reasons in
*Why both, and what is left unassigned*.

Sources: [FHFA land prices](https://www.fhfa.gov/document/land-prices_2024_20_june.xlsx) ·
[ITEP Who Pays? 7th edition](https://media.itep.org/ITEP-Who-Pays-7th-edition.pdf) ·
[IRS SOI Historic Table 2, California](https://www.irs.gov/pub/irs-soi/22in05ca.xlsx) ·
[Center for Land Economics](https://landeconomics.org/reports/california-billionaire-wealth-tax) ·
[CDTFA Publication 306](https://cdtfa.ca.gov/formspubs/pub306-2023-24.pdf)

## The five taxes as formulas

All five are in `householdTaxes(row, rates, opts)` in `taxes.js`, which is pure
and tested. `owner` is tenure; `passLand`, `passBld` and `rentElasticity` are
the controls in the Assumptions group; `cal` is the income calibration.

```
k     = (d + t0) / (d + lvtRate)          land price factor; 1 at today's rate
                                          (see Capitalisation)

lvt   = owner ? land × k × lvtRate
              : renterLand × k × lvtRate × passLand

bld   = owner ? improvements × bldRate
              : renterImprovements × bldRate × passBld

  under the Prop 13 baseline (today only), lvt + bld is instead
      owner  : propTax                             the reported bill
      renter : (renterLand + renterImprovements) × r13 × pass
  split between the two lines by the home's land share

income = caIncomeTax(income + (gainsAsIncome ? gains : 0)
                     + (ubiTaxed ? ubi : 0), filing, schedule) × cal
         − nit − ubi

nit    = nitRate × min(income, upTo × (joint ? 1 : ½))
                                          nitRate capped at 25%; 0 today
ubi    = ubiAmount × (joint ? 2 : 1)      a year, per adult; 0 today

gains  = gainsAsIncome ? 0 : gains × gainsRate

sales  = spending × salesRate

rentRise = owner ? 0 : rent × rentElasticity × tierGain(rent)

taxes = lvt + bld + income + gains + sales
total = taxes + rentRise + indirect      (indirect only with the allocation on)
```

The pieces that are not obvious:

- **The income tax is a bracket walk, not an average rate.** `tax-core.js`
  carries the 2024 FTB schedule for single and married-filing-jointly, the
  standard deduction ($5,540 / $11,080) and Prop 63's extra 1% mental health
  services surtax over $1M. The income lever edits that schedule directly (drag
  a handle in the graph, or type in the Exact values table) and a **uniform
  multiplier** scales every rate in it. The multiplier is what the balancer
  solves on, which is why the graph draws the unscaled schedule and the line
  under it says what the multiplier does on top.
- **Calibration is one number, 1.012863.** The bracket walk over the sample's
  income plus imputed gains raises $128.3B before calibration; scaling it to the
  $130B General Fund line is the factor. The independent check is the FTB's own
  ZIP-code file: the same walk without gains raises **$107.0B** against the
  FTB's **$96.4B** of self-assessed liability for 2023, a factor of 0.898. The
  model is therefore about 11% high against the FTB before gains, which is
  roughly the gap you would expect between "tax computed on census income" and
  "tax self-assessed after every deduction and credit".
- **A negative income tax and a universal income are paid through the income
  tax**, so they come off its line (which can go below zero) and the revenue
  bar and the balancer see their cost like any other cut. Both are off today.
  The negative income tax is a **negative bracket**: every household is paid
  `nitRate` (up to 25%) of its first dollars of income, up to a band of
  `upTo` ($20,000 joint by default, half for a single filer, the convention
  the bracket thresholds follow). Below the band the payment grows with
  income; above it, it stays at its top (`nitRate × upTo`, $5,000 joint and
  $2,500 single at 25%) for everyone, however much they earn. There is no
  break-even and no phase-out, so it is in effect a flat credit for most
  households and a wage match for the lowest earners; the ordinary brackets
  above it are untouched. Its base is income alone: realised gains and the
  universal income do not count. The universal income is a flat amount per
  adult. By default it is untaxed; with the "Tax the universal income" box
  ticked it is added to income in the bracket walk, so each household owes
  its marginal rate on it and that part comes straight back
  (`householdTaxes().ubiTax`, about 7% of what is paid, since California's
  rates are low for most of the households it reaches). **The sample has no
  adult count**, so filing status stands in for it:
  a joint household is two adults, a single one is one, and children are paid
  nothing; that is 20.3M adults, and each $1,000 a year costs $20.3B before
  any tax on it. The one row that does carry an adult count is the reader's
  own household (see *Your household*), which is paid for each adult it
  enters. Neither
  payment is calibrated, because `cal` scales a modelled liability to
  collections and these are transfers the model writes itself. At 25% on the
  first $20,000 the negative income tax pays $49.3B, nearly all of it to
  households above the band.
  Nobody changes how much they work or earn in response, which for a transfer
  this size is the first limit below at its sharpest.
- **Gains raise nothing of their own in the baseline**, because California taxes
  them as ordinary income: their revenue is already inside the $130B. Switching
  them out of the income tax costs about **$21.6B** before a flat rate raises a
  dollar, and a flat **12.2%** is what exactly replaces it.
- **A rent rise is not a tax.** `taxes` is the part that is revenue; `rentRise`
  is a transfer from a tenant to a landlord and is counted in what a household
  bears and never in what the state collects.

Sources: [FTB tax rate schedules](https://www.ftb.ca.gov/) ·
[FTB statistics by ZIP](https://data.ca.gov/dataset/personal-income-tax-statistics-by-zip-code)

## Incidence and pass-through

Two totals in this app must never be added together.

- **Collected** revenue is `stateRevenue()`: the whole bill on a rented lot is
  the landlord's bill, and the state collects all of it whatever the
  pass-through controls say. That is the revenue bar, and today it is
  **$309.4B**.
- **Borne** incidence is `aggregate()` over households: only the share of a
  tax that reaches a household counts, pass-through applied. That is what the
  burden and change views draw, and today it is **$235.4B** directly.

The gap between them is the non-household share plus the part of a landlord's
bill that does not reach the tenant. It is not money that vanishes, and the app
never says it leaves households; it is money whose final resting place this
model does not claim to know.

The three pass-through assumptions, all exposed as controls:

| assumption | default | why |
| --- | ---: | --- |
| Land tax passed to renters | **0%** | The supply of land does not respond to its price, so the standard result is that a land tax is borne by the owner and cannot be shifted to a tenant. This is the strongest theoretical claim in the model, and it is still a control you can move. |
| Buildings tax passed to renters | **50%** | Buildings are elastic supply over time, so part of a tax on them does reach rent. 50% is a convention, between the land tax's 0% and a full pass-through, and no source pins it. |
| Rent rises with income (ε) | **0.5** | When renters get a tax cut, some of it is bid back into rent. The model measures the average tax change for renters in each of three rent tiers as a share of their income and moves each renter's rent by `ε × tierGain`, so ε is the **elasticity of rent with respect to renters' income**: at 0.5, a cut worth 1% of income lifts rent 0.5%. The share of the cut that reaches the landlord is ε × rent ÷ income, about a sixth for a renter paying a third of income in rent. See *What ε should be* below. A crude equilibrium. |
| Sales tax on business purchases | **passed forward** | Tax a business pays on what it buys is built into the price of what it sells, which is how ITEP and the CBO treat it. It is borne by shoppers in proportion to their taxable spending; see *The indirect burden*. Not a control. |

**What ε should be.** No study measures it for an untied, statewide tax cut,
so 0.5 is a bracket, not an estimate. The evidence that bounds it:

- **Housing-tied subsidies, the upper bound.** Money that can only be spent on
  rent is captured heavily by landlords: 60% to two-thirds of UK Housing
  Benefit ([Gibbons and Manning 2006](https://ideas.repec.org/a/eee/pubeco/v90y2006i4-5p799-822.html)),
  about 78% of French housing aid (Fack 2006). US vouchers are weaker
  evidence: more vouchers did not raise average rents, only those of units
  near the voucher's rent cap, and mostly in supply-inelastic metros such as
  Los Angeles, San Francisco and New York, while the cheapest units' rents
  fell ([Eriksen and Ross 2015](https://doi.org/10.1257/pol.20130064)), which
  reads as recipients trading up rather than landlords capturing the subsidy.
  In this model a 70% capture by a renter paying a third of income in rent
  would be ε ≈ 2, far above the control's range, which is right: a tax cut is
  not tied to rent.
- **Untied income, the relevant case.** A household spends only a slice of a
  marginal dollar on housing. Assume it is a quarter to a third, about what
  California renters spend on rent on average (an assumption, not a measured
  marginal share). With supply fixed in the short run that slice is bid into
  rent, so the short-run capture is about the same share, which is ε of 0.75
  to 1 for a renter paying a third of income in rent. As building responds the capture falls, and
  California's constrained supply means it falls slowly.

ε = 0.5 sits between a long run with some building and a short run with none.
Read 0 as "rents ignore the change", 1 as "the short run, in a market that
cannot build".

Baseline collections, from `data/baseline.json`:

| tax | base | rate | revenue | households | everyone else |
| --- | --- | ---: | ---: | ---: | ---: |
| Land value tax | $8.14T of land | 0.7306% | $59.5B | $47.1B (79.1%) | $12.4B |
| Buildings tax | $5.55T of improvements | 0.7306% | $40.6B | $32.1B (79.1%) | $8.5B |
| Personal income tax | the 2024 schedule | schedule | $130.0B | $130.0B (100%) | — |
| Sales and use tax | $897B of taxable spending | 8.85% | $79.4B | $47.6B (60%) | $31.8B |
| Capital gains | $177.0B realised | ordinary rates | $0 | — | — |
| **total** | | | **$309.4B** | **$256.8B** | **$52.6B** |

Under the Prop 13 baseline the property tax lines become $46.3B + $32.1B on
households' homes and $12.8B + $8.7B on everything else, the same $100.0B.

Sources: [data/baseline.json](data/baseline.json) ·
[BOE Table 4](https://www.boe.ca.gov/dataportal/dataset.htm?url=PropTaxAssessedValueSummary) ·
[CDTFA Publication 306](https://cdtfa.ca.gov/formspubs/pub306-2023-24.pdf)

## Capitalisation: land prices move with the land tax

Land cannot be made or moved, so a tax on it cannot be shifted: it is
**capitalised** into the land's price. Land is worth its rent after tax,
discounted:

```
V = R / (d + t)
```

Today's prices already carry today's rate `t0` (0.7306%), so under a land tax
`t` the same land is worth `k = (d + t0) / (d + t)` of today's value, with `d`
the discount rate, **4% by default** (a control, from 2% to 8%). `landFactor()`
in `taxes.js` computes `k` and it scales the land base everywhere: each
household's land, rented land, and the non-household residual. Three
consequences:

- **A land tax partly shrinks its own base.** At 2.3%, `k` = 0.751: land prices
  fall **25%**, **$2.03T** across the state. The tax raises **$140.6B**, not the
  $187.2B that 2.3% of today's $8.14T would. Revenue keeps rising with the rate
  but by less each step, and can never exceed the land's whole rent, $8.14T ×
  (4% + 0.73%) = $385B.
- **The yearly bill and the price fall are the same burden.** An owner's extra
  bill, `t × k × V0 − t0 × V0`, is exactly `d` times the fall in the land's
  price, `(1 − k) × V0`. Every view on the page shows the yearly bill; the land
  card also prints the price change, because that one-time loss lands on
  whoever owns land **on the day the tax is announced**, and a later buyer pays
  a lower price and so bears none of it. A static annual model cannot show that
  timing; the land card's number is the reminder.
- **Buildings are not capitalised.** They can be built and torn down, so a
  buildings tax moves construction and, through the pass-through control, rent,
  not a fixed price. The model holds building values fixed.

The same `t0` is used under the Prop 13 baseline. That is a simplification: a
Prop 13 buyer pays about the levy rate on the purchase price in year one and
less, relative to market, every year after, so the rate today's prices carry
is somewhere near 0.73% to 0.81% (what recent movers report) rather than
exactly 0.73%. At a 2.3% land tax the difference moves the price factor by
about 2%.

**What it does to a home.** The land card prints the median owner's change in
home value in the region on screen (`homeValueSummary()`): each owner's land
times `k − 1`, the building unchanged, over today's land plus building. The
dollar and percent medians are taken separately. Statewide, at the 4% discount
rate, the median owner's home ($700,000) loses about **7%** ($48,000) at a
1.46% land tax (double today's), **17%** ($116,000) at 3% and **24%**
($170,000) at 5%. Two things it leaves out: building values are held fixed
(above), and a buildings tax cut that comes with the land tax would, in the
short run, raise what an existing building is worth; and nothing here is a
forecast of the market, only the price the model's own capitalisation implies.

Under the Prop 13 baseline itself, today's bills are today's prices and `k` is
1. `capitalize: false` in `taxes.js` turns the whole mechanism off, which the
tests use to check the arithmetic against the linear model.

Sources: `taxes.js` (`landFactor`, `homeValueChange`, `homeValueSummary`)

## The indirect burden: landlords, business and shoppers

The burden views used to sum only what households bear **directly**, and that
made a land tax look like a free lunch. The scenario used throughout this
section is a land tax of **2.3%**, balanced with the page's default ticks
(income, sales, buildings and gains move): the balancer lands on buildings
0.35%, sales 6.52%, the income tax at ×0.838, and gains taken out of the
income tax at a 0% flat rate. At that point the payers are:

| bears it | today | land tax 2.3%, balanced |
| --- | ---: | ---: |
| households, directly | $235.4B | $211.3B |
| landlords of rented homes | $21.4B | $41.3B |
| owners of business property | $20.9B | $33.4B |
| shoppers, through sales tax on business purchases | $31.8B | $23.4B |
| state total | $309.4B | $309.4B |

$24B walks off the direct chart. But landlords and businesses are owned by
somebody, and in a distributional picture that somebody is mostly a household
near the top; and the sales tax a business pays on what it buys is in the price
of what it sells. So the three indirect segments are **allocated back**:

- **Landlord** (the part of a rented home's bill the tenant is not assumed to
  bear) and **business** (the land and buildings bill on property the sample
  cannot see) go to the households that own those assets, by the tax data and
  survey proxies below, with an explicit unassigned slice for owners who are
  not California households.
- **Consumer** (the non-household 40% of sales tax) goes to every household in
  proportion to its taxable spending. None of it is set aside for visitors or
  out-of-state buyers of California goods, which somewhat overstates what
  California households bear. An earlier version put this segment on business
  owners with the rest of the non-household column, which made cutting the
  sales tax look like a cut for the top decile.

The allocation is imputed, and it is the least certain thing on the page. Every
view that shows it says so, and shows it as a separate layer rather than folding
it into the direct bill.

### Between income classes: the tax data

IRS SOI Historic Table 2 for California, tax year 2022, the same file the gains
imputation reads, carries a "Total rental and royalty net income (less loss)"
row and a "Partnership/S-corp net income (less loss)" row for each AGI class,
each with a count of returns and an amount. Measured:

| AGI class | % of filers with rental income | % with partnership or S-corp |
| --- | ---: | ---: |
| $1–10k | 3.0% | 1.6% |
| $10–25k | 3.4% | 1.9% |
| $25–50k | 3.5% | 2.4% |
| $50–75k | 5.5% | 3.5% |
| $75–100k | 8.1% | 5.0% |
| $100–200k | 11.1% | 8.6% |
| $200–500k | 14.9% | 19.8% |
| $500k–1M | 23.3% | 37.1% |
| $1M+ | 35.5% | 60.8% |

Filers above $200k are 10% of California returns, hold 26% of the landlord
returns and 42% of the partnership returns, and take **70%** of positive rental
and royalty net income and **93%** of positive partnership income.

Those shares were misread once, and the way they were misread is worth keeping
in view: see *A column-alignment trap* above. Every figure in this table is from
the corrected reading, in which cells 3 to 11 of a data row are the nine AGI
classes.

One caution that stands: IRS net rental income is depreciation-suppressed
($10.1B of positive net income statewide, against a rental stock worth
trillions), so the allocation uses the **shares** and never the levels.

**The `$1–10k` fold, and why its stated reason was wrong.** The pipeline folds
the `$1–10k` class into `$10–25k`, leaving nine classes, and the plan justified
that by calling `$1–10k` an artifact of large rental and partnership losses
written against a tiny AGI. Measured on the corrected columns, that is not where
the large negatives are: they are in the **no-AGI column**, which is a separate
column and not one of the nine classes at all (partnership −$8.9B, rental
−$1.2B). The `$1–10k` class itself carries small negatives that round to −$0.0B
on both rows, and the share step floors a negative class to zero, so folding it
or leaving it in place moves a rounding error. The fold is what the shipped
vectors were built with and it is immaterial; the **reason** given for it was a
casualty of the column-alignment trap above, and it should not be repeated.

**The vectors as shipped.** These are the numbers in `data/baseline.json` and,
byte for byte, in `INDIRECT` in `taxes.js`, which a test pins to the file. A
household is in class *i* if its AGI is below `edges[i]`, and in the last class
otherwise; AGI here is income **plus** realised gains, because that is what AGI
is and because the top classes are exactly where the imputed gains live.

| # | AGI class | upper edge | landlord share | business share |
| ---: | --- | ---: | ---: | ---: |
| 0 | No adjusted gross income | $1 | 0.000000 | 0.000000 |
| 1 | $1 under $25,000 | $25,000 | 0.019474 | 0.000000 |
| 2 | $25,000 under $50,000 | $50,000 | 0.023105 | 0.002924 |
| 3 | $50,000 under $75,000 | $75,000 | 0.022354 | 0.006756 |
| 4 | $75,000 under $100,000 | $100,000 | 0.033745 | 0.009425 |
| 5 | $100,000 under $200,000 | $200,000 | 0.199619 | 0.049609 |
| 6 | $200,000 under $500,000 | $500,000 | 0.292347 | 0.161215 |
| 7 | $500,000 under $1,000,000 | $1,000,000 | 0.139565 | 0.167430 |
| 8 | $1,000,000 or more | — | 0.269792 | 0.602640 |

The landlord vector is each class's share of **positive** rental and royalty net
income ($15.6B statewide), the business vector its share of positive
partnership and S-corp income ($135.2B). Negative classes are floored at zero,
which is why the no-AGI class takes nothing. The vectors are published rounded
to six places and **normalised at the point of use**: six places of $55B is
$55,000, more than the "to the dollar" the tests ask for, so `normalized()`
divides by the sum when the allocation runs and the published numbers stay
identical to the file.

### Inside an income class: the survey data

The tax data is a marginal by income class, so on its own it would make the
allocation a smooth function of income: the scatter would band vertically and
the change-as-percent-of-income view would show a monotone curve partly because
we built one. So a class's total is spread across its households in proportion
to `weight × proxy`: `capIncome` for the landlord segment, `bizIncome` for the
business segment. Where a class's proxy sums to zero, the fallback is weight
alone, and that class's households are all assigned an equal share.

On the shipped sample **no class falls back**: every one of the nine holds
households and a positive proxy sum, the smallest being the $1M+ class with
49,288 weighted households, and the no-AGI class with 146,819. The fallback
path and the emptier one beside it (a class holding no households at all hands
its slice to the unassigned pile, which is what makes allocated plus unassigned
equal the segment total unconditionally) are exercised on a fixture in
`test/taxes.test.js` rather than by the shipped data.

### Why both, and what is left unassigned

The tax data is state-specific, not top-coded, and actually about rental
property, but it varies only by class. The survey data varies household by
household but is flatter where the two can be compared: the survey puts 62.5% of
`INTP` on the top decile of households, while the tax data puts 70% of positive
rental and royalty income on the filers above $200k, who are about a tenth of
returns. That gap is PUMS top-coding income, and `INTP` mixing widely-held
interest and dividends in with net rent. So: **the tax data sets the
class totals, and the survey data places them inside a class.** Neither half is
sufficient alone, and the shape you see is the product of the two.

The unassigned slice is the honest part. Some California land and business
capital is owned by people and institutions that are not California households:
out-of-state investors, funds, foreign owners, REITs and listed corporations. No
source splits California's rental and commercial property between resident and
non-resident owners, so the default is **35% unassigned** and it is a control
you can move from 0 to 100%. C-corporation ownership is in neither proxy, so
those owners fall into the unassigned slice by default.

The model side is `indirectSegments()` and `allocateIndirect()` in `taxes.js`:
the landlord segment is the part of a rented home's land and buildings bill that
pass-through does *not* put on the tenant, the business segment is
`stateRevenue()`'s non-household land and buildings, the consumer segment its
non-household sales tax, and `householdTaxes()` gains an `indirect` line that
is added into `total`.

**The same two columns with the allocation on**, at its 35% default, which is
what the app shows unless you turn it off:

| bears it | today | land tax 2.3%, balanced |
| --- | ---: | ---: |
| households, directly | $235.4B | $211.3B |
| households, indirectly (imputed) | $59.2B | $72.0B |
| owned outside California (unassigned) | $14.8B | $26.2B |
| state total | $309.4B | $309.4B |

Today, by segment, and how much of each lands on the top decile:

| segment | total | assigned to households | of which top decile |
| --- | ---: | ---: | ---: |
| landlord | $21.4B | $13.9B | $8.7B (62%) |
| business | $20.9B | $13.6B | $11.9B (88%) |
| consumer | $31.8B | $31.8B | $7.0B (22%) |

Under the balanced land tax the three are $26.9B assigned ($16.7B on the top
decile), $21.7B ($19.0B) and $23.4B ($5.2B). The business segment is the most
concentrated: its share vector puts 60.3% on the $1M+ class alone, which holds
**49,288 weighted households** in this sample. PUMS top-codes household income
near the state's 99.5th percentile, so the sample's top class is thinner than
the IRS's and its per-household figure correspondingly heavier. The views
therefore draw this layer as a decile total and as a colour, never as a
per-household number on the scatter's axis.

So the swap's arithmetic, honestly stated: it takes $24.1B off households'
direct bill. Counting what comes back to them indirectly, households go from
bearing $294.6B to $283.3B, an **$11.3B** cut rather than the $24.1B the
direct-only view shows, and $11.4B more ends up with owners who are not
California households, which is entirely a function of the 35% guess. That is
why the guess is a control and not a constant. (The rent rise, $1.8B, is a
transfer to landlords and is left out of both sides.)

**The indirect burden in the baseline, by decile.** Today's rates, allocation
on, before any change is made:

| decile | indirect, total | average per household | as a share of income |
| ---: | ---: | ---: | ---: |
| 1 | $0.6B | $408 | 4.42% |
| 2 | $1.6B | $1,157 | 4.00% |
| 3 | $2.1B | $1,526 | 3.23% |
| 4 | $2.8B | $2,017 | 3.06% |
| 5 | $3.1B | $2,304 | 2.70% |
| 6 | $4.3B | $3,149 | 2.94% |
| 7 | $4.6B | $3,332 | 2.48% |
| 8 | $5.9B | $4,299 | 2.50% |
| 9 | $6.8B | $4,968 | 2.15% |
| 10 | $27.5B | $20,111 | 4.31% |
| all | $59.2B | $4,325 | 3.21% |

**46.5% of the allocated burden is on the top decile**, down from 81.7% before
business sales tax was moved onto shoppers. The layer is now U-shaped as a
share of income: the ownership segments are steeply progressive, the consumer
segment is regressive, as sales tax is. With the allocation on, the top
decile's win under the balanced swap is **1.33%** of its income against 3.41%
with it off, and the share of households paying less is 71.2% against 72.5%.
None of that is measured. It is the IRS share vectors, the PUMS proxies and
the spending imputation, applied. Move the "owned outside California" control
and watch the ownership part scale: at 0% unassigned, households bear the
entire $309.4B.

One more thing that reads as a bug and is not. `indirectSegments()` reads the
pass-through controls, so raising "land tax passed to renters" to 100% correctly
shrinks the landlord segment to nothing: the tenant is then bearing that tax
directly, and there is nothing left for the landlord to bear. With the
allocation on and pass-through at 1, the page says landlords bear nothing,
which is what the model was asked.

Sources: [IRS SOI Historic Table 2, California](https://www.irs.gov/pub/irs-soi/22in05ca.xlsx) ·
[ACS PUMS person file](https://www2.census.gov/programs-surveys/acs/data/pums/2023/1-Year/csv_pca.zip) ·
[ITEP Who Pays? 7th edition](https://media.itep.org/ITEP-Who-Pays-7th-edition.pdf)

## Revenue neutrality and the balance solver

The revenue bar compares `stateRevenue()` under your rates against the
baseline's **$309.4B** and prints the gap. The Prop 13 baseline raises the same
total, so the target does not move with that switch. Balancing is **explicit, not
automatic**: nothing moves until you press **Balance budget**.

- **What moves.** The levers whose tick box is ticked. The boxes default to the
  levers you have *not* touched since the last balance, which is what makes the
  workflow "raise the land tax, press Balance, let everything else pay for it".
  You can override the ticks before pressing; a balance recomputes the defaults.
  With nothing ticked the button is disabled rather than silently doing nothing.
- **How it moves.** The gap is spread **equally in dollars** across the ticked
  levers. Each one is solved by bisection so that it absorbs `gap / n`, to a
  tolerance of **$0.1B**. Revenue is monotone in every lever, which is all
  bisection needs; it is linear in every lever but the land tax, whose base
  shrinks as it rises. If a lever cannot absorb its share, because its rate
  would go below 0 or above the cap, it takes what it can and the remainder is
  re-spread across the others, iterating until the gap is under $0.1B or nothing
  can move.
- **What each lever's solve actually changes.** The four rate levers move their
  own rate, capped at 0 to 20%. The income lever moves the **uniform
  multiplier** on every bracket rate, capped at 0 to 3. The gains lever's first
  move is to take gains **out** of the income tax, which is worth about $21B
  before its own flat rate raises anything.
- **The solver targets the change in the total, not in one tax's own line.**
  That is identical for four levers and the only honest reading for gains, whose
  first act is to remove revenue from the income tax.

Two rough edges worth knowing. The balancer can switch "tax as ordinary income"
off without being asked, because that is the gains lever's only move; the delta
slot says "out of the income tax" when it happens, but the checkbox does change
under your hand. And the four rate sliders stop short of the model's 20% cap (6%
for land and buildings, 15% for sales) so that today's 0.73% is not crammed into
the first 4% of the track, which means a balance can land a value past the end
of its own slider, where the handle pins at the maximum and only the number box
is right.

`balance()` takes about 1 to 1.5 seconds on the shipped sample, because it is
up to twenty rounds of bisection over 8,004 weighted households.

Sources: `taxes.js` (`solveOne`, `balance`), `trades-state.js` (the tick rules)

## The five views

One plot, one view at a time. Each subsection below is what the app renders in
the "What this shows" disclosure under that view, so **the heading text here has
to match the view's chip label exactly**: the page finds the section by slugging
the label it already has.

### Every household

**What it shows.** One dot per sampled household: income across, land under the
home up, coloured by whether the household's total across all five taxes goes up
or down under your rates. It is the texture view, the one that shows that "the
top pays more" is a statement about a cloud with exceptions in it, not about a
line.

**What goes in.** Every row of the sample, with its weight used for colour
counts but not for dot size. Both before and after bills come from
`householdTaxes()` with the rent response measured between them.

**What to distrust.** A dot is a sampled household standing for hundreds to
thousands of real ones, so a lonely dot at the top right is not one identifiable
person. Income is top-coded by PUMS, so the right edge of the cloud is
compressed. Land under a renter's home is imputed from rent at a 4% (coastal)
or 5% yield, so renters sit on a smooth curve that real parcels would not lie
on; they are drawn in the band under the plot rather than at a land value. Gains are
imputed onto a hashed subset, so a dot's vertical jump when the gains lever
moves is a property of the class, not of that household.

### Burden by income

**What it shows.** The **total** tax borne by each income decile, before and
after your rates, with the imputed indirect burden stacked, hatched, on top of
the direct bill. A total, not an average, because the question the view answers
is which tenth of households carries the revenue. **Show incomes** under the
plot prints the household income at each of the nine boundaries between tenths
(weighted quantiles of the region's households), here and in *Change as % of
income*.

**What goes in.** `aggregate()`'s deciles, which are **weighted** quantiles of
household income. The bars are *borne* incidence: pass-through applied, rent
response applied, non-household tax allocated only through the indirect layer.
They therefore sum to less than the revenue bar, and the gap is explained in
*Where the money comes from*.

**What to distrust.** The indirect layer is imputed twice over, by class from
tax data and within a class from a survey proxy, and its size moves directly
with the "owned outside California" control. Decile 1 contains households with
near-zero or negative reported income and very large housing wealth, a real
category in PUMS and a strange one in a bar chart. With a negative income tax
or a universal income, a tenth can be a net recipient of its direct bill, and
its bar then hangs below zero. And nothing here is a median:
these are averages, and the top decile's average is carried by its own tail.

### Change as % of income

**What it shows.** One diverging bar per income decile: the average change in
total tax under your rates, as a share of that decile's income, with the share
of the decile that pays **less** printed under the bar. This is the view that
answers "is this regressive", and it is the one to read first.

**What goes in.** The same decile aggregates as the burden view, divided by the
decile's own weighted income. The axis keeps zero inside the data's own range
rather than forcing symmetry, so a scenario where everybody gains does not waste
half the picture. When one bar is more than 2.5 times the next largest (in
practice the poorest tenth under a land tax), the axis is scaled to the rest,
that bar runs to the edge with a zigzag cut, and its value is printed beside
it: at 2.3% balanced it is +6.9%, which would otherwise flatten every other bar
to a sliver.

**What to distrust.** The denominator is *census* income, which is not adjusted
gross income and not a cash-flow measure; a retired owner with a $2M house and
$30k of income shows a huge percentage change on a small denominator, and a
land tax, which follows land rather than income, shows it most. In the 2.3%
scenario the poorest tenth's mean is +6.9% of income while 72% of its
households pay less. The mean bar and the share-ahead label can point in
opposite directions, and when they do the share-ahead label is usually the
more honest of the two. Both numbers are printed for that reason.

### Where the money comes from

**What it shows.** Two stacked bars, today against your proposal, of what the
state **collects**, one colour per tax, with the part billed to somebody who is
not a household drawn in the same colour, paler and hatched. With the allocation
on, a third bar sorts the same total by who bears it: households directly,
imputed back onto households (landlord, business and consumer segments
together), and owned outside California. This is the view that makes $309B
collected and $235B borne directly both true on one page.

**What goes in.** `stateRevenue()`, which is always **statewide**: the
household part measured over the whole sample plus the fixed non-household
residual bases. The region chips do not change these bars, because collections
are not regional; they drive the note under the bars instead. A negative
income tax or universal income large enough to outweigh the brackets turns the
income tax's household slice negative: it is drawn below zero, and a dashed
line marks the net the bar collects.

**What to distrust.** The non-household residual is a *residual*: whatever is
left of the state's land, improvements and taxable spending after the sample's
households are subtracted, and its land share is set equal to the state's by
the reconciliation in *Land under a home*. The 60/40 household/business split
of the sales tax is unpinned. And "billed to a business" is the first instance
only; where it lands after that is the indirect allocation's imputation, not
this view's claim.

### By who you are

**What it shows.** Three groups, owner under 65, owner 65+ and renter, with the
average change in dollars and the share of the group that pays less.

**What goes in.** `aggregate()`'s groups, the same borne totals as the burden
view, split by tenure and by whether anyone in the household is 65 or older.

**What to distrust.** This is where mean and median part company most: in the
2.3% scenario owners 65 and over average **+$3,005** a year while 40% of them
pay less, because a minority with a lot of land and little income carry the
mean. The share-ahead label next to each bar is what keeps that readable, and a
median change per group would be the better headline. The baseline matters
most here. Against the flat baseline, Prop 13's protection of long-tenured
owners is assumed away before the comparison starts; switch to **Prop 13 as
billed** and the owner 65+ bar grows to +$3,892, because replacing Prop 13
with market value is then part of the change.

## Your household

The "Your household" panel prices one household the reader describes, today
against the plan on screen and against every saved plan. It adds no tax rule
of its own: `household.js` turns what the reader types into **one row in the
sample's own schema** (the shape `decode()` returns) and runs it through the
same `householdTaxes()` as the 8,004 sample rows, with the page's assumptions.
What the reader does not know is filled in from the sample, per stratum, the
way the build imputed it for the survey households.

**Inputs.** Where you live (one of the sample's eight strata), own or rent,
household income, the number of adults, realised capital gains; for an owner
the home's market value, how to split it into land and building, the lot size
and (optionally) the Prop 13 bill; for a renter the monthly rent. Under
*Spending and other income*: taxable spending, interest, dividends and rent
received, and business income, all optional.

**Imputations.**

- **Owner land share, "Area average".** The stratum's owner land over owner
  value, weighted, from the sample: FHFA's county share, condos at half, scaled
  by the CLE reconciliation (alpha), exactly as under *Land under a home*.
- **Owner land share, "Building size".** The residual method: the building is
  worth its square footage times a **replacement cost per square foot, $300 by
  default** (an assumption the reader can change: roughly what a modest
  California home costs to rebuild, before any depreciation), and the land is
  whatever is left of the market value, bounded to 5% to 95% land (the build
  caps a household's land at 95% of value). An old house that would cost less
  to rebuild than new is under-depreciated by this, which puts too little of
  the value in land.
- **Owner land share, "My own share".** The reader's percent, as typed.
- **Lot size** enters no tax. It gives the land's price per square foot of lot,
  a check on whichever split was picked.
- **A renter's home.** A year of rent times the stratum's value per dollar of
  rent, which is the build's gross yield (4% on the coast, 5% inland, so 25 or
  20 times a year's rent), split at the stratum's renter land share.
- **Taxable spending, blank.** The weighted spending-to-income ratio of the 24
  sample households nearest that income. The build gives every household
  income times one flat share per ITEP income group, so this is the reader's
  own group's ratio, blended across two groups only at a boundary: about
  $34,500 at $75,000 of income and $48,400 at $150,000.
- **Prop 13 bill, blank.** The home's value times what the stratum's owners
  report paying as a share of their homes' value. Used only when Assumptions
  compare against Prop 13 as billed.
- **Filing status.** Joint from two adults up, single for one: a household of
  two or more adults is assumed to be a married couple filing jointly, which
  overstates a shared house's bracket room.

| Area | Owner land share | Rented home, value per $1 of yearly rent | Rented land share | Prop 13 bill, % of value |
|---|---:|---:|---:|---:|
| San Francisco | 66% | 25.0 | 76% | 0.79% |
| Bay Area, rest | 67% | 25.0 | 70% | 0.73% |
| Los Angeles County | 70% | 25.0 | 73% | 0.68% |
| San Diego | 56% | 25.0 | 58% | 0.67% |
| Sacramento | 36% | 20.0 | 37% | 0.78% |
| Fresno | 30% | 20.0 | 30% | 0.77% |
| Inland Empire | 40% | 20.0 | 40% | 0.77% |
| Rest of California | 51% | 23.4 | 53% | 0.69% |
| California | 58% | 24.0 | 62% | 0.71% |

**The bill.** Each line is the household's own `householdTaxes()` line:
the land value tax, the buildings tax (for a renter, the pass-through share of
the landlord's bill), the income tax net of any negative income tax and
universal income (the universal income paid per adult entered), sales tax on
the spending, the capital gains tax when gains leave the income tax, and for
a renter the rent rise. The rent rise uses the renters' gain **in the
reader's own stratum**, by rent tercile, as the plot does for a region.
**Passed-on taxes** is the indirect layer, shown only when it is switched on:
it is allocated over the whole sample for each rate set, and the reader's
household takes what one more household of its AGI class would
(`indirectFor()`): its spending's share of the consumer segment, and its
interest, dividend and rent income and its business income against its
class's totals for the landlord and business segments (or the class average
per household, where the class has none of that proxy). It is a household of
weight one, so it never moves the totals it is placed against. The home value
line is `homeValueChange()`: the land repriced by the capitalisation factor,
the building held.

**Saved households and share links.** A household is not part of a plan.
Households are saved by name in their own store, with "Example household" (an
LA owner, a $900,000 home, $120,000 of income, two adults) built in and
immutable, and the one household on screen is priced under every saved plan.
A share link carries the plan on screen (every plan field, the view and the
region) and the household, in readable query parameters.

## The six limits

These are the limits the app states on its own page, in this order, and they are
the ones that bound every claim above.

1. **No behavioural response.** Capital gains realisations are very sensitive to
   the rate, so a low gains rate overstates the revenue loss and a high one
   overstates the gain. Work, migration, construction and consumption responses
   are all absent. The land price is the one price that moves.
2. **The top 1% is understated.** PUMS top-codes income and reports no gains;
   the IRS imputation assigns gains statistically within AGI classes, not to
   actual households. The model's top decile pays **55%** of the income tax
   against the FTB's roughly 75% for the top 10%, and that gap is printed on the
   page rather than described.
3. **Where business taxes land is imputed.** Tax on rented and business
   property is put on its owners by IRS income-class shares and survey proxies,
   and sales tax on business purchases on shoppers by imputed spending. Neither
   is measured, and the unassigned slice is an admission that part of it cannot
   be placed at all.
4. **Prop 13 bills are self-reported.** Under the Prop 13 baseline, owners'
   bills are what the census survey says they pay, in brackets; the bill on a
   rented home or a shop is reported nowhere, so one residual rate stands in
   for all of them. The default flat baseline is a counterfactual nobody pays.
5. **One weak year for gains (2022)**, single-family land shares scaled to
   CLE's totals and applied to all housing, renters' homes imputed from rent at
   a 4% or 5% yield, and taxable spending imputed from national income-group
   averages.
6. **One price effect only.** Land prices fall as the land tax rises, at the
   discount rate you set, and the one-time loss to today's owners is printed
   on the land card rather than drawn. Building values, construction and wider
   prices do not respond; rent moves only through the elasticity control.

Not modelled at all: the federal deduction for state and local taxes, which
changes what some itemising households net out of a state tax change.

## Changelog

One line per session that changed this document or anything it describes.

- **Session 9 (WP1).** The sample grew improvements, spending and gains; the
  five-tax model and `data/baseline.json` were written; the baseline became
  $305.0B collected and $249.8B billed to households.
- **Session 10 (WP2).** The page shell, the revenue bar, the balancer and its
  tick rules.
- **Session 11 (WP4).** Five views in one array, the bracket graph in the income
  card, the Sources disclosure rendered from `data/baseline.json`, and the end
  of the v2 pages.
- **Session 12 (WP6).** This document, `md.js`, the Methodology tab and the tab
  bar. Written from the plan and the design log; every number that needs WP5's
  run is marked with a TODO in place. The IRS class shares were corrected
  mid-session after the column-alignment trap above was found in the plan's own
  table; the earlier figures (27% of returns above $200k, 97% of rental income)
  appear nowhere in this file.
- **Session 12 (WP5).** The pipeline gained `capIncome` and `bizIncome` from
  the PUMS person file (appended at indices 14 and 15; the file went 370KB to
  406KB), `data/baseline.json` gained the nine IRS AGI classes and the two
  share vectors, and `taxes.js` gained `indirectSegments()`,
  `allocateIndirect()` and an `indirect` line on `householdTaxes()`, off unless
  the caller asks for it. The IRS loader now cross-checks every row it reads
  against the sheet's own printed state total, which is what would have caught
  the column shift.
- **Session 13 (WP7).** The allocation reached the page: two Assumptions
  controls (assign on by default, 35% unassigned), the indirect layer drawn as
  its own shade in *Burden by income*, a third "who bears it" bar in *Where the
  money comes from* whose unassigned slice makes the stack reach the state
  total, and the household total behind *Every household*, *Change as % of
  income* and *By who you are*, each with a line saying the layer is imputed and
  from where. Each view also renders its own section of this file under the
  plot. Every marker WP6 left behind was replaced with a measured number, and a
  test now fails if one comes back. The `$1–10k` fold
  was kept but its stated justification was corrected: the large negatives are
  in the no-AGI column, not in that class.
- **Session 14.** A methodology review, acted on. Business sales tax is passed
  forward to shoppers (a third, consumer segment, allocated by spending)
  instead of being put on business owners. Land prices capitalise the land tax
  (`landFactor`, a discount-rate control at 4%), so a land tax shrinks its own
  base. A second baseline, **Prop 13 as billed**, from each owner's reported
  `TAXAMT` (appended to the rows as `propTax`) and a residual rate on everything
  else. Renters' homes at a 4% yield in the twenty coastal counties. The land
  split reconciled with CLE's totals (`alpha` 1.1847), which ends the
  "households hold 93% of buildings" artifact. Sources pinned: the property
  tax levy to BOE Table 4 ($100.026B), sales tax to CDTFA Publication 306
  ($79.4B), and $13.69T re-cited to CLE, not the BOE. Every download's size and
  SHA-256 is recorded, the live BOE table is committed as a snapshot, and the
  build was checked to be byte-for-byte deterministic. The change-as-%-of-income
  view clips an outlying bar and prints its value.
- **Session 15.** A negative income tax (rate up to 25%, break-even $50,000
  joint) and a universal income (per adult, filing status standing in for the
  adult count), both paid through the income tax and both off today. *Burden by
  income* and *Where the money comes from* draw negative values below zero.
  Saved plans carry both.
- **Session 16.** The negative income tax became a negative bracket (a share
  of the first `upTo` dollars of income, $20,000 joint by default, no
  break-even or phase-out). The universal income can be taxed as income (a
  box under it, off by default). The land card prints the median owner's
  change in home value from the land tax's capitalisation.
- **Session 17.** The "Your household" panel: one household the reader
  describes, as a sample row, priced today, under the plan and under every
  saved plan; saved households; share links carrying the plan and the
  household. The universal income is paid per adult for a row that carries an
  adult count (only the reader's own), and `indirectFor()` places one
  household outside the sample against an allocation over it.
- **Session 18.** One Share button in the plan bar, with a box for whether the
  link carries your household (off by default); the panel says when it still
  holds the example household. The stacked bars got one distinct colour per tax
  (buildings purple, gains green, sales ochre) and a hatch, not just a paler
  shade, for the part that is not a household's own bill. The two decile views
  can print the income at each decile boundary. ε is now described as what it
  is, an elasticity of rent to renters' income, with the evidence that brackets
  it.
