"""Read-only verification of frozen native receipts and exact saved source bytes.""" from pathlib import Path, PurePosixPath from datetime import datetime import hashlib import io import json import zipfile ROOT = Path(__file__).resolve().parent HEAD = "df2e1cd65ca5e56f47669e04a9d4bcb426900fcd" GUI = {"bytes": 115056640, "sha256": "4070927256414a770c5fbcedfaab922810cea33d9f07610b81e9ab8c0465da44"} CLI = {"bytes": 20608512, "sha256": "d89aba9f10b598926dfdc5c644474ae891b753e8583a184860e941a359ed0eea"} BUILD = {"bytes": 5538, "sha256": "25c7878f56395ed1e8e6b3532fd9135e0b313fd2b781a4c982f9f2b01a4ec64b"} INPUTS = {"bytes": 102567, "sha256": "6bf74c1f68431a034681b754617c39d387783f71354c9106649aec9480e4f29f"} SOURCES = {"bytes": 2483742, "sha256": "e20f33dc363850a9289103a7be28ad613c3fffb2039061957a0186cac72d541b"} ACTIVITY_PATH = "oa/activities/activity_new_activity.arcadia" ACTIVITY = b'\noa_activity new_activity "New activity" id "1e1da408-da79-42ab-a990-9d00b7dc2631" {\n}\n\n\n' FIXTURE = b'''arcadia 7; project p "Compact source workflow" id "00000000-0000-4000-8000-000000000001" { oa_activity work "Work" id "00000000-0000-4000-8000-000000000002" {} diagram view "Overview" id "00000000-0000-4000-8000-000000000003" {} node placement id "00000000-0000-4000-8000-000000000004" { diagram @view; element @work; position { x 120.0; y 80.0; }; port_anchors [] ; // Keep explicit automatic placement. } } ''' LABELS = { "trial-1": "01-home 02-open-dialog 03-open-file-field 05-open-after-uia-error 06-open-focused 07-open-path-typed 08-project-opened 09-project-settled 10-open-keyboard-ready 11-open-submitted 12-model-explorer 13-created-activity 14-generated-source 15-source-folder 16-activity-source-row 17-compact-new-activity 18-save-before-request 19-save-before-dialog 20-cleanup-save-dialog 21-cleanup-filename-focus 22-cleanup-filename-caret 23-cleanup-save-path 24-cleanup-save-path-settled 25-cleanup-filename-refocus 26-cleanup-save-path-retry 27-cleanup-save-submitted".split(), "trial-2": "01-home 02-open-baseline 03-baseline-loaded 04-drag-work 05-text-after-move 06-model-actions 07-undo-model 08-redo-menu 09-redo-model 10-save-as-request 11-save-dialog 12-save-filename-focus 13-select-filename 14-enter-save-path 15-correct-path-selection 16-save-path-corrected 17-save-complete 18-home-reopen 19-clear-current-model 20-empty-home 21-reopen-request 22-reopened-root 23-open-source-folder 24-activity-source-list 25-reopened-compact-activity".split(), } def require(condition, message): if not condition: raise SystemExit(message) def digest(data): return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()} def membership(archive, expected, label): names = archive.namelist() require(len(names) == len(set(names)) and set(names) == set(expected), label + ": ZIP membership mismatch") require(all(not PurePosixPath(n).is_absolute() and ".." not in PurePosixPath(n).parts and "\\" not in n and ":" not in n for n in names), label + ": unsafe ZIP member") def time(value): parsed = datetime.fromisoformat(value.replace("Z", "+00:00")) require(parsed.tzinfo is not None, "Timestamp missing timezone") return parsed outer = json.loads((ROOT / "files.json").read_text(encoding="utf-8")) require(set(outer) == {"README.md", "verify.py", "evidence.zip"}, "Outer manifest membership mismatch") require({p.name for p in ROOT.iterdir()} == set(outer) | {"files.json"}, "Outer directory membership mismatch") for name, pin in outer.items(): require(digest((ROOT / name).read_bytes()) == pin, "Outer hash mismatch: " + name) with zipfile.ZipFile(ROOT / "evidence.zip") as z: def read(name): return z.read(name) def obj(name): return json.loads(read(name)) pins = obj("capture-files.json") membership(z, set(pins) | {"capture-files.json"}, "Evidence") for name, pin in pins.items(): require(digest(read(name)) == pin, "Payload hash mismatch: " + name) build = obj("build/result.json") require(digest(read("build/result.json")) == BUILD, "Original build receipt mismatch") require(build["head"] == HEAD and build["exitCode"] == 0 and build["inputsUnchanged"] is True, "Build closure mismatch") require(build["inputs"] == INPUTS and build["archive"] == SOURCES, "Build source identity mismatch") require(all(build.get(k) == v for k, v in obj("build/started.json").items()), "Build start/result mismatch") require(time(build["start"]) <= time(build["finish"]), "Build chronology mismatch") require(build["command"] == ["cargo", "build", "--locked", "--offline", "--workspace", "--bins", "--message-format=json"], "Build command mismatch") for key, name in [("inputs", "inputs.json"), ("archive", "inputs.zip"), ("helper", "gate-policy.py"), ("stdout", "stdout.log"), ("stderr", "stderr.log")]: require(digest(read("build/" + name)) == build[key], "Build payload mismatch: " + name) source_pins = obj("build/inputs.json") require(len(source_pins) == build["inputCount"] == 613, "Source count mismatch") with zipfile.ZipFile(io.BytesIO(read("build/inputs.zip"))) as sources: membership(sources, source_pins, "Source") for name, pin in source_pins.items(): require(digest(sources.read(name)) == pin, "Source blob mismatch: " + name) build_events = [json.loads(line) for line in read("build/stdout.log").decode().splitlines() if line.startswith("{")] require([e.get("success") for e in build_events if e.get("reason") == "build-finished"] == [True], "Build success event mismatch") require([e for e in build_events if e.get("reason") == "compiler-artifact" and e.get("executable")] == [a["cargo"] for a in build["artifacts"]], "Build artifact log mismatch") binaries = {a["cargo"]["target"]["name"]: a for a in build["artifacts"]} require(binaries["arcadia-studio"]["readback"] == GUI and binaries["arcadia"]["readback"] == CLI, "Native binary build identity mismatch") expected = {"build/" + n for n in ["result.json", "started.json", "stdout.log", "stderr.log", "inputs.json", "inputs.zip", "gate-policy.py"]} expected |= {"native/" + n for n in ["run-native.py", "run-native-followup.py", "capture-snippet.js", "check-fixture.py", "verify-creation-checkpoint.py", "fixture-check.result.json", "fixture-check.stdout.json", "fixture-check.stderr.log", "input/project.arcadia"]} before = FIXTURE[:-2] + b'\n include "oa/activities/activity_new_activity.arcadia";\n}\n' after = before.replace(b"position { x 120.0; y 80.0; };", b"position { x 190.0; y 80.0; };") require(read("native/input/project.arcadia") == FIXTURE, "Input fixture bytes mismatch") for label, root in [("saved-before", before), ("saved-after", after)]: expected |= {f"native/{label}/project.arcadia", f"native/{label}/{ACTIVITY_PATH}"} require(read(f"native/{label}/project.arcadia") == root and read(f"native/{label}/{ACTIVITY_PATH}") == ACTIVITY, label + ": exact source construction mismatch") previous_finish = time(build["finish"]) for trial, labels in LABELS.items(): prefix = "native/" + trial + "/" expected |= {prefix + n for n in ["started.json", "result.json", "process.json", "stdout.log", "stderr.log"]} result, started, process = (obj(prefix + n + ".json") for n in ["result", "started", "process"]) require(all(result.get(k) == v for k, v in started.items()), trial + ": start/result mismatch") require(result["exitCode"] == 0 and result["binary"] == result["binaryAfter"] == GUI, trial + ": process/binary closure mismatch") require(result["buildReceipt"] == BUILD and result["buildHead"] == HEAD and result["buildInputs"] == INPUTS, trial + ": build provenance mismatch") require(result["command"] == [binaries["arcadia-studio"]["cargo"]["executable"]], trial + ": launch command mismatch") require(previous_finish <= time(result["start"]) <= time(process["observed"]) <= time(result["finish"]), trial + ": chronology mismatch") require(isinstance(process["pid"], int) and process["pid"] > 0, trial + ": PID mismatch") for stream in ["stdout", "stderr"]: require(result[stream] == digest(read(prefix + stream + ".log")) == digest(b""), trial + ": unexpected process output") previous_capture = time(result["start"]) for label in labels: expected.add(prefix + label + ".json") frame = obj(prefix + label + ".json") require(previous_capture <= time(frame["time"]) <= time(result["finish"]), trial + ": capture chronology mismatch") previous_capture = time(frame["time"]) require(frame["window"]["id"] and (isinstance(frame["accessibility"], dict) or (trial, label, frame["accessibility"]) == ("trial-1", "08-project-opened", None)), trial + ": capture metadata mismatch") require(len(frame["images"]) in [1, 2], trial + ": image inventory mismatch") for i, image in enumerate(frame["images"]): name = f"{label}-{i}.jpg" require(image["file"] == name and image["width"] > 0 and image["height"] > 0, trial + ": image metadata mismatch") require(read(prefix + name).startswith(b"\xff\xd8"), trial + ": JPEG bytes mismatch") expected.add(prefix + name) previous_finish = time(result["finish"]) if trial == "trial-2": expected.add(prefix + "baseline.zip") require(result["helper"] == digest(read("native/run-native-followup.py")), "Trial 2 producer pin mismatch") require(result["baselineUnchanged"] is True and result["baselineArchive"] == digest(read(prefix + "baseline.zip")), "Baseline receipt mismatch") require(result["baseline"] == {"project.arcadia": digest(before), ACTIVITY_PATH: digest(ACTIVITY)}, "Baseline source pins mismatch") with zipfile.ZipFile(io.BytesIO(read(prefix + "baseline.zip"))) as baseline: membership(baseline, result["baseline"], "Baseline") require(baseline.read("project.arcadia") == before and baseline.read(ACTIVITY_PATH) == ACTIVITY, "Launch baseline bytes mismatch") fixture = obj("native/fixture-check.result.json") require(fixture["exitCode"] == 0 and fixture["binary"] == CLI, "Fixture CLI receipt mismatch") require(fixture["fixtureBefore"] == fixture["fixtureAfter"] == digest(FIXTURE), "Fixture CLI source mismatch") for key, suffix in [("stdout", "stdout.json"), ("stderr", "stderr.log")]: require(fixture[key] == digest(read("native/fixture-check." + suffix)), "Fixture CLI stream mismatch") require(read("native/fixture-check.stderr.log") == b"", "Fixture CLI stderr was not empty") expected.add("native/check-saved-bundles.py") expected.add("native/bundle-checks/summary.json") producer = digest(read("native/check-saved-bundles.py")) require(producer == {"bytes": 4238, "sha256": "b1116c3c5227fad2d99d0d4ab421e0840a09120b1aedfa1fd4364b25787450cc"}, "Saved-bundle producer pin mismatch") summary = obj("native/bundle-checks/summary.json") require(summary["status"] == "PASS" and summary["runs"] == ["saved-before", "saved-after"] and summary["producer"] == producer, "Bundle summary mismatch") diagnostics = [{"severity": "warning", "code": code, "object_id": identity} for code in ["unallocated_leaf", "work_without_behavior_context"] for identity in ["00000000-0000-4000-8000-000000000002", "1e1da408-da79-42ab-a990-9d00b7dc2631"]] for label, source in [("saved-before", before), ("saved-after", after)]: prefix = "native/bundle-checks/" + label expected |= {prefix + suffix for suffix in [".result.json", ".stdout.json", ".stderr.log"]} result, report = obj(prefix + ".result.json"), obj(prefix + ".stdout.json") entry = "C:\\ar-default-9e8r6t\\.local\\default-omission-native\\" + label + "\\project.arcadia" require(result["command"] == [binaries["arcadia"]["cargo"]["executable"], "check", entry, "--json"], label + ": CLI command mismatch") require(result["exitCode"] == 0 and result["binary"] == CLI and result["buildReceipt"] == BUILD and result["producer"] == producer, label + ": CLI provenance mismatch") require(result["filesUnchanged"] is True and result["files"] == {"project.arcadia": digest(source), ACTIVITY_PATH: digest(ACTIVITY)}, label + ": CLI input mismatch") require(previous_finish <= time(result["start"]) <= time(result["finish"]), label + ": CLI chronology mismatch") previous_finish = time(result["finish"]) require(result["stdout"] == digest(read(prefix + ".stdout.json")) and result["stderr"] == digest(read(prefix + ".stderr.log")) == digest(b""), label + ": CLI streams mismatch") require(report["entry"] == entry and report["operation"] == "check" and report["status"] == "checked" and report["exit_code"] == 0, label + ": CLI status mismatch") require(report["written"] is False and report["changes"] == [] and report["identities_to_stabilize"] == 0, label + ": CLI changed source or identities") require(result["diagnostics"] == [{k: d[k] for k in ["severity", "code", "object_id"]} for d in report["diagnostics"]] == diagnostics, label + ": expected draft diagnostics mismatch") require(set(pins) == expected, "Exact payload inventory mismatch") print("Verified closed native trials, unchanged verified GUI, original captures, 613 build inputs, and exact saved-bundle bytes.") print("Intermediate GUI behavior requires screenshot review; no Linux, performance, packaging, or full-release acceptance claim.")