"""audit.json + eye.json -> summary.json + a table printed for audit.md. No network.""" import json from collections import defaultdict from pathlib import Path H = Path(__file__).parent a = json.loads((H / "audit.json").read_text(encoding="utf-8")) eye = json.loads((H / "eye.json").read_text(encoding="utf-8")) acc = a["accounts"] handles = {d: v["handle"] for d, v in acc.items()} assert set(handles.values()) == set(k for k in eye if not k.startswith("_")), "eye.json must cover every account" final = {d: eye[h][0] for d, h in handles.items()} tally = defaultdict(int) for v in final.values(): tally[v] += 1 heur = defaultdict(int) for v in acc.values(): heur[v["auto_verdict"]] += 1 by_type = defaultdict(lambda: {"posts": 0, "human_reactions": 0, "humans": set(), "auto_reactions": 0, "unclear_reactions": 0}) rows = [] for p in a["posts"]: t = by_type[p["type"]]; t["posts"] += 1 hum = [handles[d] for d in p["responders"] if final[d] == "likely human"] nh = {"likely human": 0, "automated": 0, "unclear": 0} for d in p["responders"]: nh[final[d]] += 1 t["human_reactions"] += nh["likely human"]; t["auto_reactions"] += nh["automated"]; t["unclear_reactions"] += nh["unclear"] t["humans"].update(hum) rows.append((p["created"][:16], p["rkey"], p["type"], p["counts"]["likes"], p["counts"]["reposts"], nh, hum)) out = {"run_at": a["run_at"], "n_posts": a["n_posts"], "n_accounts": len(acc), "n_followers": a["n_followers"], "final_tally": dict(tally), "heuristic_tally": dict(heur), "overrides": sum(1 for h in eye if not h.startswith("_") and "OVERRIDE" in eye[h][1]), "by_type": {k: {**v, "humans": sorted(v["humans"])} for k, v in by_type.items()}, "followers_by_verdict": {v: sum(1 for d, x in acc.items() if x["follower"] and final[d] == v) for v in ("likely human", "automated", "unclear")}} (H / "summary.json").write_text(json.dumps(out, indent=1, ensure_ascii=False), encoding="utf-8") print(json.dumps({k: v for k, v in out.items() if k != "by_type"}, ensure_ascii=False)) print("| type | posts | reactions by likely humans | distinct likely humans | by automated | by unclear |") for k, v in sorted(by_type.items(), key=lambda kv: -len(kv[1]["humans"])): print(f"| {k} | {v['posts']} | {v['human_reactions']} | {len(v['humans'])} ({', '.join(sorted(v['humans'])) or '-'}) | {v['auto_reactions']} | {v['unclear_reactions']} |") print() for r in rows: print(f"| {r[0]} | [{r[1]}](https://bsky.app/profile/vonk.cavu.social/post/{r[1]}) | {r[2]} | {r[3]} | {r[4]} | {r[5]['likely human']} | {r[5]['automated']} | {r[5]['unclear']} | {', '.join(r[6]) or '-'} |")