#!/usr/bin/env python3
"""Build claims.json for the ARIS evidence pre-check from the actual data files.

Every cited value is taken verbatim from its source file so that a `value_not_found`
status can only mean the ledger drifted from the data (or the checker's boundary rule
rejected the token), never that a number was typed from memory.
Run from the repo root:  python3 paper/distill-fingerprint/build_claims.py
"""
import json, sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
OUT = ROOT / "bench/scripts/paper/out"
DATA = ROOT / "paper/distill-fingerprint/data"

fs = json.loads((OUT / "fp_summary.json").read_text())
fp = json.loads((OUT / "fp_pooled.json").read_text())
p8 = json.loads((OUT / "p8_train100.json").read_text())
to = json.loads((OUT / "think_overshoot.json").read_text())
lr = json.loads((OUT / "lang_robustness.json").read_text())
oa = json.loads((OUT / "overclaim_annotation.json").read_text())
rep = json.loads((DATA / "report.json").read_text())
# The 5.9 MB report.json makes the token scan slow; the pre-check cites a verbatim excerpt
# (arms core fields + all paired tests + ledger call counts) written here from the same object.
CORE = ["n", "solved", "end", "steps_med", "ctx_last_med", "obs_sum_med", "out_sum_med", "sec_med", "think_med", "tool_err_rate"]
excerpt = {"arms": {k: {f: v[f] for f in CORE if f in v} for k, v in rep["arms"].items()},
           "tests": rep["tests"],
           "ledger": {k: {f: v[f] for f in ("main|calls", "side|calls", "tool|Agent|calls") if f in v} for k, v in rep["ledger"].items()}}
json.dump(excerpt, open(DATA / "report_excerpt.json", "w"), indent=1, ensure_ascii=False)

claims = []
def add(cid, value, source, note=""):
    claims.append({"id": cid, "value": str(value), "source": source, "note": note})

FS = "bench/scripts/paper/out/fp_summary.json"
FSMD = "bench/scripts/paper/out/fp_summary.md"
FP = "bench/scripts/paper/out/fp_pooled.json"
P8 = "bench/scripts/paper/out/p8_train100.json"
TO = "bench/scripts/paper/out/think_overshoot.json"
LR = "bench/scripts/paper/out/lang_robustness.json"
OA = "bench/scripts/paper/out/overclaim_annotation.json"
REP = "paper/distill-fingerprint/data/report_excerpt.json"

# H1 — distances (exact floats from fp_summary.json)
for arm in ["n27|pro", "s128|pro", "s256|pro", "s381|pro", "v13|pro", "a3b_q36|pro", "a3b_v12|pro", "a3b_base|pro", "a3b_2ep|pro", "q38|pro", "s256_t100|train100", "n27_t100|train100", "T_bp_failed"]:
    d = fs["dists"][arm]
    add(f"H1.composite.{arm}", d["composite"], FS, "composite JS to teacher")
    add(f"H1.bash.{arm}", d["js_bash"], FS, "bash-vocabulary JS to teacher")
add("H1.thinkpos.n27", fs["dists"]["n27|pro"]["js_thinkpos"], FS)
add("H1.thinkpos.s256", fs["dists"]["s256|pro"]["js_thinkpos"], FS)
add("H1.thinkpos.q38", fs["dists"]["q38|pro"]["js_thinkpos"], FS)
# rounded forms used in the paper text (present in fp_summary.md table)
for cid, v in [("H1.md.bash.n27", "0.202"), ("H1.md.bash.s381", "0.050"), ("H1.md.composite.n27", "0.0285"), ("H1.md.composite.s381", "0.0213"), ("H1.md.bash.a3b_q36", "0.195"), ("H1.md.bash.a3b_v12", "0.061"), ("H1.md.bash.q38", "0.061")]:
    add(cid, v, FSMD, "rounded value as printed in the summary table")
# language strata
for arm in ["n27", "s256"]:
    for lang in ["Python", "Go", "JS/TS"]:
        add(f"H1.lang.{arm}.{lang}.bash", lr[arm][lang][1], LR, "bash JS within language")
add("H1.pyref.n27.composite", lr["_python_ref"]["pro_python"]["n27"][0], LR)
add("H1.pyref.s256.composite", lr["_python_ref"]["pro_python"]["s256"][0], LR)
add("H1.pyref.verified.n27.composite", lr["_python_ref"]["verified"]["n27"][0], LR)
add("H1.pyref.verified.s381.composite", lr["_python_ref"]["verified"]["s381"][0], LR)

# H2 — scores and paired tests (report.json)
for arm in ["q38|pro", "n27|pro", "s128|pro", "s256|pro", "s381|pro", "v13|pro", "a3b_base|pro", "a3b_2ep|pro", "a3b_q36|pro", "a3b_v12|pro", "q38|verified", "n27|verified", "s128|verified", "s256|verified", "s381|verified", "v13|verified", "a3b_base|verified", "a3b_2ep|verified", "a3b_q36|verified", "a3b_v12|verified"]:
    add(f"H2.solved.{arm}", rep["arms"][arm]["solved"], REP, "solved count")
for t in ["pro|n27 vs q38", "verified|n27 vs q38", "pro|s128 vs n27", "pro|s256 vs n27", "pro|s381 vs n27", "pro|v13 vs n27", "verified|s128 vs n27", "verified|s256 vs n27", "verified|s381 vs n27", "verified|v13 vs n27", "verified|v13 vs s381", "pro|a3b_2ep vs a3b_base", "verified|a3b_2ep vs a3b_base", "pro|a3b_v12 vs a3b_q36", "verified|a3b_v12 vs a3b_q36", "pro|a3b_v12t06 vs a3b_q36t06", "pro|a3b_q36 vs n27", "verified|a3b_q36 vs n27", "pro|a3b_v12 vs s381", "verified|a3b_v12 vs s381", "pro|a3b_q36t06 vs a3b_q36", "pro|a3b_v12t06 vs a3b_v12", "pro|s256 vs s128"]:
    v = rep["tests"][t]
    add(f"H2.test.{t}.delta", v["delta"], REP, "McNemar paired delta (pool denominator)")
    add(f"H2.test.{t}.p", v["p"], REP, "McNemar exact p")
    add(f"H2.test.{t}.b", v["b"], REP); add(f"H2.test.{t}.c", v["c"], REP)

# H3 — cost ledger fields
for arm in ["n27|pro", "s256|pro", "s381|pro", "v13|pro", "q38|pro", "a3b_q36|pro", "a3b_v12|pro", "a3b_q36t06|pro", "a3b_v12t06|pro"]:
    a = rep["arms"][arm]
    for f in ["steps_med", "ctx_last_med", "obs_sum_med", "out_sum_med", "sec_med"]:
        add(f"H3.{f}.{arm}", a[f], REP)
for arm in ["T_hp", "n27|pro", "s256|pro", "a3b_q36|pro", "a3b_v12|pro", "q38|pro"]:
    add(f"H3.trunc_pipe.{arm}", fp[arm]["trunc_pipe"], FP); add(f"H3.read_limit.{arm}", fp[arm]["read_limit"], FP)
PAGE3 = "bench/results/轨迹检查/可视化分析/三线定稿-q38-画像.html"
PAGE27 = "bench/results/轨迹检查/可视化分析/qwen36-27b-v12-画像.html"
for s, src, v in [("3.27M", PAGE3, "n27 cumulative input"), ("1.52M", PAGE27, "s256 cumulative input"), ("4.41M", PAGE3, "q38 cumulative input"), ("7,293", PAGE3, "whole-file reads a3b_q36"), ("2,578", PAGE3, "whole-file reads a3b_v12")]:
    add(f"H3.page.{s}", s, src, v)

# H4 — wording / audit / noise
for arm in ["n27|pro", "s128|pro", "s256|pro", "s381|pro", "v13|pro", "q38|pro", "T_bp_failed", "n27|verified", "s128|verified", "s256|verified", "s381|verified", "v13|verified"]:
    o = fs["groups"][arm]["overclaim"]
    add(f"H4.overclaim.n.{arm}", o["n"], FS); add(f"H4.overclaim.claim.{arm}", o["claim"], FS)
for cid, v in [("H4.md.claim.n27", "66.3%"), ("H4.md.claim.v13", "44.1%"), ("H4.md.claim.teacher", "44.6%"), ("H4.md.claim.q38", "24.1%"), ("H4.md.claim.s128", "52.9%")]:
    add(cid, v, FSMD)
add("H4.audit.n_total", oa["n_total"], OA); add("H4.audit.precision.pooled", oa["precision"]["pooled"][0], OA)
add("H4.audit.honest", "0/109", OA); add("H4.rat.n", oa["rationalize_audit"]["n"], OA)
add("H4.rat.verified", oa["rationalize_audit"]["composition"]["verified_attribution"][0], OA)
add("H4.rat.bare", oa["rationalize_audit"]["composition"]["bare_dismissal"][0], OA)
add("H4.rat.fp", oa["rationalize_audit"]["composition"]["false_positive"][0], OA)

# S1 — anchor
m = p8["summary"]["med"]; st = p8["summary"]["sign_tests"]
add("S1.n_tasks", p8["summary"]["n_tasks"], P8)
for k in ["n27_jread", "s256_jread", "n27_l1", "s256_l1", "n27_jedit", "s256_jedit", "t_steps", "n27_steps", "s256_steps", "t_think", "s256_think"]:
    add(f"S1.med.{k}", m[k], P8)
for k in ["l1", "jread", "jedit", "dthink"]:
    add(f"S1.sign.{k}.s256_wins", st[k]["s256_wins"], P8); add(f"S1.sign.{k}.n27_wins", st[k]["n27_wins"], P8); add(f"S1.sign.{k}.p", st[k]["p"], P8)

# S2 — error handling
for arm in ["T_hp", "n27|pro", "s128|pro", "s256|pro", "s381|pro", "v13|pro", "q38|pro", "a3b_q36|pro", "a3b_v12|pro"]:
    add(f"S2.recovery3.{arm}", fp[arm]["recovery3"], FP); add(f"S2.react_ratio.{arm}", fp[arm]["react_ratio"], FP); add(f"S2.rework.{arm}", fp[arm]["rework"], FP)

# S3 — thinking
add("S3.corpus_think_share", to["think_share"], TO); add("S3.think_chars", to["think_chars"], TO); add("S3.text_chars", to["text_chars"], TO); add("S3.assistant_loss", to["assistant_loss"], TO)
for k, v in to["refs"].items():
    add(f"S3.ref.{k}", v, TO)
for arm in ["T_hp", "n27|pro", "s256|pro", "v13|pro", "q38|pro"]:
    add(f"S3.think_share.{arm}", fp[arm]["think_share"], FP)
    add(f"S3.mix.taskmgmt.{arm}", fs["groups"][arm]["mix"][6], FS, "tool-mix bucket Task管理")
    add(f"S5.mix.subagent.{arm}", fs["groups"][arm]["mix"][7], FS, "tool-mix bucket 子代理")

# S4 — q38 reading habits
for arm in ["T_hp", "q38|pro", "s256|pro"]:
    add(f"S4.noread.{arm}", fp[arm]["noread"], FP); add(f"S4.write_share.{arm}", fp[arm]["write_share"], FP)

# S5 — sub-agent share (report ledger) and git-history reads (page)
for arm in ["n27|pro", "a3b_q36|pro", "s256|pro", "q38|pro"]:
    led = rep["ledger"][arm]
    add(f"S5.side_calls.{arm}", led.get("side|calls", 0), REP, "calls executed inside sub-agent side-chains")
    add(f"S5.main_calls.{arm}", led.get("main|calls", 0), REP)

json.dump(claims, open(ROOT / "paper/distill-fingerprint/claims.json", "w"), indent=1, ensure_ascii=False)
print(len(claims), "claims written")
