Source document

pipeline_miami/verify/reconcile_computed.py

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.

"""(iv) Computed values: recompute every derived closure-track metric from the
served inputs and compare with the served derived value.

Run:  python -m pipeline_miami.verify.reconcile_computed
"""
from __future__ import annotations

import json

from pipeline_miami.verify import common
from pipeline_miami.verify.connectors import served_db


def shift(year: str, k: int) -> str:
    a = int(year[:4]) + k
    return f"{a}-{str((a + 1) % 100).zfill(2)}"


def main() -> None:
    common.ensure_qa_dir()
    enr = served_db.fetch("enrollment_oct")
    kg = served_db.fetch("enrollment_oct_gKG")
    g5 = served_db.fetch("enrollment_oct_g5")
    perm = served_db.fetch("fish_capacity_permanent")
    perm_abc = served_db.fetch("fish_capacity_permanent_abc")
    perm_gis = served_db.fetch("fish_capacity_permanent_gis")
    tfte = served_db.fetch("teacher_fte")
    fish_years = sorted({k[1] for k in perm})
    latest_fish = fish_years[-1] if fish_years else None

    def val(d, k):
        v = d.get(k)
        return v["value"] if v and not v["suppressed"] else None

    checks = {
        "utilization_permanent_pct": [], "enrollment_change_5yr_pct": [], "k_to_g5_ratio": [], "students_per_teacher": [],
    }
    served = {m: served_db.fetch(m) for m in checks}
    for (n, y), e in enr.items():
        ev = val(enr, (n, y))
        if ev is None:
            continue
        cap = val(perm, (n, y))
        if cap is None and latest_fish and y > latest_fish:
            cap = val(perm, (n, latest_fish)) or val(perm_abc, (n, y)) or (val(perm_gis, (n, "2024-25")) if y > "2023-24" else None)
        if cap:
            checks["utilization_permanent_pct"].append(((n, y), ev / cap * 100))
        prev = val(enr, (n, shift(y, -5)))
        if prev:
            checks["enrollment_change_5yr_pct"].append(((n, y), (ev / prev - 1) * 100))
        k, f = val(kg, (n, y)), val(g5, (n, y))
        if k and f:
            checks["k_to_g5_ratio"].append(((n, y), k / f))
        t = val(tfte, (n, y))
        if t:
            checks["students_per_teacher"].append(((n, y), ev / t))
    rows = []
    for m, expected in checks.items():
        s = served[m]
        matches = mism = 0
        examples = []
        for k, x in expected:
            sv = val(s, k)
            if sv is not None and abs(sv - x) <= 1e-6 * max(1, abs(x)):
                matches += 1
            else:
                mism += 1
                if len(examples) < 5:
                    examples.append({"key": k, "expected": x, "served": sv})
        rows.append({"name": m, "expected_total": len(expected), "served_total": len(s), "common_keys": len([1 for k, _ in expected if k in s]), "matches": matches, "mismatches": mism,
                     "agreement_rate": matches / (matches + mism) if (matches + mism) else None, "examples": examples})
    (common.QA_REPORTS_DIR / "__computed_value.json").write_text(json.dumps(rows, indent=2, default=str))
    out = ["# Computed values (iv) — derived metrics recomputed from served inputs\n", "| metric | expected | served | matches | mismatches |", "|---|---:|---:|---:|---:|"]
    out += [f"| `{r['name']}` | {r['expected_total']} | {r['served_total']} | {r['matches']} | {r['mismatches']} |" for r in rows]
    (common.QA_REPORTS_DIR / "__computed_value.md").write_text("\n".join(out))
    for r in rows:
        print(f"  {r['name']:30s} expected={r['expected_total']:>5d} served={r['served_total']:>5d} matches={r['matches']:>5d} mismatches={r['mismatches']}")


if __name__ == "__main__":
    main()