from __future__ import annotations import argparse import hashlib import json from datetime import datetime, timezone from pathlib import Path import yaml ROOT = Path(__file__).resolve().parents[1] SNAPSHOT_FILES = [ "Temp/final_decision_packet_active.json", "runtime/active_artifact_manifest.yaml", "spec/41_release_dag.yaml", "package.json", ] def _sha256(path: Path) -> str: if not path.exists(): return "FILE_MISSING" return hashlib.sha256(path.read_bytes()).hexdigest() def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--out", default="runtime/rollback_manifest_v3.yaml") args = ap.parse_args() entries = [] for rel in SNAPSHOT_FILES: p = ROOT / rel entries.append({"path": rel, "sha256": _sha256(p)}) combined = "".join(e["sha256"] for e in entries if e["sha256"] != "FILE_MISSING") rollback_hash = hashlib.sha256(combined.encode()).hexdigest() if combined else "NO_HASH" manifest = { "formula_id": "REFACTOR_ROLLBACK_MANIFEST_V3", "generated_at": datetime.now(timezone.utc).isoformat(), "rollback_hash": rollback_hash, "rollback_hash_present": bool(rollback_hash and rollback_hash != "NO_HASH"), "snapshot_files": entries, } out_path = ROOT / args.out out_path.parent.mkdir(parents=True, exist_ok=True) out_path.write_text(yaml.dump(manifest, allow_unicode=True, default_flow_style=False), encoding="utf-8") print(f"rollback_hash_present: {manifest['rollback_hash_present']}") print(f"rollback_hash: {rollback_hash[:16]}...") print(f"Written to: {out_path}") return 0 if __name__ == "__main__": raise SystemExit(main())