Buckets:
| """cwm3/eval/report_final_gzfc.py — results/tables/stage_final_gzfc.md: the gaze-chain APPENDIX variant of the joint model (2026-09-12; rule pre-registered in | |
| docs/decisions.md BEFORE training) from results/paired_compare.csv. Composes eval/report_joint.py blocks (load / render / verdict / claim / provenance); nothing | |
| is recomputed here; every number comes from the CSV rows written by eval/run_joint_evals_final_gzfc.sh. | |
| python eval/report_final_gzfc.py [--seeds 0,1,2] [--out results/tables/stage_final_gzfc.md] | |
| Blocks (tags): finalc_s<k>_allminusgzfc_vs_allminus (a) variant vs the FROZEN main model — the pre-registered comparison | |
| finalc_s<k>_allminusgzfc_vs_indepgzfc (b) interaction effect on the gzfc bases (B2-style, descriptive) | |
| finalc_s<k>_indepgzfc_vs_indep the U-base swap alone (assembled bases, no training) | |
| finalcm_* masked protocol (64 v2 driver-box-suspect routes censored) — sensitivity | |
| finalc/finalcm_s<k>_{allminusgzfc,indepgzfc}_vs_k0 driver cells vs k0 / persistence (B1 on the variant) | |
| finalP_s<k>_allminusgzfc_vs_{allminus,indepgzfc} P cells (eval/pressure_eval.py) | |
| gazec_s<k>_allminusgzfc_vs_indepgzfc gaze_off_on / gaze_off_off onset cells (eval/gaze_chain_eval.py) | |
| PRE-REGISTERED RULE: the variant is reported as the appendix row "main + gaze chain (+face)" iff in (a) NO own endpoint (report_joint.OWN: veh / drv / D onset | |
| PR-AUC@3s, both regimes) is WORSE (kill_checks.beats) AND drv_onset|head_turn_onset|3s BEATS in >= 1 regime; otherwise NEGATIVE RESULT. Never replaces the headline. | |
| Also writes results/tables/stage_final_gzfc_decision.json. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import sys | |
| from pathlib import Path | |
| import numpy as np | |
| import pandas as pd | |
| CWM3 = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(CWM3 / "eval")) | |
| import report_joint as RJ # noqa: E402 | |
| HT = "drv_onset|head_turn_onset|3s" | |
| EV = ("hand_leave", "hand_return", "head_turn_onset") | |
| def block(stage, a, b, claim, title, seeds): | |
| df = RJ.load(stage, a, b, seeds) | |
| if not len(df): | |
| return df, [f"### {title}: A = {a}, B = {b} — no rows yet (tags `{stage}_s<k>_{a}_vs_{b}`)", ""], {}, ("NO ROWS", [], [], []) | |
| body, verdicts = RJ.render(df, sorted(df.seed.unique()), a, b, title) | |
| return df, body, verdicts, RJ.claim(verdicts, claim) | |
| def ms(v): | |
| v = [float(x) for x in v if str(x) not in ("", "nan")] | |
| return "—" if not v else (f"{np.mean(v):.3f} ± {np.std(v, ddof=1):.3f}" if len(v) > 1 else f"{v[0]:.3f}") | |
| def fmt(ks): | |
| return [f"{r}|{c}" + (f"|{m}" if m != "pr_auc" else "") for (r, c, m) in ks] or "none" | |
| def own_table(verdicts): | |
| """every own endpoint of a block: mean Δ and verdict (the rule's inputs, listed explicitly).""" | |
| lines = ["| regime | own endpoint | mean Δ | verdict |", "|---|---|---|---|"] | |
| for (r, c, m), v in sorted(verdicts.items()): | |
| if c in RJ.OWN and m == "pr_auc": | |
| lines.append(f"| {r} | {c.replace('|', '/')} | {v['mean_delta']:+.4f} | {v['verdict']} |") | |
| return lines | |
| def b1_lines(seeds, dfs): | |
| out, js = [], {} | |
| for proto, stage in (("all rows", "finalc"), ("suspect routes masked", "finalcm")): | |
| out += [f"### B1 on the variant — driver onset PR-AUC@3s (v2 causal targets) vs the k0 heuristic / persistence, protocol: {proto}", "", | |
| "| variant | regime | event | model | k0 | persistence (base rate) | Δ per seed [CI] | verdict |", "|---|---|---|---|---|---|---|---|"] | |
| for var in ("indepgzfc", "allminusgzfc"): | |
| if proto != "all rows" and var == "indepgzfc": | |
| continue | |
| df = RJ.load(stage, var, "k0", seeds) | |
| dfs.append(df) | |
| if not len(df): | |
| out.append(f"| {var} | — | — | no rows yet (`{stage}_s<k>_{var}_vs_k0`) | | | | |") | |
| continue | |
| verd = {} | |
| for reg in ("manual", "engaged"): | |
| for ev in EV: | |
| cell = f"drv_onset|{ev}|3s" | |
| g = df[(df.regime == reg) & (df.cell == cell) & (df.metric == "pr_auc")].sort_values("seed") | |
| base = df[(df.regime == reg) & (df.cell == cell) & (df.metric == "base_rate")] | |
| if not len(g): | |
| continue | |
| res = RJ.verdict(g) | |
| verd[(reg, cell, "pr_auc")] = res | |
| cells = " / ".join(f"{float(r.delta):+.3f} [{float(r.delta_ci_lo):+.3f},{float(r.delta_ci_hi):+.3f}]" for r in g.itertuples()) | |
| out.append(f"| {var} | {reg} | {ev} | {ms(g.value_a)} | {ms(g.value_b)} | {ms(base.value_a) if len(base) else '—'} | {cells} | {res['verdict']} |") | |
| stb, _, _, _ = RJ.claim(verd, "B1") | |
| n_beats = sum(v["verdict"] == "BEATS" for v in verd.values()) | |
| js[f"{var}|{proto}"] = {"verdict": stb, "beats": n_beats, "cells": {f"{r}|{c}": v["verdict"] for (r, c, _), v in verd.items()}} | |
| out.append(f"| {var} | **B1 ({proto})** | | | | | {n_beats}/6 cells BEATS k0; rule (hand_leave AND head_turn_onset BEATS in both regimes) | **{stb}** |") | |
| out.append("") | |
| return out, js | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--seeds", default="0,1,2") | |
| ap.add_argument("--out", default=str(CWM3 / "results" / "tables" / "stage_final_gzfc.md")) | |
| a = ap.parse_args() | |
| seeds = [int(s) for s in a.seeds.split(",")] | |
| dfs = [] | |
| # (a) the pre-registered comparison | |
| dA, bodyA, vA, (stA, worseA, bcA, boA) = block("finalc", "allminusgzfc", "allminus", "B2", "(a) variant vs the FROZEN main model (v2 causal kin targets)", seeds) | |
| dB, bodyB, vB, (stB, worseB, bcB, boB) = block("finalc", "allminusgzfc", "indepgzfc", "B2", "(b) interaction effect on the gzfc bases: all_minus_road2drv_gzfc vs indep_gzfc (B2-style)", seeds) | |
| dC, bodyC, vC, (stC, worseC, bcC, boC) = block("finalc", "indepgzfc", "indep", "B2", "U-base swap alone: indep_gzfc vs indep (assembled bases, no training; descriptive)", seeds) | |
| dAm, bodyAm, vAm, (stAm, worseAm, bcAm, boAm) = block("finalcm", "allminusgzfc", "allminus", "B2", "Masked protocol (64 v2 suspect routes censored): variant vs FROZEN main", seeds) | |
| dBm, bodyBm, vBm, (stBm, worseBm, bcBm, boBm) = block("finalcm", "allminusgzfc", "indepgzfc", "B2", "Masked protocol: all_minus_road2drv_gzfc vs indep_gzfc", seeds) | |
| dP1, bodyP1, vP1, _ = block("finalP", "allminusgzfc", "allminus", "B3", "P cells (road-pressure onset PR-AUC@3s, eval/pressure_eval.py): variant vs FROZEN main", seeds) | |
| dP2, bodyP2, vP2, _ = block("finalP", "allminusgzfc", "indepgzfc", "B3", "P cells: all_minus_road2drv_gzfc vs indep_gzfc", seeds) | |
| dG, bodyG, vG, _ = block("gazec", "allminusgzfc", "indepgzfc", "B3", "gaze_off onset cells (eval/gaze_chain_eval.py, identical rows): all_minus_road2drv_gzfc vs indep_gzfc", seeds) | |
| dfs += [dA, dB, dC, dAm, dBm, dP1, dP2, dG] | |
| b1, b1_json = b1_lines(seeds, dfs) | |
| # ---- the pre-registered rule | |
| ht = {r: vA.get((r, HT, "pr_auc"), {}).get("verdict", "NO ROWS") for r in ("manual", "engaged")} | |
| ht_beats = [r for r, v in ht.items() if v == "BEATS"] | |
| insuff = any(v["verdict"] == "INSUFFICIENT" for (r, c, m), v in vA.items() if c in RJ.OWN and m == "pr_auc") | |
| n_seeds = int(dA.seed.nunique()) if len(dA) else 0 | |
| if not len(dA): | |
| decision, dtxt = "NOT DECIDABLE", "no finalc_s<k>_allminusgzfc_vs_allminus rows yet" | |
| elif n_seeds < 3 or insuff: | |
| decision, dtxt = "INSUFFICIENT", f"{n_seeds}/3 seeds paired (rule needs 3)" | |
| elif not worseA and ht_beats: | |
| decision, dtxt = "APPENDIX ROW: main + gaze chain (+face)", f"no own endpoint WORSE vs the frozen main; head_turn_onset BEATS in {ht_beats}" | |
| else: | |
| decision, dtxt = "NEGATIVE RESULT", (f"own endpoint(s) WORSE vs the frozen main: {fmt(worseA)}; " if worseA else "no own endpoint WORSE; ") + \ | |
| f"head_turn_onset verdicts manual {ht['manual']} / engaged {ht['engaged']} (needs BEATS in >= 1 regime)" | |
| allrows = pd.concat([d for d in dfs if len(d)], ignore_index=True) if any(len(d) for d in dfs) else pd.DataFrame(columns=["a", "b", "regime", "run_stamp"]) | |
| prov, stale = RJ.provenance(allrows) if len(allrows) else ([], []) | |
| void = f" — **VOID: stale rows for {stale}**" if stale else "" | |
| L = ["# Stage FINAL — gaze-chain APPENDIX variant: the frozen joint recipe on the gaze U base (`U0_kin_can_noK_s<k>_kcv2_clip8_ln_gzfc`: gaze_off chain + causal face inputs), 3 seeds, test split, both regimes", "", | |
| "Runs `I1_{indep,all_minus_road2drv}_s<k>_final_gzfc` = the FINAL command line with only the U base swapped (V0 `can4s_stats2`, E0 `pooled_P_v2`, seeds, epochs and the " | |
| "selection rule unchanged; the gaze_off chain NLL enters the U loss and the selection objective as in the U base). The frozen main model `I1_all_minus_road2drv_s<k>_final` " | |
| "and `I1_indep_s<k>_final` are read as B layouts only. Paired device-cluster bootstrap on identical rows (eval/paired_compare_joint.py, n_boot 1000; verdict = " | |
| "kill_checks.beats: ≥ 2/3 seeds CI excl. 0, same sign, |mean Δ| > seed sd); driver populations from the v2 causal kin targets (`finalc_*`), masked protocol `finalcm_*`; " | |
| "P cells by eval/pressure_eval.py (`finalP_*`), gaze cells by eval/gaze_chain_eval.py (`gazec_*`). Identity of the assembled `indep_gzfc` with its bases: " | |
| "`results/tables/identity_final_gzfc.md`. Every number comes from `results/paired_compare.csv`.", "", | |
| "**Pre-registered rule (docs/decisions.md, 2026-09-12, before training):** appendix row \"main + gaze chain (+face)\" iff in (a) NO own endpoint is WORSE vs the FROZEN main " | |
| "AND head_turn_onset BEATS in ≥ 1 regime; otherwise a negative result. The variant never replaces the headline model.", "", | |
| f"## VERDICT: **{decision}**{void}", "", f"- {dtxt}", f"- own endpoints WORSE vs frozen main: {fmt(worseA)}", f"- own endpoints BEATS vs frozen main: {fmt(boA)}", | |
| f"- cross-leg endpoints BEATS vs frozen main: {fmt(bcA)}", f"- head_turn_onset verdicts (a): manual {ht['manual']}, engaged {ht['engaged']}", | |
| f"- masked-protocol sensitivity (a): own WORSE {fmt(worseAm)}; head_turn_onset manual {vAm.get(('manual', HT, 'pr_auc'), {}).get('verdict', 'NO ROWS')} / engaged {vAm.get(('engaged', HT, 'pr_auc'), {}).get('verdict', 'NO ROWS')}", "", | |
| "## Provenance of the A / B layouts (guard 2): layout mtime, source hash, model_id / code hash, completeness; rows older than the layout are STALE", "", | |
| "| run | regime | layout mtime (UTC) | source sha256 | model_id / code | status |", "|---|---|---|---|---|---|", *prov, "", | |
| *([f"**STALE ROWS DETECTED for {stale} — every verdict is VOID; recompute (eval/run_joint_evals_final_gzfc.sh).**", ""] if stale else []), | |
| "## 1. (a) Variant vs the FROZEN main model — the pre-registered comparison", ""] + bodyA + ["", "### Own endpoints of (a) (the rule's inputs)", ""] + own_table(vA) + \ | |
| ["", f"B2-style status of (a) for reference (needs a cross-leg BEATS): **{stA}**", "", | |
| "## 2. (b) Interaction effect on the gzfc bases", ""] + bodyB + ["", f"B2-style verdict (b): **{stB}** — own WORSE {fmt(worseB)}; cross BEATS {fmt(bcB)}; own BEATS {fmt(boB)}", "", | |
| "## 3. Attribution — the U-base swap alone (indep_gzfc vs indep, no training)", ""] + bodyC + ["", f"B2-style status: **{stC}** — own WORSE {fmt(worseC)}; own BEATS {fmt(boC)}; cross BEATS {fmt(bcC)}", "", | |
| "## 4. Masked protocol (sensitivity to the 64 suspect routes)", ""] + bodyAm + [""] + bodyBm + ["", | |
| "## 5. P cells (road-pressure chains, detached head)", ""] + bodyP1 + [""] + bodyP2 + ["", | |
| "## 6. Gaze cells (gaze_off_on / gaze_off_off onset; descriptive)", ""] + bodyG + ["", | |
| "## 7. B1 on the variant (driver cells vs k0 / persistence)", ""] + b1 | |
| out = Path(a.out); out.parent.mkdir(parents=True, exist_ok=True) | |
| out.write_text("\n".join(L) + "\n") | |
| dec = {"decision": decision, "detail": dtxt, "worse_own_vs_frozen_main": fmt(worseA), "beats_own_vs_frozen_main": fmt(boA), "beats_cross_vs_frozen_main": fmt(bcA), | |
| "head_turn_onset": ht, "masked_worse_own": fmt(worseAm), "B2_style_a": stA, "B2_style_b": stB, "B1": b1_json, "stale": stale, "seeds": seeds, "n_seeds_paired_a": n_seeds, | |
| "own_endpoints_a": {f"{r}|{c}": {"mean_delta": v["mean_delta"], "verdict": v["verdict"]} for (r, c, m), v in vA.items() if c in RJ.OWN and m == "pr_auc"}} | |
| (out.parent / "stage_final_gzfc_decision.json").write_text(json.dumps(dec, indent=1, default=str)) | |
| print("\n".join(L[:12])) | |
| print(f"\nVERDICT {decision}: {dtxt}\nwritten {out} and {out.parent / 'stage_final_gzfc_decision.json'}") | |
| if __name__ == "__main__": | |
| main() | |
Xet Storage Details
- Size:
- 13 kB
- Xet hash:
- 5bed069a2ead795266533c8000bc13830b69854efb9a17f025e490ca08349f97
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.