"""Rebuild the Canada 2026-11-01 container census classes and headline counts from census.json. python3 rebuild.py census.json [--check] Re-derives every scanned row's class from its recorded tzscan copies and recounts the headline numbers for D_maint (tag pushed on or after 2026-07-16) and D_all (all pinned images). --check exits 1 if any class or count differs from the file's own values. To re-measure one row instead of trusting the recorded copies (needs crane and tzscan): crane export --platform linux/amd64 - | python3 tzscan.py --tar - --json """ import collections, json, math, sys CANADA = ("America/Vancouver", "America/Edmonton", "America/Inuvik", "America/Winnipeg") def classify(r): copies = r["copies"] kinds = r["tzscanProblemKinds"] cw = [c for c in copies if set(c.get("wrong") or []) & set(CANADA)] if any(c["tier"] == "A" for c in cw): return "WRONG_DEFAULT" if cw: return "WRONG_LIBRARY_ONLY" if not copies: return "NO_TZ_DATA" if all(k == "nothing-judged" for k in kinds) else "UNKNOWN" if r["tzscanComplete"] and not kinds and all(c["verdict"] == "OK" for c in copies): return "CURRENT" return "UNKNOWN" def wilson(k, n, z=1.96): if n == 0: return None p = k / n d = 1 + z * z / n c = (p + z * z / (2 * n)) / d h = z * math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)) / d return [round(c - h, 4), round(c + h, 4)] def counts(sub): cnt = collections.Counter(r["class"] for r in sub) scanned = sum(v for k, v in cnt.items() if k != "NOT_SCANNED") decidable = scanned - cnt["UNKNOWN"] h1, h2 = cnt["WRONG_DEFAULT"], cnt["WRONG_DEFAULT"] + cnt["WRONG_LIBRARY_ONLY"] out = {"n": len(sub), "scanned": scanned, "notScanned": cnt["NOT_SCANNED"], "classes": dict(sorted(cnt.items()))} for name, den in (("scanned", scanned), ("decidable", decidable)): out[f"H1_{name}"] = {"k": h1, "n": den, "rate": round(h1 / den, 4) if den else None, "wilson95": wilson(h1, den)} out[f"H2_{name}"] = {"k": h2, "n": den, "rate": round(h2 / den, 4) if den else None, "wilson95": wilson(h2, den)} return out def main(): data = json.load(open(sys.argv[1], encoding="utf-8")) rows = data["rows"] bad = [] for r in rows: if r["class"] in ("EXCLUDED", "NOT_SCANNED"): continue c = classify(r) if c != r["class"]: bad.append((r["image"], r["class"], c)) pinned = [r for r in rows if r["class"] != "EXCLUDED"] got = {"D_maint": counts([r for r in pinned if r["maintained"]]), "D_all": counts(pinned)} for lbl, v in got.items(): print(f"{lbl}: n={v['n']} scanned={v['scanned']} not_scanned={v['notScanned']} classes={v['classes']}") for h in ("H1_scanned", "H2_scanned"): print(f" {h}: {v[h]['k']}/{v[h]['n']} = {v[h]['rate']} (Wilson 95% {v[h]['wilson95']})") print(f"rows: {len(rows)} (pinned {len(pinned)}, excluded {len(rows) - len(pinned)}); class mismatches: {len(bad)}") for b in bad[:20]: print(" mismatch", *b) if "--check" in sys.argv: want = data["meta"]["headline"] diff = [lbl for lbl in got if json.dumps(got[lbl], sort_keys=True) != json.dumps(want[lbl], sort_keys=True)] if bad or diff: print(f"CHECK FAILED: {len(bad)} class mismatches, headline differs for {diff}") return 1 print("CHECK OK: classes and headline counts match the file") return 0 if __name__ == "__main__": sys.exit(main())