# NJDOE IDEA Section 618 Classification Rates

```toml ergo
[dataset]
ergo = "0.4"
slug = "idea-classification-rates"
title = "NJDOE IDEA Section 618 Classification Rates"
publisher = "NJ Department of Education, Office of Special Education"
subject = "https://www.nj.gov/education/specialed/monitor/ideapublicdata/"
source_url = "https://www.nj.gov/education/specialed/monitor/ideapublicdata/docs/2025_618data/2025IDEA618PublicReporting_ClassificationRates.xlsx"
pitfall = "The classification rate is an October 15, 2024 administrative record, not the later UFB planning share or evidence of need, staffing, spending, service quality, or compliance."
status = "live"
confidence = "A"
updated = "2026-07-30"
implementation = "https://github.com/lavallee/njschooldata"

[dataset.coverage]
period = "October 15, 2024 reference date — one snapshot, no trend"
grain = "district overall classification row x metric; statewide category row x metric"
entities = "655 district reporting rows and 15 statewide rows; 558 of 587 rendered budget districts match by exact code"

[dataset.access]
keys = ["reference_date", "district_code", "category_id", "metric_id"]
```

## Consumer question and boundary

The budget product already asks how much of the UFB planning denominator is
special education. AQ-061 adds one earlier, bounded question, asked on the
district budget report and — since 2026-07-30 — on the district profile itself:

> What enrollment, students-with-IEPs count, and classification rate did
> NJDOE report for this district on October 15, 2024, before a reader
> interprets later UFB special-education planning rows?

Aquifer owns official-file custody, source literals and cell locators, mixed
native rate scales, value states, reconciliations, immutable releases, and
offline snapshots. This repo owns the budget question, two-table mart,
exact-code join, period comparison, wording, placement, static UAT, and
rollback.

The panel does not subtract the IDEA rate from the later UFB planning share.
It does not interpret either row as evidence of underlying disability
prevalence, unmet need, placement, staffing, spending cause, service quality,
appropriateness, or compliance. The October 15 reference date remains separate
from the UFB budget year, and the workbook's conflicting embedded `School Year
2023-24` title remains a publisher defect rather than an inferred period.

## Exact offline pin and mart

The committed pin is
`contracts/aquifer/nj-idea-classification-rates.lock.json`:

- release: `nj-idea-classification-aq061-refresh2-v3`;
- manifest SHA-256:
  `5137bf06f16b6dca3d74ec68a14afeb80fcbeaee338060f35617bbc7f0f1a9ec`;
- SQLite SHA-256:
  `5eb3e6750f7a4f440142b846e98aa567d7d350e9c822cecfc7a54d95b58f391c`;
- byte count: `2,215,936`.

The consumer verifies the pin before cloning the existing warehouse. It
projects the district `all-iep-students` rows and the statewide total, validates
the complete source and value-state populations, hashes every unmanaged table,
and atomically replaces the clone:

| Consumer table | Rows | Deterministic row SHA-256 |
| --- | ---: | --- |
| `idea_classification_district` | 655 | `211b90f6bf477604e6d57d7081b4bd3c89f7b39fce266ac3318d4bc384f28479` |
| `idea_classification_state` | 1 | `1445eb72e280235ac7d2d7a6a9aa266f8efc2afac50116d16a4802e6a4e5c60d` |

The source contains 670 physical rows and 1,994 canonical measure values. The
district projection retains 650 reported rates, four exact-reconciliation
zeros, and one not-collected rate; enrollment denominators retain 652 reported
and three suppressed values. Holland Township keeps its reported enrollment
of 522 beside not-collected IEP-count and rate cells. The statewide comparator
is 242,001 students with IEPs out of 1,394,970, or 17.35%.

## Static rendering and omissions

The canonical profile build writes 587 district budget reports. Exactly 558
join the IDEA mart by the same zero-padded NJDOE district code and render the
panel. The remaining 29 omit it instead of falling back to names. They include
the special-services, jointure, and educational-services entities absent from
the source, plus a small set of ordinary districts with no exact source row.
The full path set is locked in
`tests/test_aquifer_idea_classification_adapter.py` and enumerated in the
adoption receipt.

South Orange-Maplewood renders 7,140 total enrollment, 1,340 students with
IEPs, and 18.77%. Holland is the sole rendered not-collected case and displays
two `Not collected` cells, never zero. Atlantic County Special Services is an
intentional exact-code omission. Every rendered panel links the official XLSX
and preserves its source-row locator.

Since 2026-07-30 the same mart also feeds a district-profile module, **How many
students have an IEP** (`mod_special_education`). It renders the district count,
the district rate, the 17.35% statewide comparator, the three states an empty
cell can be in, and the three dimensions this file does not carry. It ships no
chart: a single rate against a single comparator is a stat figure, not a chart
form, and it sits in the enrolled-population block rather than beside the budget
section so that no layout invites the subtraction the boundary above forbids.

## Issues

### A withheld cell, an empty cell and a printed zero are three different things

```toml ergo
[issue]
id = "three-empties-are-not-zero"
title = "Three districts have a suppressed enrollment denominator (`*`), one has not-collected IEP and rate cells (empty), and four have an exact zero NJDOE printed — none of the three may render as the others"
effect = "breaks"
core = true
type = "suppression"
status = "mitigated"
detection = "Value-state populations in idea_classification_district: total_enrollment 652 reported / 3 suppressed; students_with_iep and classification_rate 650 reported / 4 exact-reconciliation-zero / 1 not-collected. The suppressed literal is `*` and the not-collected literal is the empty string. No classification rate is suppressed anywhere in the file — suppression lands only on the denominator."
misuse = "Rendering `*` or the empty literal as 0 or 0%. Holland Township (2220) reports 522 students and no IEP count at all; printed as a zero it becomes a district where no child has an IEP. Conversely, greying the four printed zeros as 'not available' deletes a figure NJDOE published."

[issue.scope]
tables = ["idea_classification_district"]
columns = ["total_enrollment_state", "students_with_iep_state", "classification_rate_state"]
rows = "total_enrollment_state <> 'reported' OR students_with_iep_state <> 'reported'"
```

The five non-clean districts, exactly as published:

| Code | District | County | Enrollment | Students with IEP | Rate |
| --- | --- | --- | --- | --- | --- |
| `2220` | Holland Township | Hunterdon | `522` reported | *empty* not-collected | *empty* not-collected |
| `8505` | Bergen Co JDC | Bergen | `*` suppressed | `0` printed zero | `0` printed zero |
| `8509` | Essex Co JDC | Essex | `5` reported | `0` printed zero | `0` printed zero |
| `8511` | Middlesex Co JDC | Middlesex | `*` suppressed | `0` printed zero | `0` printed zero |
| `8513` | Ocean Co JDC | Ocean | `*` suppressed | `0` printed zero | `0` printed zero |

The profile module renders each state distinctly, from one shared cell
formatter: a withheld cell keeps the publisher's `*` literal beside the word, an
empty cell reads "Not published" in italics, and a printed zero is emphasized as
the figure it is. The three JDC rows are the shape that most easily goes wrong —
a rate published without the denominator it was computed from — and the module
says so in words rather than showing a rate beside a blank.

### The classification rate is an administrative count, not a measure of anything

```toml ergo
[issue]
id = "rate-is-an-administrative-count"
title = "The classification rate is the share of students holding an IEP on one October day; it measures neither need, identification quality, service quality, staffing, spending, placement nor compliance, and it is directionless"
effect = "misleads"
core = true
type = "definitional"
status = "mitigated"
detection = "The published district rates run from 0.0 to 65.57 percentage points against a statewide 17.35. The four highest are state-operated or county-operated programs — Department of Corrections education (65.57), Department of Children and Families education (40.55), the Juvenile Justice Commission (39.6) — placement settings whose enrolled population arrives already classified. Nothing in the file distinguishes a district that identifies students well from one that over-identifies them, and there is no direction in which the number is better."
misuse = "Reading a high rate as unmet need being met, or as over-classification; reading a low rate as under-identification, or as a healthy population. Ranking districts on the rate. Placing the rate beside the UFB special-education planning share as if the difference between them meant something — different population, different date, different file."

[issue.scope]
tables = ["idea_classification_district", "idea_classification_state"]
columns = ["classification_rate_value"]
```

The module carries this directly beneath the figure rather than in a footnote,
and states the ambiguity in both directions in the same sentence. It also names
the structural reason the high end exists — some reporting units are state-run
programs, county juvenile detention centers and specialized placements — as a
property of what kind of entity a unit is, never as a judgment about a district.

### District rows carry no disability, race, age or educational-environment breakdown

```toml ergo
[issue]
id = "no-district-level-breakdowns"
title = "The 13 disability categories in this workbook exist for New Jersey only; there is no district-level disability breakdown, and no breakdown by race, age or educational environment at any level"
effect = "context"
type = "coverage"
status = "mitigated"
detection = "The release carries 14 category ids: `all-iep-students` plus 13 `idea-disability-*`. Every one of the 1,965 district-level cells (655 rows x 3 metrics) is `all-iep-students`; the 13 disability categories appear only in the 29 state-level cells. No race, age or educational-environment dimension exists anywhere in the artifact."
misuse = "Promising a parent a district disability breakdown, or reading the statewide category shares as this district's. The federal IDEA Section 618 collections by race, age and educational environment do exist; this NJDOE file is not them, and looking for them in this pin will not find them."

[issue.scope]
tables = ["idea_classification_district"]
columns = ["category_id"]
entities = "all 655 district reporting units"
```

The module answers all three questions out loud rather than omitting them: a
reader who is not told what is missing assumes it was not worth showing. The
statewide category breakdown is **not** projected into the consumer mart, so no
surface can render it without a projection change.

### Deaf-Blindness publishes an exact zero rate against 18 students

```toml ergo
[issue]
id = "deaf-blindness-rate-rounds-to-zero"
title = "The statewide Deaf-Blindness row publishes a classification rate of exactly 0 against a headcount of 18 students"
effect = "corrupts"
type = "measurement"
status = "open"
detection = "In the pinned release, category `idea-disability-deaf-blindness` carries students-with-IEP literal `18` typed reported, and rate literal `0` typed exact-reconciliation-zero, at `State Rates!8:B` and `State Rates!8:C`. Every other statewide category publishes a non-zero fraction; the three next-smallest (visual impairment, traumatic brain injury, orthopedic impairment) publish `0.0002`."
misuse = "Printing the category's rate as 0 or 0% without its headcount, which says no New Jersey student is deaf-blind. The zero is a rounding artifact of a rate expressed as a fraction to four decimal places, not a count."

[issue.scope]
entities = "statewide Deaf-Blindness disability category"
rows = "category_id = 'idea-disability-deaf-blindness' AND metric_id = 'idea.classification.rate-percent'"
```

Status is `open` rather than `mitigated` because the statewide category rows are
not in the consumer projection, so nothing in this repo renders the value and
nothing here can be said to handle it. If the breakdown is ever projected, the
Deaf-Blindness row cannot be printed as a zero without its 18 students.

### The workbook's embedded title contradicts its own reference date

```toml ergo
[issue]
id = "embedded-title-contradicts-reference-date"
title = "The 2025-edition workbook's embedded title reads `School Year 2023-24` while the reference date NJDOE states for the data is 2024-10-15"
effect = "misleads"
type = "entry"
status = "mitigated"
detection = "Release metadata carries `publisher_edition = 2025`, `reference_date = 2024-10-15` and `embedded_title_defect = School Year 2023-24`. The conflict is inside the published file and is preserved rather than reconciled."
misuse = "Labeling the figures `2023-24` from the embedded title, or `2025` from the edition. Either label alone attaches the count to a school year NJDOE did not say it measures."

[issue.scope]
all = true
```

Neither label is printed without the other. The reader-facing module names the
October 15, 2024 reference date, then says the embedded title disagrees and that
the disagreement is the publisher's.

### Special-services districts and commissions have no row at all

```toml ergo
[issue]
id = "special-services-districts-have-no-row"
title = "29 of the 587 rendered district reports have no exact-code row in this file, and 20 of them are the county special-services districts, educational-services commissions and jointure commissions a special-education surface most invites a reader to look for"
effect = "context"
type = "linkage"
status = "mitigated"
detection = "558 of 587 rendered district budget reports match by exact zero-padded NJDOE district code; the 29 that do not are locked in tests/test_aquifer_idea_classification_adapter.py. Twenty carry special-services, educational-services-commission or jointure-commission routes; the other nine are ordinary districts (0130, 0200, 0810, 2120, 2160, 3145, 4700, 4720, 5490) with no source row."
misuse = "Falling back to a name match to fill the gap, which would attach a neighboring district's classification rate to a special-services entity. Reading the absence as a district with no students holding IEPs."

[issue.scope]
tables = ["idea_classification_district"]
columns = ["district_code"]
entities = "29 rendered districts with no exact-code source row"
```

`attach_idea_classification` joins on the exact zero-padded district code only.
A district with no row renders no module — not an empty one — so absence is
visible as absence.

## Changelog

```toml ergo
[change]
date = "2026-07-30"
note = "Shipped the district-profile module (How many students have an IEP) and served the public explainer at /data/idea-classification-rates/, then registered the six issues a reader-facing surface has to get right — the three-way empty-cell distinction, the rate's directionlessness, the three absent dimensions, the Deaf-Blindness exact zero against 18 students, the embedded-title date conflict, and the 29 exact-code nonmatches. No projection change: the statewide disability categories remain outside the consumer mart. Measured while writing them: the release carries 13 disability categories plus all-iep-students, not 14 plus one, and 29 state-level cells rather than 31."
issues = ["three-empties-are-not-zero", "rate-is-an-administrative-count", "no-district-level-breakdowns", "deaf-blindness-rate-rounds-to-zero", "embedded-title-contradicts-reference-date", "special-services-districts-have-no-row"]
```
