"""Synthetic recovery metadata tests, not Blender acceptance evidence.""" import hashlib import json import pathlib import tempfile import unittest from recover_behavior_contracts import candidate, KINDS class RecoveryTests(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() self.addCleanup(self.temp.cleanup) self.root = pathlib.Path(self.temp.name) self.worker = self.root / "run/worker-result.json" self.worker.parent.mkdir() self.contract = {"job": "SCULPT", "task": "TASK", "result": {"sourceUnits": ["stroke", "remesh"]}} self.cases = [{"id": kind, "kind": kind, "unitIds": ["stroke", "remesh"], "receipt": f"run/{kind}.json"} for kind in sorted(KINDS)] self.worker.write_text(json.dumps({"cases": self.cases, "sourceUnits": ["stroke", "remesh"]})) (self.root / "source.cc").write_text("synthetic source") def digest(path): return hashlib.sha256(path.read_bytes()).hexdigest() artifacts = [] for case in self.cases: path = self.root / case["receipt"] path.write_text(json.dumps({"status": "PASS", "runtime": "CHROMIUM_WEBENGINE", "caseId": case["id"], "kind": case["kind"], "unitIds": case["unitIds"]})) artifacts.append({"path": case["receipt"], "sha256": digest(path)}) self.proof = self.root / "run/verified-receipt.json" self.proof.write_text(json.dumps({"status": "verified", "job": "SCULPT", "queueTask": "TASK", "sourceUnits": ["stroke", "remesh"], "artifacts": artifacts, "inputs": {"source.cc": digest(self.root / "source.cc")}})) def test_valid_metadata_is_rebound_for_fresh_execution(self): result = candidate(self.worker, self.contract, self.root) self.assertIsNotNone(result) self.assertTrue(all(case["receipt"].startswith("unallocated/") for case in result["cases"])) def test_case_count_without_verified_receipt_is_rejected(self): self.proof.unlink() self.assertIsNone(candidate(self.worker, self.contract, self.root)) def test_scope_cannot_drop_remesh(self): self.worker.write_text(json.dumps({"cases": self.cases, "sourceUnits": ["stroke"]})) self.assertIsNone(candidate(self.worker, self.contract, self.root)) def test_missing_receipt_is_rejected(self): (self.root / self.cases[0]["receipt"]).unlink() self.assertIsNone(candidate(self.worker, self.contract, self.root)) def test_changed_source_is_rejected(self): (self.root / "source.cc").write_text("modified source") self.assertIsNone(candidate(self.worker, self.contract, self.root)) if __name__ == "__main__": unittest.main()