1"""Assemble the named deliverables of the mandate (§24) from the repository state."""2import os, sys, csv, shutil, subprocess, zipfile, json, datetime3REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")); REL = os.path.join(REPO, "release")4def main():5 shutil.copy(os.path.join(REPO, "paper", "main.pdf"), os.path.join(REL, "WP29_Autonomous_Research_Claude_Code_Boucher.pdf"))6 shutil.copy(os.path.join(REPO, "results", "analysis_data", "runs.csv"), os.path.join(REL, "WP29_Experiment_Results.csv"))7 # human interventions + costs8 rows = list(csv.DictReader(open(os.path.join(REPO, "reports", "interventions.csv"))))9 acc = open(os.path.join(REPO, "reports", "experiment_accounting.md")).read()10 with open(os.path.join(REL, "WP29_Human_Interventions_and_Costs.csv"), "w", newline="") as fh:11 w = csv.writer(fh); w.writerow(["record_type", "id", "timestamp_utc", "actor_or_split", "category", "description", "duration_or_cost", "measurement_basis"])12 for r in rows: w.writerow(["human_intervention", r["intervention_id"], r["timestamp_utc"], r["actor"], r["category"], r["description"], r["duration_minutes"], r["measurement_basis"]])13 import pandas as pd14 s = pd.read_csv(os.path.join(REPO, "results", "analysis_data", "sessions.csv")); rr = pd.read_csv(os.path.join(REPO, "results", "analysis_data", "runs.csv"))15 for sp, d in rr.groupby("split"):16 w.writerow(["inference_cost", sp, "", sp, "inference", f"{len(d)} runs, {int(s.run_id.isin(d.run_id).sum())} sessions", f"{s[s.run_id.isin(d.run_id)].session_cost_usd.sum():.2f} USD", "client list-price estimate (total_cost_usd)"])17 be = json.load(open(os.path.join(REPO, "reports", "builder_effort.json")))18 for k, v in be["subagents"].items(): w.writerow(["builder_subsession", k, "", "builder", "delegated work", k, f"{v['tokens']} tokens / {v['duration_min']:.0f} min", "client task notification"])19 for k, v in be["builder"].items(): w.writerow(["builder_session", k, "", "builder", "builder work", k, v["wall"], v["basis"]])20 # visual evidence appendix (standalone PDF of the gallery)21 tex = r"""\documentclass[11pt]{article}\usepackage[margin=0.8in]{geometry}\usepackage{graphicx}\usepackage{hyperref}\usepackage[T1]{fontenc}\usepackage[utf8]{inputenc}22\DeclareUnicodeCharacter{2192}{$\rightarrow$}\DeclareUnicodeCharacter{2014}{---}\DeclareUnicodeCharacter{2013}{--}23\begin{document}\title{WP29 --- Visual Evidence Appendix}\author{Simon-Pierre Boucher, UQO}\date{October 2026}\maketitle24\noindent Companion to UQO Working Paper 29. All captures are authentic (native \texttt{screencapture}); modes, hashes and selection rules follow the screenshot manifest. Capture failures are listed without images.25\input{appendices/gallery}\end{document}"""26 vt = os.path.join(REPO, "paper", "visual_appendix.tex"); open(vt, "w").write(tex)27 r = subprocess.run(["pdflatex", "-interaction=nonstopmode", "visual_appendix.tex"], cwd=os.path.join(REPO, "paper"), capture_output=True, text=True)28 vp = os.path.join(REPO, "paper", "visual_appendix.pdf")29 if os.path.exists(vp): shutil.copy(vp, os.path.join(REL, "WP29_Visual_Evidence_Appendix.pdf"))30 else: print("visual appendix failed", r.stdout[-500:])31 # method + implementation zip32 z = zipfile.ZipFile(os.path.join(REL, "WP29_Method_and_Implementation.zip"), "w", zipfile.ZIP_DEFLATED)33 for d in ["src", "protocol", "configs", "evaluators", "tests", "analysis", "tasks", "README.md", "Makefile", "pyproject.toml", "CLAUDE.md", "reports"]:34 p = os.path.join(REPO, d)35 if os.path.isfile(p): z.write(p, d)36 else:37 for root, _, fs in os.walk(p):38 for f in fs:39 if "__pycache__" in root or f.endswith(".pyc"): continue40 q = os.path.join(root, f); z.write(q, os.path.relpath(q, REPO))41 z.close()42 # hidden oracles for reviewers only (restricted, not committed)43 os.makedirs(os.path.join(REL, "restricted"), exist_ok=True)44 zo = zipfile.ZipFile(os.path.join(REL, "restricted", "WP29_Oracles.zip"), "w", zipfile.ZIP_DEFLATED)45 orc = os.path.expanduser("~/wp29-oracles")46 for root, _, fs in os.walk(orc):47 for f in fs:48 if "__pycache__" in root or f.endswith(".pyc"): continue49 q = os.path.join(root, f); zo.write(q, os.path.relpath(q, os.path.dirname(orc)))50 zo.close()51 # final review (concatenate the three sub-session reviews + builder response)52 parts = ["# WP29 — Final review record", "", f"Assembled {datetime.datetime.now(datetime.timezone.utc).isoformat(timespec='seconds')}. Reviewers are Claude Code sub-sessions (claude-fable-5-1) of the same client family as the builder; no human review had occurred at build time. The builder's responses are in `reports/final_review.md`.", ""]53 for f in ["review_systems_isolation.md", "review_statistics_evaluators.md", "review_manuscript.md", "final_review.md"]:54 p = os.path.join(REPO, "reports", f)55 if os.path.exists(p): parts += [f"\n\n---\n\n<!-- {f} -->\n", open(p).read()]56 open(os.path.join(REL, "WP29_Final_Review.md"), "w").write("\n".join(parts))57 print("release assembled:", sorted(os.listdir(REL)))58if __name__ == "__main__": main()59