# Methodology

How the project ledger was built, what each figure means, and where it stops.

## The problem the dataset solves

Inclusionary zoning has been law in at least one Pittsburgh neighborhood since 2019, yet at the September 2025 hearing the City Controller told council that neither side had definitive proof of its effects, because the underlying data is thin. Supporters counted the pipeline; opponents counted completions; the two never met. The dataset here does not pick a side. It disaggregates the count so a reader can see exactly which units each side is counting.

## The coding decision: four stages, not one number

The core file, `02-data/iz_projects.csv`, assigns every inclusionary-zoning-relevant development to one stage:

- **completed** — a finished building whose affordable units can be occupied today.
- **under_construction** — permitted and building, not yet occupiable.
- **proposed** — announced or entitled, not under construction; may never finish.
- **downsized** — redrawn to 19 units to fall below the 20-unit trigger, delivering zero affordable units.

A parallel field, `iz_status`, records whether the mandate actually applies: **subject** (a market-rate building the rule touches), **exempt** (e.g. a 100% LIHTC project the rule does not cause), or **bunched_out** (downsized below the threshold). The distinction matters: the 35-unit Sixth Ward Flats is affordable housing, but it is a tax-credit project that would have been built regardless, so it is not attributable to inclusionary zoning and is coded `exempt`.

`03-harness/build.py` reduces the ledger to the headline tally and asserts the two load-bearing figures — 35 completed IZ-attributable units, 3 bunched-out projects — so neither can drift silently.

## What the "35" is, precisely

Thirty-five is the number of deed-restricted affordable units in the one completed market-rate project in a covered neighborhood that the mandate produced: Arsenal 201 Phase II. It is the honest floor of the count. It is also, by design, the figure that ignores everything not yet finished, which is why supporters reject it as the measure.

## Sources and the trust layer

Every figure carries a `source_id` resolving to `01-sources-archive/sources.json`. `capture.py` fetches each source, validates that the bytes are the document claimed (a PDF must begin `%PDF-`; a bot-challenge page is quarantined, not archived), and writes a `.sha256` sidecar. `generate_manifests.py` reduces those hashes to `MANIFEST.md` and `PROVENANCE.md`, which contain no wall-clock, so an unchanged archive regenerates to identical bytes and any diff is a real change. `verify.py` re-hashes offline; `gate.py` refuses to pass while any source is uncaptured, any manifest stale, or any claim unresolved.

## Limits, stated plainly

- The proposed-pipeline figure (100-plus affordable units across five Oakland projects) is hearing testimony from Andrea Boykowycz. Two of the five projects are named in the public record; three are not, and the total is not independently itemized here.
- The opposition's 30% construction-decline figure is reproduced from the Pro-Housing Pittsburgh study, which states its own result is not statistically significant given a 103-project citywide sample.
- This archive documents the units and the dispute. It does not resolve whether inclusionary zoning raises or lowers housing supply; the evidence for that claim, on both sides, is what the record shows to be insufficient.

The counting stops where the documents stop. That boundary is the finding.
