# Portability — building an accountability dataset when the agency won't

This repository is a template. The pattern it runs works on any policy fight where two sides cite numbers and the responsible agency has published none. Point it at a new subject and the structure holds.

## The pattern

1. **Find the vacuum.** The reportable finding is often not a scandal but an absence: a figure everyone argues about and no one has compiled. Name it in one sentence.
2. **Build the ledger the agency didn't.** Decide the unit of analysis (here, a development), then the stages that separate what the dueling claims blur (built / building / proposed / avoided). Code every case to a stage, each row carrying a `source_id`.
3. **Archive before you cite.** Capture every source document and hash it (`capture.py`). A citation without a captured, hashed file is not a source.
4. **Preserve the dispute.** A `contested_claims.csv` maps each claim to its claimant, its source, what the source actually says, and a forensic verdict. You are not adjudicating; you are showing where each number rests and where it stops.
5. **Make trust mechanical.** `build.py` recomputes the headline figures from the ledger; `verify.py` confirms every claim resolves to an archived source; `gate.py` refuses to ship on any gap. A reader runs `check.py` and needs no faith in the reporter.
6. **Present it three ways.** A reader-facing piece (`site/`), a data appendix (`appendix-dataviz/`), and a source index (`05-sources/`) — the same evidence for the skimmer, the analyst, and the editor.

## What to change per subject

| Slot | This case | Swap for |
| --- | --- | --- |
| The vacuum | affordable units IZ has produced | the missing count in your subject |
| Unit of analysis | a development | a contract, a vote, a permit, a case |
| Stages | built / building / proposed / dodged | whatever your dueling claims conflate |
| Sources | studies, memos, developer pages | the documents both sides cite |
| Harness | reused unchanged | reused unchanged |

The harness in `03-harness/` is subject-agnostic; only `sources.json` and the CSV schema change. Copy the folder, empty `02-data/` and `01-sources-archive/raw/`, rewrite `sources.json`, and the gate works on the new case the day you start capturing.

Reporter: Brian Nuckols · Memory Hole / Hesitation Media.
