Files
workinf_Blender_Wasm/my-tools/recover_behavior_contracts.py
mes123456 f3e21c6b98
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
chore: checkpoint web Blender migration source, tools and docs
Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer,
web workflow engine and protocol, tooling, docs and task records.
Large generated evidence, user-testing archives, build snapshots and
imported test assets remain untracked.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-11-10 11:18:01 +08:00

78 lines
3.3 KiB
Python

#!/usr/bin/env python3
"""Recover only complete, scope-preserving behavior contracts from valid receipts."""
import copy
import hashlib
import json
from pathlib import Path
from wbv2_autopilot import ROOT, contained, read_json, write_json
KINDS = {"positive", "negative", "undo_redo", "save_reopen", "determinism"}
def candidate(worker, contract, root=ROOT):
try:
value = read_json(worker)
proof = read_json(worker.parent / "verified-receipt.json")
required = set(contract["result"]["sourceUnits"])
if (proof.get("status") != "verified" or proof.get("job") != contract["job"]
or proof.get("queueTask") != contract["task"]
or not required.issubset(value.get("sourceUnits", []))
or not required.issubset(proof.get("sourceUnits", []))):
return None
cases = value.get("cases", [])
if not KINDS.issubset({case["kind"] for case in cases}):
return None
artifacts = {item["path"]: item["sha256"] for item in proof.get("artifacts", [])}
inputs = proof.get("inputs", {})
if not artifacts or not inputs:
return None
for relative, digest in {**inputs, **artifacts}.items():
path = contained(root, relative)
if (not path.is_file() or hashlib.sha256(path.read_bytes()).hexdigest() != digest):
return None
for case in cases:
receipt_path = contained(root, case["receipt"])
if case["receipt"] not in artifacts:
return None
receipt = read_json(receipt_path)
if (receipt.get("status") != "PASS"
or receipt.get("runtime") not in {"CHROMIUM_WEBENGINE", "BLENDER_NATIVE"}
or receipt.get("caseId") != case["id"]
or receipt.get("kind") != case["kind"]
or set(receipt.get("unitIds", [])) != set(case["unitIds"])):
return None
result = copy.deepcopy(value)
result.pop("contractKind", None)
result.pop("mandatoryCacheInputs", None)
for case in result["cases"]:
case["receipt"] = "unallocated/" + case["id"] + ".json"
return result
except (OSError, ValueError, KeyError, TypeError):
return None
def main():
recovered, unavailable = [], []
for path in sorted((ROOT / "my-tools/local-workflows").glob("*.json")):
contract = read_json(path)
if contract.get("result", {}).get("contractKind") != "compilation_only":
continue
job = contract["job"]
candidates = []
for worker in (ROOT / "tests/golden/WBV2/autopilot/runs").glob(job + "-*/worker-result.json"):
result = candidate(worker, contract)
if result:
candidates.append((worker.stat().st_mtime_ns, result))
if not candidates:
unavailable.append(job)
continue
contract["result"] = max(candidates, key=lambda item: item[0])[1]
contract["acceptance"] = "pending fresh execution; historical receipts are not new results"
write_json(path, contract)
recovered.append(job)
print(json.dumps({"recovered": recovered, "count": len(recovered), "unavailable": unavailable}))
if __name__ == "__main__":
main()