Source document

scripts/loaders/miami/abc_book.ts

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.

// Load the parsed board Attendance Zone Recommendations capacity blocks
// (data/cities/miami/reference/parsed/mdcps_abc_book_<year>.csv) →
// enrollment_abc, fish_capacity_permanent_abc, utilization_permanent_pct_abc
// under the block's current year, and projected_enrollment_y1 / _y2 under the
// projected years.
// Run:  npx tsx scripts/loaders/miami/abc_book.ts [source_id]

import fs from "node:fs";
import path from "node:path";
import { parse } from "csv-parse/sync";
import { requireSource, startDataLoad, finishDataLoad, schoolUniverse, upsertFacts, runMain, type Fact } from "./_lib";

const SCRIPT_PATH = "scripts/loaders/miami/abc_book.ts";
const PARSED = path.join(process.cwd(), "data", "cities", "miami", "reference", "parsed");

const num = (v: string | undefined): number | null => {
  if (v === undefined || v === "" || v === "nan") return null;
  const n = Number.parseFloat(v);
  return Number.isFinite(n) ? n : null;
};

async function main() {
  const sourceId = process.argv[2] ?? "mdcps_abc_book_2026-27";
  const { prov } = requireSource(sourceId);
  const gate = JSON.parse(fs.readFileSync(path.join(PARSED, `${sourceId}.gate.json`), "utf-8")) as { pass: boolean };
  if (!gate.pass) throw new Error(`${sourceId}: parser gate did not pass`);
  const rows = parse(fs.readFileSync(path.join(PARSED, `${sourceId}.csv`), "utf-8"), { columns: true, skip_empty_lines: true }) as Record<string, string>[];
  const universe = await schoolUniverse();
  const facts: Fact[] = [];
  let schools = 0;
  for (const r of rows) {
    if (!universe.has(r.school_number)) { console.warn(`[abc] ${r.school_number} ${r.school_name} not in directory`); continue; }
    schools++;
    const y0 = r.year_current;
    const e = num(r.enrollment_current), c = num(r.perm_fish_current), u = num(r.util_perm_current);
    if (e !== null) facts.push({ schoolNumber: r.school_number, year: y0, metricKey: "enrollment_abc", value: e });
    if (c !== null) facts.push({ schoolNumber: r.school_number, year: y0, metricKey: "fish_capacity_permanent_abc", value: c });
    if (u !== null) facts.push({ schoolNumber: r.school_number, year: y0, metricKey: "utilization_permanent_pct_abc", value: u, denominator: c });
    const p1 = num(r.enrollment_proj1), p2 = num(r.enrollment_proj2);
    if (p1 !== null && r.year_proj1) facts.push({ schoolNumber: r.school_number, year: r.year_proj1, metricKey: "projected_enrollment_y1", value: p1 });
    if (p2 !== null && r.year_proj2) facts.push({ schoolNumber: r.school_number, year: r.year_proj2, metricKey: "projected_enrollment_y2", value: p2 });
  }
  const load = await startDataLoad({ sourceId, sourceUrl: prov.url, sha256: prov.sha256, bytes: prov.bytes, yearCovered: rows[0]?.year_current, scriptPath: SCRIPT_PATH,
    notes: `parsed capacity blocks (${rows.length} schools; arithmetic gate PASS)` });
  const res = await upsertFacts(facts, load.id);
  await finishDataLoad(load.id, { inserted: res.written, updated: 0, suppressed: 0 });
  console.log(`[abc] ${res.written} facts for ${schools} schools`);
}

runMain(main);