10 — NYC enrollment, capacity and utilization
What this covers. NYC's school-building utilization data — the School Construction Authority's Enrollment, Capacity & Utilization Report, the "Blue Book" — what it measures, how it is loaded, what a twelve-year panel of it shows, and how far it has been checked.
Summary. NYC publishes the data through one authoritative publisher, with a
published utilization figure rather than a derived one, and 99.6–99.7% of its
organizations with an enrollment resolve to a DBN in every year (§3.1). The
warehouse carries it at school grain (school_year_metrics), loaded by
scripts/loaders/nyc-bluebook.ts (§7, §8), and
/methodology/analysis/enrollment-capacity renders it, building grain
included, from a committed packet built from the source (§9). The panel runs
twelve of the thirteen school years from 2013-14 to 2025-26 — seven read
from NYC Open Data, five parsed from the SCA's own annual
PDFs (§2.1). The thirteenth, 2020-21, the SCA never published. The binding
constraints are not access, identity resolution or coverage. They are that a
school's facts are split across one row per building, and that NYC has no
public closure list to validate against.
Where the numbers come from. Figures in §1–§4 are measured by
probe/bluebook_util.py, which fetches the Socrata sources, reads the committed
PDF parses and reprints all of it (python docs/design/probe/bluebook_util.py).
The exceptions are named where they appear: the §2.1 parse figures are in the
gate report beside each parsed CSV, the §4.3 segment table is the packet's
decomposition.segments (scripts/analysis/nyc-capacity-packet.ts), the
Miami-Dade and Philadelphia figures in §4.2 are those cities' packets, and the
§4.2 charter and District 75 counts are a separate count over the same 2024-25
join. §5 checks the result against sources that did not come from the SCA
(probe/bluebook_verify.py): the enrollment numerator reconciles with the
federal CCD copy as well as the DOE's own file does, and the capacity
denominator is 92% explained by the physical room inventory at a stable ~32 sq
ft per seat. The Pre-K measurements — the room-set variant in §5.2 and
everything in §5.4 — are separate computations that neither probe runs; the
method is stated beside each. Nothing here is quoted from a press account.
Companion documents: the Miami-Dade analysis this is modelled on is
docs/cities/miami/06_enrollment_capacity_closures.md; the validation taxonomy
is 05_validation_spec.md; what is still open across the capacity work is
docs/capacity-utilization-gaps.md.
1. The source
The SCA's Enrollment, Capacity & Utilization Report — the "Blue Book" — is NYC's counterpart to FISH, the Florida Inventory of School Houses, which is the facilities inventory Miami-Dade's capacity figures come from (the Miami-Dade doc named above defines the Florida terms used here). It is on NYC Open Data as three datasets:
| Dataset | What it is | State |
|---|---|---|
gkd7-3vk7 | Enrollment Capacity And Utilization Reports | live, last updated 2026-09-10; 20,754 rows across 7 snapshots |
q9xk-w9iv | ... Historical by Organization | retired 2015; 2,658 rows, one vintage. Carries the pre-2014 capacity formula |
hq56-zhrp | ... Historical by Building | retired 2015; same vintage, building grain |
The SCA also posts the report as a PDF each year it publishes it. The five school years Socrata does not carry are read from those files and committed beside the extract (§2.1).
gkd7-3vk7 carries both grains in one row: building enrollment / target
capacity / utilization, and the organization's own enrollment / target capacity
/ utilization within that building. Two adjacent datasets: wavz-fkw8 (DOE
Building Space Usage: every room, its dimensions and its function, updated
2026-01), which §5.2 tests capacity against, and 32rn-zwi7 (Transportable
Classroom Unit removals, the NYC analogue of Miami's relocatables), which
nothing here uses.
What NYC has that Miami does not
- The utilization figure is published, not derived. Miami's analysis has to
carry three separate numerators — COFTE (the state's capital-outlay
full-time-equivalent count), October headcount and the county GIS layer's
enrollment count — because each of its three publishers divides a different
count. NYC has one publisher, and it states the figure. For the
~85% of organizations that occupy a single building, the published figure
equals
round(100 × enrollment / capacity)within 1 percentage point for 100% of schools in every one of the twelve snapshots, maximum disagreement 0. This is validation check (iv), the computed-values check of the (i)–(iv) taxonomy in05_validation_spec.md: the published utilization recomputed from enrollment and capacity. It passes on the raw data, and the loader runs it before it writes anything. - The enrollment numerator is the DOE's own register count. Matched by DBN
against the DOE Demographic Snapshot, the median absolute difference is
exactly 0 in every one of the twelve snapshots, with 82–95% of schools
matching to the student. The Blue Book and our existing
total_enrollmentare the same number, so utilization enters the warehouse without an enrollment reconciliation step. - Building grain. 38.5–42.1% of NYC school buildings house more than one organization — the low end is 2013-14, the high end 2025-26, so this is a slow rise, not a constant. That range is over buildings carrying both an enrollment and a capacity (1,311–1,334 per year), which is the universe every figure in this doc and on the page uses. The loader prints 35.7–41.3% for the same quantity because it reports over every building in the extract (1,383–1,466); the two are different denominators, not a disagreement. Co-location is structural here in a way it is not in Miami-Dade, and the Blue Book reports both grains natively.
What NYC has that is worse
- The panel has one hole — twelve school years, and 2020-21 was never published (§2). Five of the twelve are absent from NYC Open Data and are read out of the SCA's PDFs under a two-parser gate (§2.1), which is more machinery than a Socrata pull.
- No closure reference (§6).
2. Which years the panel covers
The vintage key is not a school year. For the seven Socrata snapshots it is a
posting date, and the lag from count to posting is not constant — it runs from
about three months to about eighteen. For the five snapshots read from the PDFs
it is the audited-register date the report itself states (10/31/<year>),
because a PDF has no posting date. Either way the key is an identifier for the
vintage, and the school year beside it is measured, not read off it.
The measurement: the probe joins each snapshot to every year of the DOE Demographic Snapshot, matched on DBN, and takes the year minimising the median absolute per-school enrollment difference. The minimum is 0 students in all twelve cases, and the runner-up year is 18–24 students away, so the assignment is unambiguous:
data_as_of | school year | median diff (students) | % exact | n | citywide enrollment | read from |
|---|---|---|---|---|---|---|
| 2014-10-31 | 2014-15 | 0 | 92% | 1,690 | 1,029,321 | SCA PDF |
| 2015-04-27 | 2013-14 | 0 | 90% | 1,654 | 1,022,505 | Socrata |
| 2017-09-12 | 2015-16 | 0 | 89% | 1,698 | 1,035,660 | Socrata |
| 2018-01-08 | 2016-17 | 0 | 94% | 1,703 | 1,033,647 | Socrata |
| 2019-01-31 | 2017-18 | 0 | 95% | 1,715 | 1,025,875 | Socrata |
| 2019-10-31 | 2019-20 | 0 | 95% | 1,698 | 999,453 | SCA PDF |
| 2019-12-18 | 2018-19 | 0 | 95% | 1,688 | 1,012,330 | Socrata |
| 2022-10-31 | 2022-23 | 0 | 92% | 1,681 | 892,729 | SCA PDF |
| 2023-01-04 | 2021-22 | 0 | 95% | 1,706 | 915,272 | Socrata |
| 2023-10-31 | 2023-24 | 0 | 94% | 1,687 | 896,571 | SCA PDF |
| 2024-10-31 | 2024-25 | 0 | 95% | 1,698 | 889,640 | SCA PDF |
| 2026-09-09 | 2025-26 | 0 | 82% | 1,698 | 862,834 | Socrata |
Rows are in the probe's order (section B), which is key order and not school-year order. That the two differ — the 2014-10-31 key carries 2014-15 while the later 2015-04-27 key carries 2013-14 — is the reason the mapping is measured rather than sorted. The five PDF vintages are stamped by the same procedure as the seven Socrata ones and score the same way: median 0, 92–95% exact, runner-up margins of 18–23 students against 20.5–24 for the Socrata seven (§2.1).
2020-21 is not published. The SCA never posted it. Three independent lines
of evidence: no file of that name has ever been archived on the SCA's blob store
or on nycsca.org; the archived filename inventory runs Blue Book 2019-2020
straight to Blue Book 2021-2022; and the SCA's own file-listing API
(getlistings?catName=29), in an archive capture from September 2022,
enumerates seven year-categories from 2013-14 to 2019-20 with no 2020-21 slot at
all. The panel therefore covers every year the SCA published, and the 2019-20 →
2021-22 step in §4.3 spans the one it did not.
2.1 The five years read from the PDFs
Socrata carries seven vintages. The other five years are parsed from the SCA's
PDFs by pipeline_nyc/parse/bluebook.py, which targets the report's "Target
Calculation By Building" section — the Socrata extract's own grain, one row per
(building, organization). Output is committed at
data/cities/nyc/reference/parsed/bluebook_<year>.csv with a
bluebook_<year>.gate.json beside it.
| year | key | PDF(s) | rows | organizations | buildings | gate mismatches |
|---|---|---|---|---|---|---|
| 2014-15 | 2014-10-31 | 2014-2015BlueBook.pdf | 2,717 | 1,844 | 1,465 | 0 |
| 2019-20 | 2019-10-31 | Blue Book 2019-2020.pdf | 3,157 | 1,811 | 1,397 | 0 |
| 2022-23 | 2022-10-31 | Blue Book 2022-2023.pdf | 3,106 | 1,802 | 1,383 | 0 |
| 2023-24 | 2023-10-31 | Blue Book 2023-2024.pdf | 3,121 | 1,786 | 1,385 | 0 |
| 2024-25 | 2024-10-31 | Blue Book 2024-2025.pdf | 3,121 | 1,778 | 1,383 | 0 |
The building counts here are over every building id in the parse, the wider of the two universes §1 distinguishes — not the 1,311–1,334 buildings carrying both an enrollment and a capacity that §4.1 tabulates.
The two-parser gate. Following pipeline_miami/parse/fish_los.py, two
extractions that share no code are run over the same pages and must agree
before anything is written: parser A places pdfplumber word boxes against
column anchors taken from each page's own header row (canonical — this is what
gets committed), parser B reads the same pages through camelot's stream
flavor, which infers columns from whitespace. The gate requires equal record
counts and cell-for-cell agreement, in order, on all thirteen identifier and
numeric fields — geo_dist, bldg_id, org_id, organization_name,
bldg_enroll, target_bldg_cap, target_bldg_util, org_enroll,
org_target_cap, org_target_util, prek_cap and the two cluster-room
columns. All five years pass with zero cell mismatches. bldg_name is
compared and reported but not gated, as fish_los.py gates only the first line
of its wrapped facility name. Here the reason is parser B: camelot truncates a
building name that wraps, so a disagreement there is a property of parser B
rather than evidence about the data (213–353 soft mismatches per year, all of
that kind; gate.soft_mismatches in each gate report).
The control. 2025-26 is the one year published on Socrata and available as a PDF, so the parser is run on it and the result compared with the extract it should reproduce. 3,132 parsed rows against 3,132 published, no key present on only one side, no duplicate keys, and 43,700 of 43,848 cells identical (0.338% divergence). Running the parsed rows through this repo's own transform reproduces Socrata's answers: the same 1,776 organizations, the same 1,384 buildings (again the wider universe), and an identical check (iv) — 1,496/1,496 single-building organizations within 1 pp at maximum 0 pp, split-site 51/209 at maximum 75 pp.
The 148 divergent cells are three understood groups, none of which changes a figure in this document:
- 124 cells (62 rows × 2 columns) — blank versus zero. The report prints a
blank where the published extract carries a
0, in the PK-capacity and cluster-rooms-needed columns, on split-site organizations. The ink is not on the page, so the parse reads them as absent rather than inventing a zero. The blank-versus-zero rule the parser does apply — if any of the three "+" columns carries a value, the blanks among them are zeros; if all three are blank, all three are absent — is exact on all 1,660 rows where anything is printed. 62 of 3,132 rows is 2.0%, and it is confined toprek_capacityandcluster_rooms_needed(§7), neither of which enters the utilization denominator or any distribution below. - 18 cells (6 rows × 3 columns) — repeated building columns. The published
extract blanks the building columns on a row where the parse repeats them.
rollUpBuildingstakes the first complete row, so both sides produce the same building record. - 6 cells — whitespace. Five building-name cells covering three distinct names (one of them repeated on three rows), and one organization name.
2014-15 exists in two editions, and both are parsed. The SCA issued that
year as the citywide Classic Edition and again as a City Council Edition split
into five per-borough files. Both go through the same two parsers and are
compared on the (building, organization) key. This is a stronger check than the
gate — the gate reads one document twice, this reads two documents — and the
two agree on 2,717 rows with no key present in only one, and on every figure
in ten of eleven fields; target_bldg_util agrees on 2,716 of 2,717, the sole
exception being X965/X997, where the Classic edition prints a zero the City
Council edition leaves blank.
The Classic edition is the one loaded, because its first column is the
geographic district the Socrata extract carries. The City Council edition
heads that column CC Dist — the council district — and a year loaded from it
would carry no geo_dist at all; the parser drops that column rather than
misfiling a council district as a geographic one. The comparison is recorded in
bluebook_2014-15.gate.json under cross_edition_check.
Three of the five PDFs (2019-20, 2022-23, 2023-24) do not resolve through the
SCA's own file API — its records for them point at no file — and are fetched
from Internet Archive captures, each verified byte-identical against a second,
independent capture. Checksums and the retrieval route for each file are in
data/cities/nyc/sources/sca_bluebook_<year>/.
3. Two hazards for a loader
3.1 The join key is the org code, not the DBN and not geo_dist + org_id
The Blue Book keys on org_id — a borough letter plus three digits (M015),
not a DBN. The obvious reconstruction, geo_dist + org_id, is wrong:
geo_dist is the geographic district of the building, which is not the
administrative district for D75 special education, D79 alternative programs, or
charters. It matches only 89.0% of 2025-26 organizations. The 10.8% it misses
are not missing schools — they are 01M094 → 75M094, 01M973 → 79M973,
01M080 → 84M080.
Keyed on the org code alone, against the union of our directory seed and every
Demographic Snapshot year (2,236 DBNs), the match rate is 99.6–99.7% in every
one of the twelve years. Only 4 org codes out of 2,232 map to more than one DBN
in that union (K594, K646, M505, M610), and the packet drops those four
rather than guessing. The persistent unmatched are a handful of adult-education
and citywide programs.
The loader joins against the warehouse's schools table instead and skips a
code only when it is ambiguous there; resolving one would take an entry in
ORG_CODE_DBN_OVERRIDES (scripts/loaders/_bluebook.ts), which is empty.
Production's schools table (2,131 DBNs, built from the 2019-20 School
Locations extract) holds one DBN for each of the four, so the loader writes them
to 13K594, 17K646, 03M505 and 04M610, whose names match the Blue Book's
organization names.
3.2 A school split across buildings gets one row per building
14.0–19.2% of organizations occupy more than one building in every
snapshot, and each of their rows carries only that building's share of the
school's enrollment and capacity. Annex rows (the 9xx building codes) often
carry a null capacity, while the utilization column on such a row can be the
org-wide figure rather than that building's.
Read any single row and the school is misstated. P.S. 163X, for example, appears as 404 students against 276 seats in building X163 plus 185 students and a null capacity in X933; the published 213% belongs to neither row on its own.
It is the hazard a loader is most likely to get wrong. Summing enrollment and capacity across an organization's rows before dividing is what makes the enrollment agree with the Demographic Snapshot exactly for 82–95% of schools (§2), and it gives 100% of matched schools a capacity in every year (probe section D); read row by row, an annex row carries students and no seats.
4. What the data says
4.1 Utilization is falling, and the shape of the distribution has changed
School grain, rolled up across buildings, target capacity:
| year | n | p10 | p25 | median | p75 | p90 | <50% | <33% | >100% | citywide (Σ/Σ) |
|---|---|---|---|---|---|---|---|---|---|---|
| 2013-14 | 1,741 | 55 | 71 | 91 | 111 | 131 | 6.4% | 2.4% | 36.6% | 93.7% |
| 2014-15 | 1,753 | 58 | 75 | 95 | 116 | 139 | 5.8% | 1.8% | 42.8% | 96.7% |
| 2015-16 | 1,743 | 56 | 74 | 94 | 115 | 140 | 6.7% | 1.9% | 42.0% | 95.9% |
| 2016-17 | 1,716 | 55 | 74 | 93 | 115 | 136 | 6.4% | 1.3% | 41.1% | 95.1% |
| 2017-18 | 1,715 | 54 | 72 | 92 | 113 | 134 | 6.8% | 1.5% | 38.8% | 93.6% |
| 2018-19 | 1,697 | 55 | 72 | 91 | 112 | 132 | 6.8% | 1.5% | 37.8% | 92.5% |
| 2019-20 | 1,706 | 53 | 70 | 91 | 113 | 135 | 7.5% | 1.4% | 37.7% | 92.4% |
| 2021-22 | 1,704 | 47 | 64 | 83 | 102 | 121 | 11.9% | 3.2% | 26.8% | 84.4% |
| 2022-23 | 1,702 | 45 | 62 | 82 | 102 | 121 | 12.7% | 3.5% | 26.7% | 84.0% |
| 2023-24 | 1,704 | 46 | 63 | 82 | 103 | 122 | 12.3% | 3.4% | 27.3% | 84.5% |
| 2024-25 | 1,702 | 45 | 61 | 80 | 101 | 120 | 13.3% | 3.6% | 26.2% | 83.1% |
| 2025-26 | 1,698 | 42 | 58 | 78 | 98 | 116 | 15.5% | 4.8% | 21.9% | 80.3% |
The same years at building grain, which is the grain NYC plans on:
| year | buildings | median | <50% | <33% | >100% | citywide (Σ/Σ) | multi-org buildings |
|---|---|---|---|---|---|---|---|
| 2013-14 | 1,311 | 96 | 3.2% | 1.0% | 43.9% | 92.9% | 505 (38.5%) |
| 2014-15 | 1,320 | 100 | 3.3% | 0.8% | 49.2% | 95.9% | 535 (40.5%) |
| 2015-16 | 1,323 | 99 | 4.5% | 1.3% | 48.3% | 95.8% | 540 (40.8%) |
| 2016-17 | 1,320 | 98 | 4.8% | 1.1% | 47.1% | 95.1% | 530 (40.2%) |
| 2017-18 | 1,326 | 97 | 5.1% | 1.4% | 45.7% | 93.5% | 536 (40.4%) |
| 2018-19 | 1,323 | 95 | 5.6% | 1.4% | 42.9% | 92.5% | 531 (40.1%) |
| 2019-20 | 1,324 | 95 | 4.9% | 1.1% | 43.6% | 92.3% | 533 (40.3%) |
| 2021-22 | 1,327 | 86 | 8.6% | 2.0% | 30.5% | 84.3% | 543 (40.9%) |
| 2022-23 | 1,323 | 85 | 9.8% | 2.3% | 30.7% | 84.0% | 547 (41.3%) |
| 2023-24 | 1,322 | 86 | 9.3% | 2.5% | 30.9% | 84.4% | 548 (41.5%) |
| 2024-25 | 1,329 | 84 | 9.5% | 2.3% | 29.1% | 83.1% | 557 (41.9%) |
| 2025-26 | 1,334 | 81 | 11.5% | 3.0% | 25.3% | 80.3% | 561 (42.1%) |
End to end that is median 96 → 81, share under 50% 3.2% → 11.5%, share over 100% 43.9% → 25.3%, citywide 92.9% → 80.3%. Multi-organization buildings run 38.5% in 2013-14, then 40–41% through 2021-22, then 41.3–42.1% — a slow rise with year-to-year wobble rather than a constant or a clean trend (complete buildings; §1 explains why the loader prints a lower range over a wider universe).
Two movements, not one. The under-50% group rose from 6.4% to 15.5% of schools — a factor of 2.4 — and the over-100% group fell from 37% to 22%. The shape of the distribution changed, not just its level: in 2013-14 the over-capacity tail was the larger of the two by a factor of 5.7, and in 2025-26 it is larger by 1.4. Which of the two tails matters more is a judgement about what a building is for, not something these figures settle.
The panel locates the change. The school-grain median is flat at 91–95 from 2013-14 through 2019-20, is 83 by 2021-22, and then drifts down — 82, 82, 80, 78. The under-50% share behaves the same way: 5.8–7.5% through 2019-20, 11.9% at 2021-22, then 12.7, 12.3, 13.3, 15.5 — the one step back is 2023-24, and it is 0.4 points. So the level shift sits entirely in the 2019-20 → 2021-22 interval, which spans the unpublished 2020-21, and what follows it is a drift rather than a second step. The panel cannot say which part of that shift is the pandemic itself and which is the trend that continues through it, because the year in between is the one the SCA did not publish.
4.2 Against Miami-Dade and Philadelphia
Miami-Dade, 2024-25, 316 district-run regular schools, October headcount ÷
permanent FISH capacity (data/analysis/miami-enrollment.json → utilization):
median 66.7%, 21.2% below 50% (67 of 316), 4.7% below one-third (15 of
316), district-wide 69.7%.
NYC in the same school year, 1,702 schools: median 80%, 13.3% below 50%, 3.6% below one-third, citywide 83.1% (2025-26: 78%, 15.5%, 4.8%, 80.3%).
NYC's median school is fuller than Miami-Dade's — 80% against 66.7% — and its citywide figure is 13.4 points higher. The tails are not close: Miami-Dade's under-50% share is 7.9 points higher, and its share below one-third is also higher (4.7% against 3.6%). NYC's under-50% share is moving toward Miami-Dade's (6.4% in 2013-14, 13.3% in 2024-25, 15.5% in 2025-26), but on the common year it is 7.9 points below.
This comparison is indicative, not exact. Miami-Dade's denominator is permanent FISH capacity; NYC's is SCA target capacity. The universes differ: Miami-Dade's figure is 316 district-run regular schools; NYC's is the 1,702 organizations in DOE buildings whose org code resolves to exactly one DBN, co-located charter schools (about 110) and District 75 programs (about 60) included. Both numerators count enrolled Pre-K children (NYC also 3-K, §5.4); NYC's target capacity also counts Pre-K rooms, and whether Miami-Dade's FISH capacity counts Pre-K stations is not established. §4.4 measures how much the denominator choice alone moves the answer — 2.4 points (2013-14, 1,747 schools), about a third of the 7.9-point NYC–Miami-Dade under-50% gap in 2024-25.
Philadelphia in the same year, measured in
docs/cities/philly/06_enrollment_capacity_utilization.md, has the largest low
tail of the three (24.7% of 215 district sites below 50%, 7.9% below
one-third); its median site (67.1%) is level with Miami-Dade's median school.
Philadelphia's numerator adds allotted Pre-K seats rather than enrolled
children. NYC has the fullest buildings of the three and the only long history;
Philadelphia has the largest low tail and the only published closure decision
list. That doc carries the three-way table and its caveats.
4.3 It is students leaving, not seats being built
Continuing buildings only (1,273 present in both 2018-19 and 2025-26), additive decomposition of the change in Σenrollment / Σcapacity:
| enrollment | 1,001,480 → 847,345 (−15.4%) |
| capacity | 1,082,413 → 1,049,116 (−3.1%) |
| utilization | 92.5% → 80.8% (−11.8 pp) |
| enrollment effect (capacity held fixed) | −14.2 pp |
| capacity effect (enrollment held fixed) | +2.5 pp |
The SCA's target-capacity total fell over the period, and a smaller denominator raises utilization — by 2.5 pp. The entire decline and more is enrollment. A framing that attributes NYC's emptying buildings to overbuilding is not supported by this data.
Two limits on that reading. The panel is continuing buildings only, so seats added in new buildings are outside the decomposition. And target capacity is a planning construct: a fall in it is equally consistent with rooms taken out of instructional use, a reclassification, or a change in the formula, and nothing here separates those. "Seats were removed" is one reading of the capacity term, not a measurement.
The panel carries five of the six intermediate years — every one except the
unpublished 2020-21 — so the endpoints can be read against the path between
them. The same split on each consecutive published pair (the packet's
decomposition.segments):
| span | buildings in both | utilization | change | enrollment effect | capacity effect |
|---|---|---|---|---|---|
| 2018-19 → 2019-20 | 1,316 | 92.5% → 92.4% | −0.1 pp | −1.2 | +1.0 |
| 2019-20 → 2021-22 (two years) | 1,312 | 92.3% → 84.4% | −7.9 pp | −7.9 | 0.0 |
| 2021-22 → 2022-23 | 1,314 | 84.3% → 84.1% | −0.2 pp | −2.1 | +1.9 |
| 2022-23 → 2023-24 | 1,317 | 84.0% → 84.5% | +0.4 pp | +0.4 | +0.1 |
| 2023-24 → 2024-25 | 1,311 | 84.5% → 83.4% | −1.1 pp | −0.9 | −0.2 |
| 2024-25 → 2025-26 | 1,319 | 83.1% → 80.5% | −2.6 pp | −2.5 | −0.1 |
| 2018-19 → 2025-26 | 1,273 | 92.5% → 80.8% | −11.8 pp | −14.2 | +2.5 |
Each segment is computed on the buildings complete in both of its endpoint years, so the seven continuing sets differ, a year's utilization reads slightly differently as a segment's start and as the previous segment's end (84.4 against 84.3 at 2021-22), and the segment effects are not required to sum to the whole-span effects. The 2019-20 → 2021-22 segment is two school years wide because it spans the unpublished 2020-21; every other segment is one.
Three things the endpoint comparison does not show:
- Most of the decline is one step, not a slope. The 2019-20 → 2021-22 segment alone moves −7.9 pp against a whole-span −11.8 pp (not a partition, for the reason above, but the same order). The year before it moves −0.1 pp and the two after it move −0.2 and +0.4.
- One segment reverses. 2022-23 → 2023-24 is +0.4 pp, on a +0.4 pp enrollment effect: enrollment in continuing buildings rose 0.5% that year. It is the only rise among the six segments, it is small, and the two after it resume falling, at −1.1 and −2.6 pp.
- The capacity term changes sign. Over the whole span capacity contributes +2.5 pp — capacity fell, which raises utilization — but that is an early-period effect. Capacity falls in the first four segments, through 2023-24 (+1.0, 0.0, +1.9, +0.1 pp), and rises slightly in the last two (−0.2, −0.1 pp, on capacity up 0.2% in each). A shrinking denominator describes the early part of the panel, not the latest two years.
What the panel cannot separate is a pandemic effect from the trend running through it: the single largest segment is the one that spans the year the SCA did not publish, and it is two years wide.
4.4 Which capacity you divide by moves the answer
The retired "historical capacity" series is the pre-2014 formula, published for the same schools in the same year (2013-14). Two universes are involved and they are not the same size: 1,767 schools carry a capacity on both bases, while 1,747 also carry a utilization on each — a school needs an enrollment as well as a capacity to have one.
| statistic | universe | value |
|---|---|---|
| target ÷ historical capacity | 1,767 | median 0.917, p10 0.804, p90 1.022 |
| utilization gap (target − historical) | 1,747 | median +7 pp, p10 −2, p90 +21 |
| share below 50% | 1,747 | 8.8% historical → 6.4% target |
That 2.4-point swing is about a third of the 7.9-point NYC–Miami-Dade gap in §4.2 (2024-25). This is the NYC form of Miami's "utilization has three numerators" problem, at the same order of magnitude. A page names its denominator in the figure, not in a footnote.
4.5 Where it is concentrated
2025-26, school grain, by community school district:
| district | schools | utilization | share <50% |
|---|---|---|---|
| 16 (Bed-Stuy) | 30 | 45.6% | 46.7% |
| 32 (Bushwick) | 30 | 57.4% | 36.7% |
| 1 (Lower East Side) | 32 | 58.0% | 34.4% |
| 23 (Brownsville) | 32 | 58.6% | 40.6% |
| 5 (Harlem) | 34 | 59.3% | 29.4% |
| 17 (Crown Heights) | 54 | 64.3% | 38.9% |
| 18 (East Flatbush) | 41 | 65.0% | 34.1% |
| 14 (Williamsburg/Greenpoint) | 47 | 66.2% | 25.5% |
| ... | |||
| 22 (Sheepshead Bay/Midwood) | 40 | 95.9% | 7.5% |
| 25 (Flushing) | 47 | 100.7% | 0.0% |
| 26 (NE Queens) | 40 | 102.4% | 2.5% |
| 20 (Bay Ridge/Sunset Park) | 48 | 103.8% | 6.2% |
District aggregates run 45.6% to 103.8% — a 58-point span, against a school-level p10–p90 in the same year of 42 to 116, or 74 points. District 16 (45.6%, 2025-26) is 24 points below Miami-Dade's 2024-25 district-wide 69.7% and has the largest low tail of any district, 46.7% of its schools under 50%; District 20, a few miles away, is over capacity. A citywide average describes neither.
These are Σ/Σ aggregates, so they are mechanically narrower than the school distribution; that they still span most of it is the point. How much of the school-level spread lies between districts and how much within them is not measured here. (Neighborhood labels are annotation, not data.)
4.6 Does low utilization predict a school disappearing?
Negative result first, because it constrains the analysis. The DOE Demographic Snapshot cannot supply a closure reference: each published file restates every year to one fixed school universe, so a school that closes is retro-removed from the earlier years too. Within-file exits are 0 in nine of twelve year pairs across the three publication vintages and never exceed 2. Exits are visible only across vintages.
The one non-circular test available uses DBNs listed in the 2013-14 sheet of the 2018-vintage Socrata publication that are absent from the 2026-vintage InfoHub file — DOE on the outcome side, SCA on the predictor side. Base disappearance rate over twelve years: 3.4% of 1,653 schools.
| cut point | flagged | disappeared | rest | lift | Fisher p |
|---|---|---|---|---|---|
| utilization < 33% | 18 | 5.6% | 3.4% | 1.65× | 0.46 |
| utilization < 50% | 73 | 8.2% | 3.2% | 2.60× | 0.034 |
| utilization < 66% | 266 | 9.4% | 2.2% | 4.21× | 2.6e-07 |
| utilization < 75% | 442 | 6.8% | 2.1% | 3.16× | 1.8e-05 |
| enrollment < 200 | 145 | 9.0% | 2.9% | 3.14× | 0.00073 |
| enrollment < 300 | 349 | 7.7% | 2.2% | 3.48× | 5.3e-06 |
| enrollment < 400 | 599 | 6.8% | 1.4% | 4.81× | 1.5e-08 |
| enrollment < 500 | 844 | 5.9% | 0.7% | 7.99× | 8.4e-10 |
Two things worth carrying forward:
- The conventional thresholds separate least. "Under one-third" flags 18 schools and does not separate at all (p = 0.46). "Half-empty" is marginal (p = 0.034). The strongest cut is around two-thirds — which is also where Miami's Strategic Plan baseline sits, arrived at independently. The lift table carries this better than any single threshold.
- Utilization is not simply a restatement of size, but the evidence is
mixed. Conditioned on enrollment,
<66%utilization still separates among schools of 300+ students (4.02×, p = 0.002); among schools under 300 it is marginal (2.18×, p = 0.044). Size on its own is the stronger single predictor here (enrollment < 500: 7.99×), as it is in Miami-Dade, where size predicts the district's own closure and review lists.
Both results are weaker evidence than Miami's: the reference conflates closure, merger, grade truncation and rename, and the predictor is twelve years upstream of the outcome. It is a proxy for a closure list, not a substitute for one.
5. Verification against other sources
probe/bluebook_util.py establishes what the SCA publishes and that it is
internally consistent. probe/bluebook_verify.py asks the separate question:
is it right, judged against sources that did not come from the SCA.
5.1 The enrollment numerator, against an independent publisher
The Blue Book count reaches NCES only through DOE → NYSED SIRS → NCES CCD — a different chain from the DOE Demographic Snapshot. District schools only (charter BEDS codes do not encode a DBN), ~1,520 schools per year.
| year | comparison | n | median |diff| | r |
|---|---|---|---|---|
| 2018-19 | Blue Book vs CCD | 1,517 | 3 students | 0.9998 |
| Blue Book vs Snapshot (control) | 1,690 | 0 students | 0.9944 | |
| CCD vs Snapshot (control) | 1,509 | 3 students | 0.9998 | |
| 2021-22 | Blue Book vs CCD | 1,521 | 4 students | 0.9997 |
| Blue Book vs Snapshot (control) | 1,708 | 0 students | 0.9921 | |
| CCD vs Snapshot (control) | 1,523 | 4 students | 0.9997 |
The control row is what makes this readable. CCD differs from the DOE's own Snapshot by the same 3–4 students, with the same correlation, as it differs from the Blue Book. The Blue Book is therefore indistinguishable from the DOE register as the federal chain sees it; the residual is a CCD-side count-date difference, not a Blue Book error. Verified.
5.2 The capacity denominator, against the physical room inventory
Target capacity is a formula output. The DOE Building Space Usage dataset
(wavz-fkw8, 1.02M rows, nine vintages) is a physical census: every room, its
dimensions, its function. Same publisher, different process — so the question
is whether capacity tracks floor area, and how tightly.
The instructional room set (28 of 112 functions) and the two statistics were
fixed before any comparison was run. The set holds rooms whose function names a
K-12 teaching space; it does not include the Pre-K rooms (PRE-K FULL DAY,
PRE-K HALF DAY) or 3K CLASSROOM. Target capacity does count Pre-K rooms
(§5.4), so the table covers the K-12 part of what the formula counts.
| year | buildings | sq ft per target seat | seats per instructional room | R² of capacity on area |
|---|---|---|---|---|
| 2018-19 | 1,321 | median 31.8 (IQR 28.2–36.1) | 20.9 (IQR 17.9–23.7) | 0.9225 |
| 2021-22 | 1,319 | median 31.9 (IQR 28.1–36.4) | 20.7 (IQR 17.6–24.0) | 0.9275 |
| 2025-26 | 1,331 | median 32.6 (IQR 28.8–36.6) | 20.4 (IQR 17.6–23.6) | 0.9217 |
As a sensitivity, the same computation with the PRE-K FULL DAY and PRE-K HALF DAY rooms added to the set covers 1,329 / 1,325 / 1,338 buildings, with a
median of 33.2 / 33.7 / 34.2 sq ft per seat and R² of 0.9215 / 0.9225 / 0.9180
(2018-19 / 2021-22 / 2025-26). The probe does not run this variant.
Target capacity is 92% explained by instructional floor area, and the implied constant — about 32 square feet per seat on the K-12 room set (33–34 with Pre-K rooms counted) — is stable across three vintages eight years apart. Buildings whose instructional space is ≥80% elementary-band rooms run higher, 34.4 sq ft per seat (n=165), consistent with smaller class sizes in the lower grades. Target capacity tracks instructional floor area (R² 0.92–0.93 in each vintage), consistent with floor area divided by a stable space standard.
Caveat: most middle- and high-school rooms carry the unbanded label "REGULAR CLASSROOM", so the per-band split resolves only the elementary case (n=11 and n=2 for middle and high). The banded figure is elementary-only evidence.
5.3 Cross-dataset consistency
The retired by-building extract (hq56-zhrp) against the live dataset's
2013-14 snapshot: 1,382 buildings, 100% exact agreement on enrollment,
r = 1.0000. Same publisher, so this only rules out extract and transcription
error — but on these 1,382 buildings it rules it out, and it confirms the
retired extract is the vintage it claims to be (it differs from the live
dataset only in the capacity formula, which is the §4.4 finding).
5.4 Pre-K in the numerator and the denominator
Both halves of NYC's ratio include Pre-K. The measurements in this subsection are separate computations that neither probe runs; each states its method.
- The numerator includes 3-K and Pre-K students. Blue Book organization enrollment, summed across building rows, was compared with the 2024-25 DOE Demographic Snapshot, matched by org code to the Snapshot's DBNs (1,702 schools, the same count as §4.1). Of the 693 with 3-K or Pre-K students in the Snapshot, 671 have a Blue Book enrollment equal to the Snapshot total including those grades, and none equals the total excluding them. Across the 1,702, 3-K and Pre-K students are 3.47% of the summed enrollment: 3-K 0.94%, Pre-K 2.53%.
- Target capacity counts Pre-K rooms. The SCA's method (2024-25 report, pages 9–10) counts rooms in use for instruction "(Pk-5, …)" and gives each room the lower of two figures: a maximum by room type — Pre-K full-day 18, Pre-K half-day 36 (18 a.m., 18 p.m.), kindergarten and grades 1–3 20, grades 4–8 23, grades 9–12 25 — and the room's area divided by 35 sq ft for Pre-K and kindergarten rooms or 20 sq ft for grades 1–8. A full-day Pre-K room therefore counts at most 18 seats, and fewer if it is under 630 sq ft.
- A regression shows the same. Building target capacity, regressed by least squares with no intercept on counts of rooms of 240 sq ft or more in nine grouped room types (K–3, grades 4–8, high school, unbanded general classroom, special education, specialty rooms, Pre-K full-day, Pre-K half-day, 3-K), gives 16.4, 13.0 and 15.4 seats per full-day Pre-K room in 2018-19, 2021-22 and 2025-26 (1,329, 1,324 and 1,338 buildings), against 15.4, 13.6 and 14.5 per K–3 room. The coefficient depends on how the rooms are grouped; what the regression establishes is that it is of the same order as a K–3 room's, where rooms left out of target capacity would give a coefficient near zero.
- The PK Cap column is part of target capacity, not an addition to it. In 2024-25 all 645 buildings carrying a PK Cap have a building target capacity equal to the sum of their organizations' capacities, and none equals that sum plus PK Cap; PK Cap is no larger than the organization's target capacity for all 659 organizations carrying one.
- 3-K rooms are not established. The SCA's text names Pre-K rooms and is
silent on 3-K. The regression above gives 11.4 seats per
3K CLASSROOMin 2025-26, the only one of the three vintages with that room type, with a wide standard error; the statements in this doc cover Pre-K rooms only. - Pre-K centres carry no figures of their own. The five organizations named
as Pre-K centres in the 2024-25 Blue Book (for example
DISTRICT 2 PRE-K CENTERandMOSAIC PRE-K CENTER) have no organization enrollment and no organization capacity, so they have no utilization and are outside the school grain.
Philadelphia's utilization numerator adds the Pre-K seats allotted to a site
rather than enrolled children, so the two cities' figures are on different
Pre-K bases (docs/cities/philly/06_enrollment_capacity_utilization.md).
5.5 What is not verified
- No second publisher states NYC school capacity. CCD, NYSED and the city's other datasets carry enrollment, not seats. §5.2 is the strongest available test and it is a within-publisher consistency check, not independent confirmation.
- Charter enrollment is outside §5.1 (charter BEDS codes do not encode a DBN).
- 2020-21 cannot be checked at all, because the SCA never published it (§2).
- The five years read from the PDFs are verified against the published extract only by proxy: the control is 2025-26, the one year available on both routes (§2.1). No published extract exists for 2014-15, 2019-20, 2022-23, 2023-24 or 2024-25 to compare against directly, so what is established is that the parser reproduces Socrata where both exist, not that each PDF year is right. Their internal checks — the two-parser gate, check (iv), the date-stamp measurement — all pass, and all are within-source.
- The Pre-K measurements (the §5.2 variant and §5.4) are not reproduced by either probe; each is a one-off computation over the same published files, with its method stated beside it.
6. The main gap: no closure record
Miami's analysis has MiamiSchoolEvent — a hand-built table of board actions,
each row citing a PDF, and that table is what every closure claim is validated
against. NYC has no public equivalent. A catalog search returns nothing for
school closings, mergers, or Panel for Educational Policy actions; the only
adjacent dataset, q7ra-ebu4 ("Underutilized Space Report"), is a one-off 2015
list built on the 2013-14 Blue Book.
The NYC source is the PEP's own record: significant-change proposals,
Educational Impact Statements, and the monthly vote calendar, all PDF. Building
a SchoolEvent table from those is the single largest piece of work in this
track and the one that gates any claim of the form "the schools the city
actually closed were the ones at X% utilization."
Until it exists, a page on this data is descriptive — this is how full each building is, and how that has changed — not predictive.
7. Metrics and schema
The NYC figures go into existing tables (school_year_metrics, keyed on
metric_definitions), so NYC adds no table and no column. The six keys are
defined in scripts/loaders/metric-definitions-capacity.ts, subdomain
Facilities, all at school grain:
| metric_key | unit | source | notes |
|---|---|---|---|
target_capacity | COUNT | Blue Book org_target_cap, summed across the school's building rows (§3.2) | includes Pre-K rooms (§5.4) |
utilization_pct | PERCENT | derived: summed enrollment ÷ summed capacity | equals the published figure for single-building schools (§1); marked derived |
utilization_pct_published | PERCENT | Blue Book org_target_util | stored only where a school prints one figure; a split-site school prints one per building row |
prek_capacity | COUNT | Blue Book prek_cap | part of target capacity (the Pre-K rooms' seats), printed separately; adding it to target_capacity counts those seats twice. On ~2% of rows in a PDF year this is absent where Socrata would carry a 0 (§2.1) |
cluster_rooms_reported / cluster_rooms_needed | COUNT | Blue Book | art/music/science room counts — a separate crowding measure. cluster_rooms_needed carries the same ~2% blank-versus-zero caveat (§2.1) |
The historical-capacity basis of §4.4 is not stored as a metric; it is in the
packet's capacity_definitions block, 2013-14 only.
Every key is NEUTRAL: none of them is "better" in a direction. The percentile
batch (scripts/loaders/compute-percentiles.ts) leaves the Facilities keys
out, so they carry no percentile and no outlier ranking. The movers page, which
sorts by year-over-year change rather than by percentile, lists them like any
other metric.
Building grain is not stored. The loader rolls the building rows up in memory
— to sum a school split across buildings (§3.2), for check (iv) and its
split-site report, and for the co-location counts it prints — and writes only
the school facts above. Building figures are never written onto a school's
DBN: 42.1% of buildings hold more than one school in the latest year, so any
citywide aggregate would count those buildings more than once. The page's
building-grain figures (§4.1, §9) come from the packet, which reads the source.
What the Blue Book carries at building grain, and the schema that would hold
it, are in the gap register, docs/capacity-utilization-gaps.md §10.
8. What is built
| Piece | Where | State |
|---|---|---|
| PDF parser and parsed panel | pipeline_nyc/parse/bluebook.py → data/cities/nyc/reference/parsed/; PDF provenance in data/cities/nyc/sources/sca_bluebook_<year>/ | five years, each behind a passing two-parser gate (§2.1) |
| Schema | none: the facts are rows in school_year_metrics (§7) | — |
| Metric catalogue | scripts/loaders/metric-definitions-capacity.ts | six keys (§7); run before the loader |
| Loader | scripts/loaders/nyc-bluebook.ts, with the pure transform in _bluebook.ts and the PDF years read by _bluebook_recovered.ts | loads all twelve years; refuses an unmapped vintage, a parsed year whose gate did not pass, or a year failing check (iv) |
| Transform tests | tests/nyc-bluebook-transform.test.ts | verbatim source rows for the snapshot → year mapping (§2) and the two loader hazards of §3: the org-code join and the split-site roll-up |
| Packet | scripts/analysis/nyc-capacity-packet.ts → data/analysis/nyc-enrollment-capacity.json | --check regenerates and diffs against the committed file |
| Page | /methodology/analysis/enrollment-capacity | renders only packet values (§9) |
| School page | /schools/[dbn] | lists the school-grain keys in its Access table |
| Base-case validation (ii) for the Blue Book | — | not built: verify/ does not cover this source |
Closure table (SchoolEvent from PEP records) | — | not built; gates any predictive claim (§6) |
9. The page
/methodology/analysis/enrollment-capacity is a working analysis (numbered
takeaways → figures with "how to read" notes → numbers appendix → limits →
sources and checks). It is noindex and carries a work-in-progress strip, because
no full-QA report exists for the packet. Figures, in order:
- Utilization distribution, school grain, first published year against latest, with the 50% and 100% lines and the percentile ladders (§4.1).
- The two tails as time series: share under 50% and share over 100% (§4.1) — the shape change is the finding, not the median.
- Decomposition waterfall: −14.2 pp enrollment, +2.5 pp capacity (§4.3), with the segments in appendix table A3b.
- Community school districts, ranked bars, 2025-26 (§4.5).
- Denominator sensitivity: the same schools on target vs historical capacity (§4.4).
- School grain against building grain, over the share of buildings holding more than one school (§1, §4.1).
Each time-series figure plots twelve points on a real-year axis and breaks the line at 2020-21 rather than joining 2019-20 to 2021-22 as if the interval were one year. Each figure names its capacity definition and its grain in the caption. The page carries no closure or disappearance figure: the §4.6 lift table rests on a proxy, and the page is descriptive (§6).
10. Open items and caveats
- 2020-21 is unpublished (§2); the SCA never posted it. The other five years Socrata does not carry are parsed from the SCA's PDFs (§2.1).
- The PDF years blank two columns that Socrata zeroes (§2.1). On about 2% of rows the report prints nothing where the published extract carries a
0, inprek_capacityandcluster_rooms_needed. Neither column enters the utilization calculation, so no figure in §4 moves, but a future metric built on those two columns would read a PDF year differently from a Socrata one. - A City Council edition carries no
geo_dist(§2.1). None of the twelve loaded years comes from one — 2014-15 is loaded from the Classic edition — and the parser drops that column rather than misfiling a council district as a geographic one, so a year loaded from a City Council edition could not appear in a district breakdown of the §4.5 kind. - No closure record (§6). The largest gap; gates predictive claims.
- Only school grain is stored (§7). Building facts are not copied onto DBNs, which would double-count across the 42.1% of buildings that are shared in the latest year; the building-grain figures come from the source, through the packet.
- Split-site schools (§3.2) are the loader's main correctness hazard.
rollUpOrgssums every school's enrollment and capacity over its building rows before dividing, and the transform tests assert it on P.S. 163X and M094. - Target capacity is a planning construct, not a fire-code occupancy limit. It is what the SCA divides by; it is not "how many children fit."
- Pre-K is on both sides of the ratio (§5.4). Enrollment is the audited register including 3-K and Pre-K students; target capacity counts each Pre-K room at up to 18 seats (36 half-day), capped by its area ÷ 35 sq ft, and the PK Cap column restates that share rather than adding to it. Whether 3-K rooms carry capacity is not established.
- The Pre-K measurements are not in the probes (§5.5). Adding the §5.2 Pre-K room variant and the §5.4 numerator check to
probe/bluebook_verify.pywould make them reproducible from a committed script. - Charters in DOE buildings appear as organizations with their own enrollment and capacity; charters in private space are absent from the Blue Book entirely. Any citywide utilization figure is therefore a DOE-buildings figure.
- The warehouse and the packet count different school sets. The loader resolves org codes against the warehouse's
schoolstable and the packet against the directory-plus-Snapshot union (§3.1), so the number of storedutilization_pctrows depends on theschoolstable the loader joins against. Production'sschoolstable (§3.1) lacks the schools opened since 2019-20, so against it the stored count is within one school of the packet's n through 2019-20 and falls behind after it, to 1,671 against 1,702 in 2024-25 (57 org codes find no DBN that year) and 1,660 against 1,698 in 2025-26. The analysis page cites the packet's figure. scripts/loaders/demographics.tspoints at a file that returns 404. Its URL isdemographic-snapshot-2020-21-to-2024-25-public.xlsx; InfoHub servesdemographic-snapshot-2021-22-to-2025-26-public.xlsxinstead. Swapping the URL is one line, but it changes the loader's year coverage (drops 2020-21, adds 2025-26), so it is a decision rather than a fix, and it is left open.