"""Prepare/launch the identified Windows GUI and preserve native trial checkpoints. All actual GUI interaction is performed separately with Computer Use. """ import argparse import datetime import hashlib import json import os from pathlib import Path import shutil import subprocess root = Path(__file__).resolve().parents[2] evidence = Path(__file__).resolve().parent trial = root / ".local/text-navigation-native-20260911" fixtures = root / ".local/text-navigation-native-20260911-preparation" runtime = root / ".local/toolchain/llvm-mingw-20260826-ucrt-x86_64/bin/libunwind.dll" oracle = root / ".local/staged-source-oracle-20260911/staged-source-authoring-contract.exe" runtime_sha = "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4" oracle_sha = "967d9ba3c6fb3a7efb410833903ec94556ca2d48a67d5072c8bb160f40a00f9c" fixture_manifest_sha = "edd4157fc31823f4494dee91862728b87f12ef51c49b8d1fd86a954bc9ecc1ed" def sha(path): return hashlib.sha256(path.read_bytes()).hexdigest() def now(): return datetime.datetime.now(datetime.timezone.utc).isoformat() def record(path, value): with path.open("x", encoding="utf-8", newline="\n") as out: json.dump(value, out, indent=2, ensure_ascii=False) out.write("\n") def inventory(folder): result = {} for path in folder.rglob("*"): assert not path.is_symlink() and not (getattr(path.lstat(), "st_file_attributes", 0) & 0x400), path if path.is_file(): result[path.relative_to(folder).as_posix()] = sha(path) return result def environment(): parent = {key.upper(): value for key, value in os.environ.items()} names = ("SystemRoot", "SystemDrive", "ProgramData", "ALLUSERSPROFILE", "PUBLIC") standard = {name: parent[name.upper()] for name in names} assert all("%" not in value for value in standard.values()) system = standard["SystemRoot"] return {**standard, "WINDIR": system, "PATH": system + "\\System32;" + system, "USERPROFILE": str(trial / "profile"), "LOCALAPPDATA": str(trial / "profile/local"), "APPDATA": str(trial / "profile/roaming"), "TEMP": str(trial / "tmp"), "TMP": str(trial / "tmp")} def verify_fixtures(): manifest = fixtures / "fixture-manifest.json" assert sha(manifest) == fixture_manifest_sha for entry in json.loads(manifest.read_text(encoding="utf-8")): path = (fixtures / entry["path"]).resolve() assert path.is_relative_to(fixtures) and path.stat().st_size == entry["bytes"] assert sha(path) == entry["sha256"], entry["path"] parser = argparse.ArgumentParser() parser.add_argument("action", choices=("launch", "check", "closed")) parser.add_argument("--label") parser.add_argument("--model", choices=("valid", "release1"), default="valid") args = parser.parse_args() if args.action == "launch": verify_fixtures() receipt_path = evidence / "gui-build-v2.json" receipt = json.loads(receipt_path.read_text(encoding="utf-8")) preserved = json.loads((evidence / "gui-preserved.json").read_text(encoding="utf-8")) assert preserved["buildReceiptSha256"] == sha(receipt_path) binary = Path(preserved["binary"]).resolve() assert binary == evidence / "gui-v2.exe" assert preserved["sha256"] == receipt["sha256"] assert sha(binary) == receipt["sha256"] assert sha(runtime) == runtime_sha and sha(oracle) == oracle_sha trial.mkdir(exist_ok=False) for folder in ("bin", "profile/local", "profile/roaming", "profile/Desktop", "tmp", "screenshots"): (trial / folder).mkdir(parents=True) shutil.copy2(binary, trial / "bin/arcadia-studio.exe") shutil.copy2(runtime, trial / "bin/libunwind.dll") for source, destination in (("valid-baseline", "valid"), ("release1-baseline", "release1"), ("ambiguous-open", "ambiguous"), ("missing-include-open", "missing-include")): shutil.copytree(fixtures / source, trial / destination) before = inventory(trial / "bin") record(trial / "binary-before.json", before) record(trial / "source-before.json", {name: inventory(trial / name) for name in ("valid", "release1", "ambiguous", "missing-include")}) env = environment() startup = subprocess.STARTUPINFO() startup.dwFlags |= subprocess.STARTF_USESHOWWINDOW startup.wShowWindow = 0 with (trial / "stdout.log").open("xb") as out, (trial / "stderr.log").open("xb") as err: process = subprocess.Popen([str(trial / "bin/arcadia-studio.exe")], cwd=trial / "bin", env=env, stdout=out, stderr=err, startupinfo=startup) launch = {"atUtc": now(), "pid": process.pid, "binarySha256": receipt["sha256"], "buildReceiptSha256": sha(receipt_path), "source": str(trial / "valid/project.arcadia"), "environment": env, "scope": "Identified local Windows GUI; native verification pending"} record(trial / "launch.json", launch) print(json.dumps(launch, ensure_ascii=False)) elif args.action == "check": verify_fixtures() assert args.label and args.label.replace("-", "").isalnum() assert inventory(trial / "bin") == json.loads((trial / "binary-before.json").read_text(encoding="utf-8")) assert sha(oracle) == oracle_sha checkpoint = trial / (args.label + "-sources") shutil.copytree(trial / args.model, checkpoint) env = environment() env["PATH"] = str(trial / "bin") + ";" + env["PATH"] command = [str(oracle), "same", str(fixtures / (args.model + "-baseline") / "project.arcadia"), str(checkpoint / "project.arcadia")] result = subprocess.run(command, capture_output=True, env=env) (trial / (args.label + ".stdout.log")).write_bytes(result.stdout) (trial / (args.label + ".stderr.log")).write_bytes(result.stderr) receipt = {"atUtc": now(), "command": command, "exitCode": result.returncode, "oracleSha256": oracle_sha, "files": inventory(checkpoint), "binaryFilesUnchanged": True, "scope": "Complete saved Project/identity, reachable sources and physical Arcadia equality"} record(trial / (args.label + ".json"), receipt) print(result.stdout.decode("utf-8", errors="replace")) print(json.dumps({"label": args.label, "exitCode": result.returncode})) if result.returncode: print(result.stderr.decode("utf-8", errors="replace")) raise SystemExit(result.returncode) else: # The caller must observe process closure independently before this readback. before = json.loads((trial / "binary-before.json").read_text(encoding="utf-8")) after = inventory(trial / "bin") record(trial / "binary-after-close.json", {"atUtc": now(), "files": after, "unchanged": before == after}) assert before == after print(json.dumps({"binaryFilesUnchanged": True, "files": len(after)}))