Source document

docs/design/10_nyc_enrollment_capacity_utilization.md

Served verbatim from the project repository. Internal working document conventions apply: documents may reference file paths, branch names, and findings-ledger anchors from the repo.

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:

DatasetWhat it isState
gkd7-3vk7Enrollment Capacity And Utilization Reportslive, last updated 2026-09-10; 20,754 rows across 7 snapshots
q9xk-w9iv... Historical by Organizationretired 2015; 2,658 rows, one vintage. Carries the pre-2014 capacity formula
hq56-zhrp... Historical by Buildingretired 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 in 05_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_enrollment are 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_ofschool yearmedian diff (students)% exactncitywide enrollmentread from
2014-10-312014-15092%1,6901,029,321SCA PDF
2015-04-272013-14090%1,6541,022,505Socrata
2017-09-122015-16089%1,6981,035,660Socrata
2018-01-082016-17094%1,7031,033,647Socrata
2019-01-312017-18095%1,7151,025,875Socrata
2019-10-312019-20095%1,698999,453SCA PDF
2019-12-182018-19095%1,6881,012,330Socrata
2022-10-312022-23092%1,681892,729SCA PDF
2023-01-042021-22095%1,706915,272Socrata
2023-10-312023-24094%1,687896,571SCA PDF
2024-10-312024-25095%1,698889,640SCA PDF
2026-09-092025-26082%1,698862,834Socrata

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.

yearkeyPDF(s)rowsorganizationsbuildingsgate mismatches
2014-152014-10-312014-2015BlueBook.pdf2,7171,8441,4650
2019-202019-10-31Blue Book 2019-2020.pdf3,1571,8111,3970
2022-232022-10-31Blue Book 2022-2023.pdf3,1061,8021,3830
2023-242023-10-31Blue Book 2023-2024.pdf3,1211,7861,3850
2024-252024-10-31Blue Book 2024-2025.pdf3,1211,7781,3830

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 to prek_capacity and cluster_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. rollUpBuildings takes 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:

yearnp10p25medianp75p90<50%<33%>100%citywide (Σ/Σ)
2013-141,7415571911111316.4%2.4%36.6%93.7%
2014-151,7535875951161395.8%1.8%42.8%96.7%
2015-161,7435674941151406.7%1.9%42.0%95.9%
2016-171,7165574931151366.4%1.3%41.1%95.1%
2017-181,7155472921131346.8%1.5%38.8%93.6%
2018-191,6975572911121326.8%1.5%37.8%92.5%
2019-201,7065370911131357.5%1.4%37.7%92.4%
2021-221,70447648310212111.9%3.2%26.8%84.4%
2022-231,70245628210212112.7%3.5%26.7%84.0%
2023-241,70446638210312212.3%3.4%27.3%84.5%
2024-251,70245618010112013.3%3.6%26.2%83.1%
2025-261,6984258789811615.5%4.8%21.9%80.3%

The same years at building grain, which is the grain NYC plans on:

yearbuildingsmedian<50%<33%>100%citywide (Σ/Σ)multi-org buildings
2013-141,311963.2%1.0%43.9%92.9%505 (38.5%)
2014-151,3201003.3%0.8%49.2%95.9%535 (40.5%)
2015-161,323994.5%1.3%48.3%95.8%540 (40.8%)
2016-171,320984.8%1.1%47.1%95.1%530 (40.2%)
2017-181,326975.1%1.4%45.7%93.5%536 (40.4%)
2018-191,323955.6%1.4%42.9%92.5%531 (40.1%)
2019-201,324954.9%1.1%43.6%92.3%533 (40.3%)
2021-221,327868.6%2.0%30.5%84.3%543 (40.9%)
2022-231,323859.8%2.3%30.7%84.0%547 (41.3%)
2023-241,322869.3%2.5%30.9%84.4%548 (41.5%)
2024-251,329849.5%2.3%29.1%83.1%557 (41.9%)
2025-261,3348111.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:

enrollment1,001,480 → 847,345 (−15.4%)
capacity1,082,413 → 1,049,116 (−3.1%)
utilization92.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):

spanbuildings in bothutilizationchangeenrollment effectcapacity effect
2018-19 → 2019-201,31692.5% → 92.4%−0.1 pp−1.2+1.0
2019-20 → 2021-22 (two years)1,31292.3% → 84.4%−7.9 pp−7.90.0
2021-22 → 2022-231,31484.3% → 84.1%−0.2 pp−2.1+1.9
2022-23 → 2023-241,31784.0% → 84.5%+0.4 pp+0.4+0.1
2023-24 → 2024-251,31184.5% → 83.4%−1.1 pp−0.9−0.2
2024-25 → 2025-261,31983.1% → 80.5%−2.6 pp−2.5−0.1
2018-19 → 2025-261,27392.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:

  1. 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.
  2. 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.
  3. 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.

statisticuniversevalue
target ÷ historical capacity1,767median 0.917, p10 0.804, p90 1.022
utilization gap (target − historical)1,747median +7 pp, p10 −2, p90 +21
share below 50%1,7478.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:

districtschoolsutilizationshare <50%
16 (Bed-Stuy)3045.6%46.7%
32 (Bushwick)3057.4%36.7%
1 (Lower East Side)3258.0%34.4%
23 (Brownsville)3258.6%40.6%
5 (Harlem)3459.3%29.4%
17 (Crown Heights)5464.3%38.9%
18 (East Flatbush)4165.0%34.1%
14 (Williamsburg/Greenpoint)4766.2%25.5%
...
22 (Sheepshead Bay/Midwood)4095.9%7.5%
25 (Flushing)47100.7%0.0%
26 (NE Queens)40102.4%2.5%
20 (Bay Ridge/Sunset Park)48103.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 pointflaggeddisappearedrestliftFisher p
utilization < 33%185.6%3.4%1.65×0.46
utilization < 50%738.2%3.2%2.60×0.034
utilization < 66%2669.4%2.2%4.21×2.6e-07
utilization < 75%4426.8%2.1%3.16×1.8e-05
enrollment < 2001459.0%2.9%3.14×0.00073
enrollment < 3003497.7%2.2%3.48×5.3e-06
enrollment < 4005996.8%1.4%4.81×1.5e-08
enrollment < 5008445.9%0.7%7.99×8.4e-10

Two things worth carrying forward:

  1. 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.
  2. 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.

yearcomparisonnmedian |diff|r
2018-19Blue Book vs CCD1,5173 students0.9998
Blue Book vs Snapshot (control)1,6900 students0.9944
CCD vs Snapshot (control)1,5093 students0.9998
2021-22Blue Book vs CCD1,5214 students0.9997
Blue Book vs Snapshot (control)1,7080 students0.9921
CCD vs Snapshot (control)1,5234 students0.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.

yearbuildingssq ft per target seatseats per instructional roomR² of capacity on area
2018-191,321median 31.8 (IQR 28.2–36.1)20.9 (IQR 17.9–23.7)0.9225
2021-221,319median 31.9 (IQR 28.1–36.4)20.7 (IQR 17.6–24.0)0.9275
2025-261,331median 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 CLASSROOM in 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 CENTER and MOSAIC 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_keyunitsourcenotes
target_capacityCOUNTBlue Book org_target_cap, summed across the school's building rows (§3.2)includes Pre-K rooms (§5.4)
utilization_pctPERCENTderived: summed enrollment ÷ summed capacityequals the published figure for single-building schools (§1); marked derived
utilization_pct_publishedPERCENTBlue Book org_target_utilstored only where a school prints one figure; a split-site school prints one per building row
prek_capacityCOUNTBlue Book prek_cappart 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_neededCOUNTBlue Bookart/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

PieceWhereState
PDF parser and parsed panelpipeline_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)
Schemanone: the facts are rows in school_year_metrics (§7)—
Metric cataloguescripts/loaders/metric-definitions-capacity.tssix keys (§7); run before the loader
Loaderscripts/loaders/nyc-bluebook.ts, with the pure transform in _bluebook.ts and the PDF years read by _bluebook_recovered.tsloads all twelve years; refuses an unmapped vintage, a parsed year whose gate did not pass, or a year failing check (iv)
Transform teststests/nyc-bluebook-transform.test.tsverbatim 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
Packetscripts/analysis/nyc-capacity-packet.ts → data/analysis/nyc-enrollment-capacity.json--check regenerates and diffs against the committed file
Page/methodology/analysis/enrollment-capacityrenders 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:

  1. Utilization distribution, school grain, first published year against latest, with the 50% and 100% lines and the percentile ladders (§4.1).
  2. The two tails as time series: share under 50% and share over 100% (§4.1) — the shape change is the finding, not the median.
  3. Decomposition waterfall: −14.2 pp enrollment, +2.5 pp capacity (§4.3), with the segments in appendix table A3b.
  4. Community school districts, ranked bars, 2025-26 (§4.5).
  5. Denominator sensitivity: the same schools on target vs historical capacity (§4.4).
  6. 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, in prek_capacity and cluster_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. rollUpOrgs sums 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.py would 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 schools table and the packet against the directory-plus-Snapshot union (§3.1), so the number of stored utilization_pct rows depends on the schools table the loader joins against. Production's schools table (§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.ts points at a file that returns 404. Its URL is demographic-snapshot-2020-21-to-2024-25-public.xlsx; InfoHub serves demographic-snapshot-2021-22-to-2025-26-public.xlsx instead. 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.