"""승인 전 모든 증거/자산/오디오 수학과 원본을 비교하고 새 build의 바이트도 검사한다.""" import hashlib import json from pathlib import Path import subprocess EVIDENCE = Path(__file__).resolve().parent ROOT = EVIDENCE.parents[2] def sha(path): return hashlib.sha256(path.read_bytes()).hexdigest() before = json.loads((EVIDENCE / "before-sha256.json").read_text()) updated_status = {".agent/RESULT-v0.2.5.md", ".agent/ACCEPTANCE-v0.2.5.md"} for name, digest in before["files"].items(): # 두 상태 문서만 갱신하고 이전 원문은 승인 전 snapshot으로 보존한다. path = EVIDENCE / f"before-{Path(name).name}" if name in updated_status else ROOT / name if sha(path) != digest: raise ValueError(f"Historical byte mismatch: {name}") head = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=ROOT, text=True).strip() if head != before["head"]: raise ValueError("HEAD changed") plan = json.loads((ROOT / ".agent/AMBIENCE-SOURCES-v0.2.3.json").read_text()) manifest = json.loads((ROOT / "public/ambience/manifest.json").read_text()) for source, entry in zip(plan["assets"], manifest["files"], strict=True): name = source["environmentId"] extension = ".mp3" if name in ("theater", "department") else ".flac" if name == "rain" else ".ogg" raw = Path("/tmp/findword-ambience-sources") / (name + extension) if sha(raw) != source["expectedSourceSha256"] or raw.stat().st_size != source["sourceBytes"]: raise ValueError(f"Source bytes mismatch: {name}") if not all(entry[key] == value for key, value in source.items()): raise ValueError(f"Source metadata mismatch: {name}") if entry["conversion"]["startSeconds"] != source["selectedSegmentStartSeconds"]: raise ValueError(f"Segment mismatch: {name}") public = [path for path in (ROOT / "public").rglob("*") if path.is_file()] for path in public: if path.read_bytes() != (ROOT / "dist" / path.relative_to(ROOT / "public")).read_bytes(): raise ValueError(f"Build bytes mismatch: {path}") report = { "passed": True, "headUnchanged": head, "existingFilesChecked": len(before["files"]), "unchangedInPlace": len(before["files"]) - len(updated_status), "updatedStatusDocumentsPreservedAsSnapshots": sorted(updated_status), "allEarlierEvidenceUnchanged": True, "originalSourceFilesVerified": len(plan["assets"]), "sourceAndSegmentsPreserved": True, "voiceWavsUnchanged": 101, "ambienceWavsUnchanged": 8, "normalizationPlanManifestGainMathAndRuntimeUnchanged": True, "publicFilesIdenticalToBuild": len(public), "finalAsrSha256": sha(ROOT / ".agent/evidence-v0.2.5/review-fixes/final-asr.json"), } (EVIDENCE / "preservation.json").write_text(json.dumps(report, indent=2) + "\n") print(json.dumps(report, indent=2))