| file | blocks | passed | failed | skipped |
|---|---|---|---|---|
test-ai-badges.R |
2 | 15 | 0 | 0 |
test-compute.R |
9 | 216 | 0 | 0 |
test-data_sheets.R |
9 | 45 | 0 | 0 |
test-figures.R |
22 | 76 | 0 | 0 |
test-ingest_excel.R |
5 | 21 | 0 | 0 |
test-py-parity.R |
2 | 56 | 0 | 0 |
test-site.R |
10 | 100 | 0 | 0 |
test-snapshots.R |
28 | 34 | 0 | 0 |
test-sql-steps.R |
6 | 18 | 0 | 0 |
test-sql-workbook.R |
3 | 41 | 0 | 0 |
test-sql.R |
3 | 38 | 0 | 0 |
test-tables.R |
14 | 127 | 0 | 0 |
test-verify.R |
6 | 7 | 0 | 0 |
| total | 119 | 794 | 0 | 0 |
Prop 40, BSZ analysis: the materials
Every script, test, data file and source behind the explorer, the report and the slides
BSZ analysis of California Proposition 40: Overview · Open Output: Explorer · Open Analysis: Report and Slides · Open Materials (this page is its guide)
Also in this project: Comparison overview · JR analysis overview
This page is a guide to the Open Materials layer (the repository) of the BSZ analysis (Boll, Saez and Zucman, BSZ, plus the Galle, Gamage, Saez and Shanske (GGSS) expert report): what to download, what to run, and what the checks found. Everything lives in one repository, fhoces/opa-prop40, under bsz-analysis/. The tables on this page are built from the files themselves when the page is rendered, so they cannot fall out of date with the code without a re-render showing it.
Rebuild everything
git clone https://github.com/fhoces/opa-prop40 && cd opa-prop40/bsz-analysis
curl -L -o original-materials/BSZ_MainTablesFigures.xlsx \
https://eml.berkeley.edu/~saez/BSZ_MainTablesFigures.xlsx # check the SHA-256 below
Rscript -e 'targets::tar_make(names = !tidyselect::any_of(c("report_html","report_pdf")))'
Rscript tools/site-test-results.R # the full test suite; writes site/data/test-results.csv
cd site && quarto render repro.qmd && quarto render materials.qmd
cd slides && Rscript -e 'rmarkdown::render("slides.Rmd")'The pipeline is an R {targets} project (an R package that runs the pipeline’s steps in order and records which outputs are current). The default workbook vintage (the dated version of the workbook a number comes from) is the August 2026 revision with the data appendix of 2026-10-08 (SHA-256 below); BSZ_VINTAGE=september selects the data appendix of 2026-09-04 and BSZ_VINTAGE=may the May version. CAWTBSZ_MATERIALS points the pipeline at the sources if they are not in original-materials/.
Every computation also has a Python twin in py/, with the same function names as in R/. After pip install -r requirements.txt, the command python py/run_export.py (about 2 seconds) writes the same results to export/py/, and tests/testthat/test-py-parity.R checks each file against R’s. The report’s code folds show both languages.
Tests
Last run: 2026-10-16, August vintage: 794 expectations passed, 0 failed, in 119 test blocks. Of these, 694 belong to the reproduction itself and 100 to this site: they check that the explorer reproduces Table 5 to 1e-12, that explorer/grid.js is the exporter’s own output, and that every number typed into a hand-written page still matches the pipeline. GitHub Actions rebuilds the pipeline and runs the suite on every push that touches bsz-analysis/ (.github/workflows/bsz-ci.yml); it does not render the Quarto pages or the slides.
Scripts
| file | lines | what it does |
|---|---|---|
R/code_listing.R |
24 | helper for code listings in the original report |
R/compute_billionaires_ca_inctax.R |
736 | CA income tax of all billionaires (FTB + Pareto), and all taxes |
R/compute_data_sec_agg.R |
46 | yearly totals from the billionaire list (drops rows repeated in the 2026-09-04 copy) |
R/compute_pareto.R |
163 | Pareto extrapolation of missing billionaires; the Laffer curve |
R/compute_shortrunseries.R |
282 | wealth growth panel and the 2025 snapshot |
R/compute_tab5.R |
144 | Table 5: the estimating function the explorer also runs, and the four estimate rows of the one-time tax |
R/compute_top4taxes.R |
133 | taxes of the top 4 by year, 2004-2025 |
R/data_sheets.R |
193 | 14 extractors, one per workbook sheet the pipeline reads |
R/excel_cells.R |
22 | single-cell and row/column readers shared by the compute files |
R/export_contract.R |
104 | Export contract: the only files the comparison layer (comparison/) reads from |
R/figures.R |
725 | the twelve ggplot figures |
R/form4_basis.R |
132 | R twin of py/form4_basis.py: capital gains on Form 4 sales, the sequential |
R/ingest_excel.R |
83 | reads the workbook: sheet reader, vintage switch, source directory |
R/render.R |
75 | writes tables and figures to outputs/ |
R/run_sql.R |
191 | R twin of py/run_sql.py: run a shared .sql file against |
R/site_exports.R |
263 | this site's data: the dials, the grid (computed by compute_tab5.R), input origins |
R/tables.R |
718 | the six gt tables |
R/verify.R |
59 | the test helper that compares R with the workbook's cached cells |
R/vintage.R |
206 | everything that differs between the May and August workbooks, in one place |
R/workbook_db.R |
126 | The public workbook's two large input sheets in SQLite, for the shared |
Also: _targets.R (the pipeline: which function builds which result), tools/site-test-results.R (runs the suite for this page), and the site sources site/repro.qmd, site/materials.qmd, site/slides/slides.Rmd, site/index.html and site/explorer/index.html.
Data files the site publishes
| file | rows | columns | contents |
|---|---|---|---|
grid.csv |
1920 | 16 | every cell of the explorer: six inputs and seven outcomes |
inputs.csv |
20 | 5 | every input of the one-time estimate, with value, origin label and source |
tab5.csv |
4 | 8 | Table 5, the four estimate rows, as the pipeline computes them |
tab5-vs-printed.csv |
28 | 7 | every Table 5 cell against the digit printed in the paper |
leavers.csv |
7 | 4 | the seven named leavers of Table 5 rows 3 and 4 |
test-results.csv |
119 | 7 | one row per test block from the last full run |
Every file except test-results.csv is written by a target in _targets.R (site_grid_csv, site_inputs_csv, site_tab5_csv, site_tab5_printed_csv, site_leavers_csv; the explorer’s grid.js by site_grid_js). None is edited by hand.
Sources
The authors’ workbook and paper are not redistributed here. The manifest records where each file came from, its SHA-256 and its terms:
| file | provider | obtained | SHA-256 (first 12) | terms |
|---|---|---|---|---|
BSZ_MainTablesFigures.xlsx |
Boll Saez Zucman (via Saez lab, UC Berkeley) | public-download 2026-10-14 | ea0c14107e10 |
do-not-redistribute |
september-2026/BSZ_MainTablesFigures.xlsx |
Boll Saez Zucman (via Saez lab, UC Berkeley) | public-download 2026-09-22 | c236cc941337 |
do-not-redistribute |
BSZ26CAbillionaires.pdf |
NBER (Boll Saez Zucman) | public-download 2026-09-22 | ee1f2ea5a06c |
do-not-redistribute |
may-2026/BSZ_MainTablesFigures.xlsx |
Boll Saez Zucman (via Saez lab, UC Berkeley) | public-download 2026-05-26 | cffe04bd950f |
do-not-redistribute |
may-2026/BSZ26CAbillionaires.pdf |
NBER (Boll Saez Zucman) | public-download 2026-05-26 | cd8588edf529 |
do-not-redistribute |
additional-documentation/galle-gamage-saez-shanskeCAbillionairetaxJuly26.pdf |
Galle, Gamage, Saez, Shanske | public-download 2026-09-22 | 91d124417e5d |
do-not-redistribute |
additional-documentation/galle-gamage-saez-shanskeCBTAcontrollingshares.pdf |
Galle, Gamage, Saez, Shanske | public-download 2026-09-22 | 22d7f330ed06 |
do-not-redistribute |
additional-documentation/galle-gamage-shanskeCBTAlegal.pdf |
Galle, Gamage, Shanske | public-download 2026-09-22 | ac75de294f93 |
do-not-redistribute |
additional-documentation/GGS26props41-42.pdf |
Galle, Gamage, Shanske | public-download 2026-09-22 | 97364601fbc3 |
do-not-redistribute |
additional-documentation/responsetorauh26.pdf |
Galle, Gamage, Saez, Shanske (response to Rauh et al.) | public-download 2026-09-22 | c58b25e3540d |
do-not-redistribute |
additional-documentation/saez-tpe26-presentation.pdf |
Saez | public-download 2026-09-22 | 38c5cfd22421 |
do-not-redistribute |
author-shared/2026-09-23_bsz-replication-code-data/ |
Boll, Saez, Zucman (author-shared) | author-shared 2026-09-23 | 15dc5f6c3db5 |
confidential: use for re-analysis permitted; no public sharing |
Full rows, including what each source feeds: DATA-SOURCES.csv; the column definitions: DATA-SOURCES.md. The author-shared bundle is confidential. The SQL in sql/ rebuilds the workbook’s data sheets from it and checks them against the public workbook; only that comparison is reported, and none of the bundle’s contents is committed or shown.
What the checks found
The code reproduces the paper’s published results from the authors’ public workbook: Table 5, the other tables and figures it builds, every variation of Table 5 the paper prints, and the other numbers checked on the checks page. A figure counts as reproduced when it rounds to the printed digit, or when the paper prints it one unit lower in the last digit (note 1). A figure the text derives counts as reproduced when the inputs the text states give it.
The seven notes below are kept for transparency. Each records a place where the paper’s text, its tables and the workbook describe a step differently. None is a failure to reproduce a printed result. They are of three kinds, and each note states its kind:
- Rounding (note 1): the paper prints a value at a different rounding from its workbook.
- Small numerical difference (notes 6 and 7): the text uses a first-order formula, and the workbook’s exact curve gives a slightly different figure. Each note gives the size.
- Documentation (notes 2, 3, 4 and 5): the text, a table label and the workbook describe one calculation differently, or use different inputs for it. Each printed result reproduces from the inputs stated beside it.
An earlier version of these pages called the first note a pair of cells that “differ from the workbook”, and notes 5 to 7 numbers that “differ” or are “close”. They were reclassified on 2026-10-16 under the standard first applied to the JR analysis; feedback/007-2026-10-16-bsz-reproduction-standard/REPORT.md gives each item’s old and new label. The notes cover the current workbook only, so a note on four rows that the 2026-09-04 copy of the workbook listed twice was dropped on 2026-10-17: the 2026-10-08 update lists each row once.
Errors in this OPA, found and fixed
- A display error in this reproduction’s Tables 1 and A1: the display put Panel B’s values under Panel A’s headers and formats and kept the May workbook’s labels (GDP for AGI, 2025 for 2026); fixed in the display code on 2026-10-15.
- Appendix Table A1 at first used 44 years, so three cells of the annualized row printed lower than the paper. It now uses 43, as the paper and the workbook do (note 4), and a test checks each cell of the row.
- A malformed row in this OPA’s own source manifest: two
providerfields contained an unquoted comma, which shifted every later column for any CSV reader; quoted on 2026-09-23. - Stale positions in this OPA’s code. When the authors updated the workbook, 184 of this reproduction’s tests failed on row positions and constants that this OPA’s code had fixed at the earlier layout. All were fixed (
VERIFY-AUGUST.md).
Not reproduced
The paper’s Figure 8 and Appendix Figure A1 (wealth relative to AGI) have no builder yet. The raw data behind the workbook is taken as given.
BSZ analysis of California Proposition 40: Overview · Open Output: Explorer · Open Analysis: Report and Slides · Open Materials (this page is its guide)
Also in this project: Comparison overview · JR analysis overview
OPA done by Fernando Hoces de la Guardia, using agentic coding tools