#!/usr/bin/env python3 """Write results/manifest.json: every result artefact with size, SHA-256, producing script and inputs.""" import hashlib import json import subprocess import time from pathlib import Path ROOT = Path(__file__).resolve().parents[1] R = ROOT / "results" PRODUCERS = { "tables/frame_exclusions.csv": "src/ingestion/build_frame.py", "tables/robots_exclusion_balance.csv": "src/ingestion/build_frame.py", "raw/frame_summary.json": "src/ingestion/build_frame.py", "raw/sample_summary.json": "src/ingestion/sample.py", "raw/exp_agreement.json": "scripts/06_exp_agreement.py", "raw/exp_cost.json": "scripts/07_exp_cost.py", "raw/aggregate_summary.json": "scripts/05_aggregate.py", "raw/api_usage.jsonl": "src/extraction/client.py", "raw/image_hosts.json": "ad hoc host census (research_log 2026-10-20)", "raw/robots_check.txt": "curl robots.txt census (research_log)", } def sha(p: Path) -> str: h = hashlib.sha256() with open(p, "rb") as fh: for chunk in iter(lambda: fh.read(1 << 20), b""): h.update(chunk) return h.hexdigest() def main(): items = [] for p in sorted(R.rglob("*")): if p.is_dir() or p.name == "manifest.json" or ".DS_Store" in p.name: continue rel = str(p.relative_to(R)) prod = PRODUCERS.get(rel) if prod is None: if rel.startswith("tables/exp1") and rel.startswith(("tables/exp1_", "tables/exp2", "tables/exp3", "tables/exp4", "tables/exp9", "tables/exp12", "tables/exp16")): prod = "scripts/06_exp_agreement.py" elif rel.startswith("tables/exp"): prod = "scripts/07_exp_cost.py" if any(rel.startswith(f"tables/exp{k}") for k in ("5", "6", "7", "10", "13", "14", "15")) else "scripts/06_exp_agreement.py" elif rel.startswith("tables/tex/"): prod = "src/visualization/tables.py" elif rel.startswith("figures/"): prod = "src/visualization/figures.py" elif rel.startswith("raw/batches/"): prod = "scripts/04_run_batches.py (Anthropic Message Batches API)" items.append({"path": rel, "bytes": p.stat().st_size, "sha256": sha(p), "producer": prod, "modified": time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(p.stat().st_mtime))}) try: commit = subprocess.run(["git", "rev-parse", "HEAD"], cwd=ROOT, capture_output=True, text=True).stdout.strip() except Exception: commit = None manifest = {"generated": time.strftime("%Y-%m-%dT%H:%M:%S"), "git_commit": commit or "uncommitted", "schema_version": json.load(open(R / "raw" / "batches" / "run_meta.json"))["schema_version"], "prompt_version": json.load(open(R / "raw" / "batches" / "run_meta.json"))["prompt_version"], "n_items": len(items), "items": items} json.dump(manifest, open(R / "manifest.json", "w"), indent=1) print(len(items), "artefacts listed") if __name__ == "__main__": main()