Merge commit '954528a7c5a0e27e2e50b642373168fa0a550aba' into HEAD

This commit is contained in:
Agent Control Runner
2026-10-21 04:23:01 +09:00
4 changed files with 2536 additions and 0 deletions
@@ -0,0 +1,735 @@
#!/usr/bin/env python3
"""RESTART evidence validation; typed state comparisons execute in Godot."""
import ast
import copy
import hashlib
import importlib.util
import json
import math
from pathlib import Path
import re
import sys
import sysconfig
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[6]
BASE = "docs/plans/original-completion-2026-10-02/execution/p28-01/"
DEPENDENCIES = {
"tools/run_all_tests.py": "320ca668732b4ff72fc4449998af2327d4e5c527b06896740806aaf0487282b4",
"tools/regression/owned_outer.py": "c2e3483b76db1a3ff940f23f88ea0083fc78736e874ebcdb385d766dde8866e7",
"tools/regression/owned_diagnostic_process.py": "e31e93c6e2c5ea46a7d954ef8bc0b4caec1c08b86b8aef19e93b52ef24993087",
"tools/regression/p09_owned_engine_process.py": "c007e712c281573254faa1233c2ac92e100ab87393256a6dc096b35283e43037",
BASE + "collector/collect_p28_01.py": "a43e1f963ef8505ddd5acf8bf747d9bfac22a028cbb805c0b964ee11b9b40a14",
BASE + "collector/check_p28_01_report.py": "6c0851d498ca80bdc120fad047b072255f48713f63114521f3d4dfc902b2512b",
}
LOCAL = {BASE + "restart/probe/" + n for n in
("restart_pair.py", "check_restart.py", "test_restart.py", "restart_probe.gd")}
SIDECAR = "p28_restart/evidence/report_full.json"
TIMINGS = ("duration_us", "runtime_duration_us")
SAVE_EVENTS = {
"SAVE_CHECKPOINT_SUCCEEDED", "SAVE_CHECKPOINT_FAILED", "SAVE_LOADED", "SAVE_LOAD_FAILED",
"SAVE_MIGRATION_SUCCEEDED", "SAVE_MIGRATION_FAILED", "SAVE_RECOVERY_LOADED",
"SAVE_RECOVERY_CANDIDATE_LOADED", "SAVE_RECOVERY_FAILED",
}
PHASES = ["import", "parse-base", "parse-wrapper", "R-writer", "R-reader", "O-writer", "O-reader"]
CROSS = [
{"condition": "原本条件とUI操作が一致", "applicable": False, "reference": "collector C1/C2",
"reason": "既存collectorのUI経路受入を参照。このtaskは再開の比較を担当する。"},
{"condition": "Runtimeの実利用・会計・行動へ接続", "applicable": False, "reference": "collector C2/C3",
"reason": "既存collectorの実Runtime観測を参照。製品の接続は変更しない。"},
{"condition": "途中保存・再起動で再現", "applicable": True, "reference": "RS1/RS2/RS3/RS4/RS5",
"reason": "別PIDのR/O writerとreaderで適用する。"},
{"condition": "異常/境界/中断を検証", "applicable": False, "reference": "collector C5/C6/C7",
"reason": "横断受入は既存collectorを参照。再開固有の異常と境界はRS5で検証する。"},
{"condition": "関連回帰PASS", "applicable": False, "reference": "collector C8",
"reason": "既存collectorの正式回帰証拠を参照。workerは全回帰を実行しない。"},
{"condition": "要件別ログとソースハッシュを保存", "applicable": False, "reference": "collector C6/C7/C9",
"reason": "既存collectorの証拠契約を参照。再開のraw結合はRS7で保存する。"},
]
def require(condition, message):
if not condition:
raise ValueError(message)
def sha(path):
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def pin(path):
path = Path(path)
require(path.is_file() and not path.is_symlink(), "missing/symlink evidence")
return {"sha256": sha(path), "bytes": path.stat().st_size}
def check_dependencies(root=ROOT):
for name, expected in DEPENDENCIES.items():
require(sha(root / name) == expected, "dependency SHA: " + name)
def check_imports(text, external=None):
tree = ast.parse(text)
if external is not None:
require(external in DEPENDENCIES, "external AST closure")
# The explicitly forbidden run_all_tests.main imports are not executed.
tree.body = [node for node in tree.body if not (
isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == "main")]
allowed = {Path(p).stem for p in set(DEPENDENCIES) | LOCAL}
for node in ast.walk(tree):
if isinstance(node, (ast.Import, ast.ImportFrom)):
names = [node.module] if isinstance(node, ast.ImportFrom) else [a.name for a in node.names]
for name in names:
require(name and (standard_library(name.split(".")[0]) or name in allowed),
"import outside closure")
if isinstance(node, ast.Call):
name = node.func.id if isinstance(node.func, ast.Name) else getattr(node.func, "attr", "")
require(name not in ("__import__", "eval", "import_module"), "dynamic code forbidden")
require(name != "exec" or external == "tools/regression/owned_diagnostic_process.py",
"unapproved exec")
if name == "spec_from_file_location":
for sub in ast.walk(node):
if isinstance(sub, ast.Constant) and isinstance(sub.value, str):
for path in re.findall(r"[\w./-]+\.py", sub.value):
require(path in DEPENDENCIES or path in LOCAL or
path in {Path(p).name for p in DEPENDENCIES}, "loader outside closure")
if external and isinstance(node, ast.BinOp):
for sub in ast.walk(node):
if isinstance(sub, ast.Constant) and isinstance(sub.value, str) and sub.value.endswith(".py"):
require(sub.value in DEPENDENCIES or sub.value in {Path(p).name for p in DEPENDENCIES},
"external loader path outside closure")
def standard_library(name):
# Python 3.9 on the native host has no sys.stdlib_module_names.
spec = importlib.util.find_spec(name)
if spec is None:
return False
if spec.origin in ("built-in", "frozen"):
return True
if not spec.origin:
return False
path = Path(spec.origin).resolve()
return path.is_relative_to(Path(sysconfig.get_path("stdlib")).resolve()) and not any(
part in ("site-packages", "dist-packages") for part in path.parts)
def check_modules(modules=None, root=ROOT):
for module in (sys.modules if modules is None else modules).values():
name = getattr(module, "__file__", None)
if name:
path = Path(name).resolve()
if path.is_relative_to(root):
require(path.relative_to(root).as_posix() in set(DEPENDENCIES) | LOCAL,
"loaded project module outside closure")
def check_probe(text):
# Focused guard for direct Variant inference only, not GDScript compilation.
# Root's actual Godot parse remains required.
lines = [raw.split("#", 1)[0] for raw in text.splitlines()]
variant_names = set()
variant_functions = {"field"}
for line in lines:
declaration = re.match(r"^var\s+(\w+)\s*:\s*Variant\b", line)
if declaration:
variant_names.add(declaration[1])
declaration = re.match(r"^func\s+(\w+)\s*\(.*\)\s*->\s*Variant\b", line)
if declaration:
variant_functions.add(declaration[1])
function = None
blocks = []
pauses = 0
watchdog_calls = 0
for raw in text.splitlines():
line = raw.split("#", 1)[0]
inferred = re.match(r"^\s*var\s+\w+\s*:=\s*(\w+)\b(.*)", line)
if inferred:
require(not (inferred[1] in variant_names or
(inferred[1] in variant_functions and inferred[2].lstrip().startswith("("))),
"direct Variant inference requires an explicit type")
match = re.match(r"^func (\w+)\(", line)
if match:
function = match[1]
if function == "deterministic_step":
blocks.append([])
if function == "deterministic_step":
blocks[-1].append(line)
require(not re.search(r"set_paused\s*\(\s*false|\bclear\s*\(|spawn_guest|SimulationRuntime\.new|\binitialize\s*\(|enable_production_|_toggle_pause", line),
"forbidden probe API")
if re.search(r"\badvance_", line):
require(function == "deterministic_step" and line.strip() == "GameClock.advance_minutes(1)",
"advance outside deterministic_step")
if "set_paused(" in line:
require(function == "on_tick" and line.strip() == "GameClock.set_paused(true)", "pause outside tick")
pauses += 1
if "Time." in line:
require(function == "deadline_timer_seconds" and
line.strip() == "return Time.get_ticks_msec() / 1000.0", "timing API outside watchdog")
watchdog_calls += 1
# Literal names are used only by the finite evidence redaction routine.
timing_line = line.strip() == 'for key: String in ["duration_us", "runtime_duration_us"]:'
require(not re.search(r"\b\w+_(?:us|ms)\b|Performance\.|get_performance_report", line)
or (function == "redact_payload" and timing_line),
"performance instrumentation")
require(len(blocks) == 1 and pauses == 1 and watchdog_calls == 1, "deterministic/tick/watchdog functions required")
block = "\n".join(blocks[0])
require(block.count("GameClock.advance_minutes(1)") == 1 and
"io_ready" in block and "GameClock.paused" in block, "step admission")
def event_id(counter):
require(type(counter) is int and counter >= 0, "counter type")
return "domain_event.%012d" % (counter + 1)
def transform(witness, event):
"""Consistency oracle for recorded IO paths, not a Godot state decoder."""
result = copy.deepcopy(witness)
eid = event_id(witness["counter"])
ids, recent = witness["published_ids"], witness["recent_events"]
require(event["event_id"] == eid, "IO event ID")
require(ids == sorted(set(ids)) and eid not in ids and len(recent) <= 256, "event history")
require(len({x["event_id"] for x in recent}) == len(recent) and
all(x["event_id"] in ids for x in recent), "recent IDs")
result["counter"] += 1
result["published_ids"] = sorted(ids + [eid])
result["recent_events"] = (recent[1:] if len(recent) == 256 else recent) + [event]
return result
def exact(row):
require(row["method"] == "var_to_bytes" and row["equal"] is True and row["diff_paths"] == [],
"typed bytes differ")
require(row["excluded_paths"] == [], "state path exclusion")
require(re.fullmatch("[0-9a-f]{64}", row["expected_sha256"]) and
row["actual_sha256"] == row["expected_sha256"], "typed comparison contradiction")
def check_io(row, kind):
require(row["kind"] == kind and row["signal_count"] == 1, "one IO signal required")
signal, latest, ev = row["signal_payload"], row["latest"], row["event"]
require(signal == latest == ev["payload"], "signal/latest/event mismatch")
require(row["signal_projection"] == "_save_event_payload" and row["payload_bytes_equal"] is True,
"typed payload comparison")
success = kind != "tamper"
require(type(signal["ok"]) is bool and signal["ok"] is success and
((signal["code"] == "OK") is success), "IO result")
require(signal["operation"] == ("save" if kind == "save" else "load"), "operation")
require(signal["save_path"].startswith("user://p28_restart/") and ".." not in signal["save_path"],
"private IO path")
require(row["return_kind"] == ("bool" if kind == "save" else "void"), "return kind")
require(row["return_value"] is signal["ok"] if kind == "save" else row["return_value"] is None,
"return/signal mismatch")
expected_type = {"save": "SAVE_CHECKPOINT_SUCCEEDED", "load": "SAVE_LOADED",
"tamper": "SAVE_LOAD_FAILED"}[kind]
require(ev["event_type"] == expected_type and ev["source_service"] == "save_service" and
ev["entity_ids"] == [] and ev["causation_command_id"] == 0, "event shape")
require(ev["absolute_minute"] == row["minute_after"] == row["minute_before"], "IO minute")
require(row["after"] == transform(row["before"], ev), "not X(P,event)")
require(row["dropped"] == (row["before"]["recent_events"][0]
if len(row["before"]["recent_events"]) == 256 else None), "wrong dropped head")
exact(row["comparison"])
if success:
require(signal["saved_absolute_minute"] == row["minute_after"] and bool(signal["save_id"]),
"save identity")
require(row["paused_after"] is True, "IO clock not paused")
else:
failure = row["failure"]
require(failure["preload_pause_restored"] is True and
failure["loaded_clock_paused"] is row["paused_before"] and
row["paused_after"] is row["paused_before"], "tamper pause")
if failure["recovery_report"] is not None:
require(failure["recovery_report"]["restore_committed"] is False, "tamper restore")
require(type(failure["migration_attempted"]) is bool, "migration observation")
def save_event(event):
return isinstance(event, dict) and event.get("source_service") == "save_service" and \
event.get("event_type") in SAVE_EVENTS
def payload_paths(report):
"""The complete W2 closure; no recursive payload-name exemption."""
result = {}
for i, row in enumerate(report["io"]):
prefix = "/report/io/%d" % i
for name in ("signal_payload", "latest"):
result[prefix + "/" + name] = row[name]
events = [(prefix + "/event", row["event"]), (prefix + "/dropped", row["dropped"])]
for side in ("before", "after"):
events.extend((prefix + "/" + side + "/recent_events/%d" % j, event)
for j, event in enumerate(row[side]["recent_events"]))
for path, event in events:
if save_event(event):
result[path + "/payload"] = event["payload"]
for k, row in enumerate(report["minutes"]):
if save_event(row["replacement"]):
result["/report/minutes/%d/replacement/payload" % k] = row["replacement"]["payload"]
return result
def walk(value, path=""):
if isinstance(value, dict):
for key, child in value.items():
pointer = path + "/" + key.replace("~", "~0").replace("/", "~1")
yield pointer, key, child
yield from walk(child, pointer)
elif isinstance(value, list):
for i, child in enumerate(value):
yield from walk(child, path + "/" + str(i))
def redact_report(verbatim):
"""Also validates the full sidecar report before producing its unique public form."""
full = json.loads(json.dumps(verbatim))
allowed = payload_paths(full)
for path, key, _ in walk(full, "/report"):
require(key != "timing_redactions", "reserved marker in verbatim evidence")
require(not key.endswith(("_us", "_ms")) or
(path.rsplit("/", 1)[0] in allowed and key in TIMINGS), "timing outside W2 closure")
require(key not in ("performance", "statistics", "fps", "budget_verdict"),
"sidecar performance use")
for path, payload in allowed.items():
require(isinstance(payload, dict) and all(k in payload for k in TIMINGS), "both timing keys required")
payload["timing_redactions"] = [
{"original_key": key, "sidecar_ref": path + "/" + key} for key in TIMINGS]
for key in TIMINGS:
del payload[key]
check_no_metrics(full)
return full
def resolve_pointer(sidecar, pointer):
require(pointer.startswith("/report/"), "pointer outside report")
value = sidecar
for part in pointer[1:].split("/"):
part = part.replace("~1", "/").replace("~0", "~")
value = value[int(part)] if isinstance(value, list) else value[part]
return value
def json_sha(value):
# JSON numbers are represented uniformly across Godot's JSON float parser
# and Python. Fixed decimal form is valid JSON; keys and strings remain verbatim.
def encode(v):
if isinstance(v, dict):
require(len({str(k) for k in v}) == len(v), "canonical_key_collision")
require(all(type(k) is str for k in v), "canonical JSON requires text keys")
return "{" + ",".join(json.dumps(k, ensure_ascii=False) + ":" + encode(v[k])
for k in sorted(v)) + "}"
if isinstance(v, list):
return "[" + ",".join(encode(x) for x in v) + "]"
if type(v) in (int, float):
require(math.isfinite(v), "nonfinite JSON")
return format(v, ".17f")
return json.dumps(v, ensure_ascii=False, separators=(",", ":"), allow_nan=False)
return hashlib.sha256(encode(value).encode()).hexdigest()
def canonical_event(event, eid):
return {"event_id": eid, "replaced_for_cross_pid_compare": True} \
if event["event_id"] == eid else event
def check_sidecar(public, sidecar):
require(isinstance(sidecar, dict) and set(sidecar) == {"report", "at_390_event_verbatim"},
"sidecar root/missing")
check_no_metrics(public)
full = sidecar["report"]
require(full.get("stop_reason") != "canonical_key_collision", "canonical_key_collision")
require(public == redact_report(full), "public redaction differs from W2")
restored = copy.deepcopy(public)
for path, payload in payload_paths(restored).items():
expected = [{"original_key": k, "sidecar_ref": path + "/" + k} for k in TIMINGS]
require(payload.pop("timing_redactions") == expected, "redaction marker/pointer mismatch")
for marker in expected:
payload[marker["original_key"]] = resolve_pointer(sidecar, marker["sidecar_ref"])
require(restored == full, "entire restored report differs")
events = sidecar["at_390_event_verbatim"]
require(isinstance(events, list), "at390 verbatim array")
observation = full.get("at_390")
summaries = observation["events"] if observation is not None else []
require(len(events) == len(summaries), "at390 verbatim count")
for event, summary in zip(events, summaries):
for path, key, _ in walk(event):
require(key != "timing_redactions" and key not in
("performance", "statistics", "fps", "budget_verdict"), "at390 forbidden field")
require(not key.endswith(("_us", "_ms")) or
(save_event(event) and path == "/payload/" + key and key in TIMINGS),
"at390 timing outside SAVE payload")
if save_event(event):
require(all(k in event["payload"] for k in TIMINGS), "at390 both timing keys")
require(set(summary) == {"event_id", "event_type", "absolute_minute",
"raw_event_sha256", "canonical_sha256"}, "at390 summary shape")
require(all(event[k] == summary[k] for k in ("event_id", "event_type", "absolute_minute")),
"at390 verbatim order/metadata")
require(json_sha(event) == summary["raw_event_sha256"] and
json_sha(canonical_event(event, full["event_id"])) == summary["canonical_sha256"],
"at390 raw/canonical SHA")
return full
def check_deadline(value, complete=True):
require(set(value) == {"limit_seconds_from_engine_start", "engine_elapsed_at_begin_seconds",
"timer_seconds"}, "deadline shape")
elapsed, timer = value["engine_elapsed_at_begin_seconds"], value["timer_seconds"]
require(type(elapsed) in (int, float) and type(timer) in (int, float) and
math.isfinite(elapsed) and math.isfinite(timer) and elapsed >= 0 and
value["limit_seconds_from_engine_start"] == 1740 and timer == 1740 - elapsed,
"engine elapsed deadline formula")
require(not complete or timer > 0, "expired deadline")
def overload_case(report):
backlog = report["paused_idle"]["before"]["backlog"]
overloads = report["overloads"]
require(isinstance(overloads, list) and type(backlog) is int and backlog >= 0, "overload facts")
expected = {"exercised": bool(overloads and backlog > 0),
"overloads": len(overloads), "backlog_at_save": backlog}
require(report["overload_case"] == expected and
type(report["overload_case"]["exercised"]) is bool and
set(report["overload_case"]) == set(expected), "overload disclosure")
for _, key, value in walk(report):
if key in ("nonzero_backlog_preserved", "overload_persistence",
"across_restart_backlog_persistence_claimed"):
require(value is False, "unsupported overload/persistence claim")
return expected
def coverage(reports):
detail = {r["role"]: overload_case(r) for r in reports if r["role"].endswith("writer")}
return {"overload_nonzero_backlog":
"exercised_recorded" if detail and all(x["exercised"] for x in detail.values()) else "not_exercised",
"per_role": detail, "across_restart_backlog_persistence_claimed": False}
def check_no_arrival_diagnostic(report):
require(report["role"] == "O-writer" and report["boundary"] is None and
report["boundary_reason"] == report["stop_reason"] == "no_arrival_within_cap",
"no-arrival reason/null")
require(report["ui_ticks"] and
report["ui_ticks"][-1]["clock"] - report["start_minute"] == 120 and
all(t["guest_auto_count"] == 0 and t["guest_auto_ids"] == [] for t in report["ui_ticks"]),
"no-arrival cap/facts")
return True
def check_report(report, sidecar=None):
check_no_metrics(report)
require(sidecar is not None, "sidecar required")
report = check_sidecar(report, sidecar)
if report["stop_reason"] == "no_arrival_within_cap":
check_no_arrival_diagnostic(report)
require(report["schema"] == "p28-restart-v1" and report["stop_reason"] == "complete", "incomplete probe")
require(report["role"] in PHASES[3:] and type(report["pid"]) is int and report["pid"] > 0, "role/PID")
require(report["main_added"] is True and report["k_target"] == 30 and report["actual_k"] == 30, "main/K")
require(report["comparison_scope"] == "complete_typed_var_to_bytes" and report["excluded_paths"] == [],
"partial digest/path exclusion")
require(report["transfer_before_guard_writes"] == 0 and report["probe_deadline_seconds"] == 1740,
"profile/deadline")
check_deadline(report["probe_deadline"])
writer = report["role"].endswith("writer")
kinds = ["save"] if writer else ["tamper", "load"]
require(len(report["io"]) == len(kinds), "IO sequence")
for row, kind in zip(report["io"], kinds):
check_io(row, kind)
if writer:
overload_case(report)
exact(report["package_matches_before"])
require(report["package_matches_before"]["actual_sha256"] == report["states"]["P"]["sha256"],
"P not package snapshot")
else:
require(report["failure_event_absent"] is True and report["transfer_verified"] is True,
"failed event survived/transfer not verified")
io = report["io"][-1]
require(report["event_id"] == io["event"]["event_id"] and report["saved_minute"] == io["minute_after"],
"continuation IO identity")
require(report["paused_idle"]["before"] == report["paused_idle"]["after"], "paused clock consumed backlog")
require(report["paused_idle"]["before"]["paused"] is True, "paused observation")
exact(report["paused_idle"]["comparison"])
rows = report["minutes"]
require(len(rows) == 30, "actual K not 30")
previous, lost = report["saved_minute"], False
for row in rows:
require(row["before"] == previous and row["after"] == previous + 1, "K counts actual minute advances")
require(row["paused"] is True and row["backlog_before"] == row["backlog_after"], "step consumed backlog")
require(row["scope"] == "complete_typed_var_to_bytes" and row["excluded_paths"] == [], "partial state")
require(re.fullmatch("[0-9a-f]{64}", row["sha256"]), "minute SHA")
if row["replacement"] is not None:
require(not lost and row["replacement"] == io["event"] and row["replacement_count"] == 1,
"replacement must be unchanged in-window E")
else:
lost = True
require(row["replacement_count"] == 0, "replacement after E left window")
require(0 <= row["recent_count"] <= 256, "recent limit")
require(len(row["recent_ids"]) == len(set(row["recent_ids"])) == row["recent_count"] and
row["recent_ids"].count(report["event_id"]) == row["replacement_count"],
"replacement does not match actual window")
previous = row["after"]
require(report["final_minute"] == previous, "final minute")
for name, entry in report["states"].items():
require(re.fullmatch("[0-9a-f]{64}", entry["sha256"]) and entry["bytes"] > 0 and
entry["path"] == "p28_restart/evidence/" + name + ".bin", "state binding")
required = {"P", "after_save", "final"} if writer else {"P", "B", "after_tamper", "after_load", "final"}
require(set(report["states"]) == required, "missing complete state files")
require(report["states"]["after_save" if writer else "after_load"]["sha256"] ==
io["comparison"]["actual_sha256"], "IO state file differs")
if not writer:
require(report["states"]["after_tamper"]["sha256"] == report["io"][0]["comparison"]["actual_sha256"],
"tamper state file differs")
if report["role"].startswith("O-"):
observation = report["at_390"]
require(isinstance(observation, dict) and observation["clock"] == {"absolute_minute": 390},
"at390 missing/clock")
require(isinstance(observation["operations"], dict) and
type(observation["domain_event_counter"]) is int and
type(observation["published_ids_count"]) is int and
observation["domain_event_counter"] >= observation["published_ids_count"] >= 0,
"at390 report/counter")
require(isinstance(observation["processed_arrival_minutes"], list) and
observation["processed_arrival_minutes"] == sorted(set(observation["processed_arrival_minutes"])) and
all(type(m) is int and m <= 390 for m in observation["processed_arrival_minutes"]),
"at390 processed minutes")
ids = observation["guest_auto_ids"]
require(isinstance(ids, list) and ids == sorted(set(ids)) and
type(observation["guest_auto_count"]) is int and
len(ids) == observation["guest_auto_count"] and
all(x.startswith("guest-auto-") for x in ids), "at390 guests")
require(all(type(e["absolute_minute"]) is int and
report["saved_minute"] < e["absolute_minute"] <= 390
for e in observation["events"]), "at390 event window")
event_ids = [e["event_id"] for e in observation["events"]]
require(len(event_ids) == len(set(event_ids)), "at390 duplicate event")
at_rows = [r for r in rows if r["after"] == 390]
require(len(at_rows) == 1 and at_rows[0]["operations_observation"] ==
{k: v for k, v in observation.items() if k != "events"}, "at390 minute consistency")
require(all(e in at_rows[0]["recent_ids"] for e in event_ids), "at390 event window IDs")
boundary = report["boundary"]
require(boundary is not None and boundary["guest_auto_count"] > 0, "arrival not processed")
require(len(boundary["guest_auto_ids"]) == len(set(boundary["guest_auto_ids"])) ==
boundary["guest_auto_count"], "arrival IDs")
require(all(x.startswith("guest-auto-") for x in boundary["guest_auto_ids"]), "arrival identity")
require(boundary["clock"] == report["saved_minute"] and boundary["processed_arrival_minutes"],
"arrival boundary not processed")
if writer:
require(0 < report["saved_minute"] - report["start_minute"] <= 120, "arrival cap")
ticks = report["ui_ticks"]
require(ticks and ticks[-1] == boundary and all(t["guest_auto_count"] == 0 for t in ticks[:-1]),
"not first arrival tick")
next_boundary = report["next_boundary"]
added = [m for m in next_boundary["after"] if m not in next_boundary["before"]]
require(next_boundary["before"] == boundary["processed_arrival_minutes"] and
added == [next_boundary["minute"]] and next_boundary["processed_once"] is True and
next_boundary["minute"] > boundary["clock"] and
next_boundary["minute"] <= report["final_minute"], "next arrival missing/duplicate")
minutes = next_boundary["after"]
require(minutes == sorted(set(minutes)), "duplicate processed arrivals")
require([r["minute"] for r in next_boundary["arrival_reports"]] == minutes,
"arrival report duplicates/omissions")
else:
require(report["boundary"] is None and report["next_boundary"] is None and
report["at_390"] is None, "R Operations boundary")
return True
def check_no_metrics(value):
if isinstance(value, dict):
for key, child in value.items():
require(not key.endswith(("_us", "_ms")) and key not in
("performance", "statistics", "fps", "budget_verdict"), "performance field forbidden")
check_no_metrics(child)
elif isinstance(value, list):
for child in value:
check_no_metrics(child)
def canonical_observation(observation, eid):
result = copy.deepcopy(observation)
if result is not None:
result["events"] = [
{"event_id": eid, "replaced_for_cross_pid_compare": True,
"canonical_sha256": e["canonical_sha256"]} if e["event_id"] == eid else e
for e in result["events"]]
return result
def check_pair(writer, reader, writer_sidecar=None, reader_sidecar=None):
check_report(writer, writer_sidecar)
check_report(reader, reader_sidecar)
writer, reader = writer_sidecar["report"], reader_sidecar["report"]
require(writer["role"].replace("writer", "reader") == reader["role"] and writer["pid"] != reader["pid"],
"pair roles/PID")
require(writer["event_id"] == reader["event_id"] and writer["saved_minute"] == reader["saved_minute"],
"pair IO identity")
require(writer["states"]["P"] == reader["states"]["P"], "package P differs")
require(writer["io"][0]["before"] == reader["io"][1]["before"], "package history differs")
for left, right in zip(writer["minutes"], reader["minutes"]):
require(all(left[k] == right[k] for k in
("before", "after", "sha256", "scope", "replacement_count", "recent_count")),
"cross-PID complete typed state mismatch")
require(writer["boundary"] == reader["boundary"] and writer["next_boundary"] == reader["next_boundary"],
"Operations boundary differs")
require(canonical_observation(writer["at_390"], writer["event_id"]) ==
canonical_observation(reader["at_390"], reader["event_id"]), "at390 pair differs")
def bound_raw(folder, row):
folder = Path(folder)
require(set(row["raw"]) == {"stdout.log", "stderr.log", "engine-native.log"}, "all raw required")
for name, expected in {**row["raw"], **row["owned_files"]}.items():
require(Path(name).name == name and pin(folder / name) == expected, "raw/owned SHA mismatch")
require(set(row["owned_files"]) == {"process.json", "started.json", "ended.json",
"adapter-owned-cleanup.json", "outer-owned-finally.json"}, "owned receipts missing")
require(json.loads((folder / "process.json").read_text()) == row["process"], "process receipt mismatch")
process, capture = row["process"], row["capture"]
require(row["passed"] is True and process["exit_code"] == 0 and process["helper_exit_code"] == 0 and
process["timed_out"] is False and process["error_lines"] == [] and process["lifecycle_error"] is None and
process["external_process_or_group_signals"] == 0 and process["owned_popen_ended"] is True and
process["old_helper_engine_ended"] is True and process["start_receipt_written"] is True and
process["end_receipt_written"] is True, "owned phase failed")
require(capture["passed"] is True and capture["all_captured_ended"] is True and
capture["outer_cleanup_errors"] == [] and capture["adapter_exception"] is None and
capture["foreign_process_or_group_signals"] == 0 and
capture["all_cleanup_before_outer_receipt"] is True and capture["outer_receipt_written"] is True and
capture["outer_receipt_error"] is None and len(capture["actual_captured_pids"]) == 1, "outer capture")
actual = json.loads((folder / "outer-owned-finally.json").read_text())
require(actual == {k: v for k, v in capture.items() if k not in
("passed", "outer_receipt_written", "outer_receipt_error")}, "outer raw differs")
pid = capture["actual_captured_pids"][0]
require(process["pid"] == pid and process["argv"] == row["argv"], "process PID/argv")
for filename, key in (("started.json", "actual_start_binding"), ("ended.json", "actual_end_binding")):
binding = json.loads((folder / filename).read_text())
require(binding == process[key] and binding["pid"] == binding["actual_pid"] == pid and
binding["argv"] == binding["command"] == row["argv"] and binding["owner_pid"] > 0,
"START/END binding")
require(process["actual_start_binding"]["owner_pid"] == process["actual_end_binding"]["owner_pid"],
"START/END owners differ")
require(json.loads((folder / "adapter-owned-cleanup.json").read_text()) == process["adapter_owned_cleanup"]
and process["adapter_owned_cleanup"]["engine_ended"] is True and
process["adapter_owned_cleanup"]["errors"] == [], "adapter cleanup binding")
require(process["stdout_sha256"] == row["raw"]["stdout.log"]["sha256"] and
process["stderr_sha256"] == row["raw"]["stderr.log"]["sha256"], "process raw binding")
require(row["timeout_seconds"] == 1800 and row["diagnostics"] == [], "phase timeout/diagnostics")
raw = (folder / "stdout.log").read_text()
for name in ("stdout.log", "stderr.log", "engine-native.log"):
require(not re.search(r"SCRIPT ERROR|Parse Error|ERROR:", (folder / name).read_text()),
"raw engine error")
if row["phase"] not in PHASES[3:]:
require("P28_RESTART_REPORT=" not in raw, "parse/import report")
if row["phase"].startswith("parse"):
require("--check-only" in row["argv"], "parse not check-only")
return None
reports = [s.partition("=")[2] for s in raw.splitlines() if s.startswith("P28_RESTART_REPORT=")]
closes = [s.partition("=")[2] for s in raw.splitlines() if s.startswith("P28_RESTART_AUDIO_CLOSE=")]
require(len(reports) == len(closes) == 1, "report/audio close count")
report, close = json.loads(reports[0]), json.loads(closes[0])
require(report == row["report"] and report["role"] == row["phase"] and
capture["actual_captured_pids"] == [report["pid"]], "raw report/PID binding")
require(close.get("coordinator") is True and close.get("passed") is True and
close.get("owned_engine_pid") == report["pid"] and close.get("all_owned_targets_released") is True and
close.get("deadline_reached") is False and close.get("clock_process_held_stopped") is True and
close.get("window_input_held_disabled") is True and close.get("restored_before_quit") is False and
close.get("shared_bus_deleted") is False and close.get("settings_mutated") is False, "audio close")
check_report(report, bound_sidecar(folder.parent, row))
return report
def bound_sidecar(out, row):
binding = row["sidecar"]
require(set(binding) == {"path", "sha256", "bytes"} and binding["path"] == SIDECAR,
"sidecar binding/path")
expected = {k: binding[k] for k in ("sha256", "bytes")}
path = Path(out) / (row["phase"] + "-states") / "report_full.json"
require(pin(path) == expected and pin(Path(row["runtime_profile"]) / SIDECAR) == expected,
"sidecar SHA/private profile binding")
return json.loads(path.read_text())
def check_receipt(receipt, out):
from restart_pair import COLLECTOR_PINS, check_transfer
out = Path(out)
require(receipt["passed"] is True and receipt["error"] is None and receipt["cleanup_errors"] == [],
"execution failed")
require(receipt["source_before"] == receipt["source_after"] and len(receipt["source_before"]) == 1407,
"source map mismatch")
require(receipt["default_player_before"] == receipt["default_player_after"], "ordinary player changed")
require(receipt["dependencies_before"] == receipt["dependencies_after"] == DEPENDENCIES, "dependency pins")
require(receipt["collector_before"] == receipt["collector_after"] == COLLECTOR_PINS,
"collector changed")
require(receipt["worker_before"] == receipt["worker_after"] and set(receipt["worker_before"]) ==
{"restart_pair.py", "restart_probe.gd", "check_restart.py", "test_restart.py"}, "worker changed")
require(receipt["cross_cutting"] == CROSS, "cross-cutting record")
require(receipt["original_credit"] == 0 and receipt["windows_verified"] is False and
receipt["operations_200_guests_verified"] is False, "scope expanded")
rows = receipt["phases"]
require([r["phase"] for r in rows] == PHASES, "phase order/incomplete execution")
pids = []
for row in rows:
report = bound_raw(out / row["phase"], row)
pids.extend(row["capture"]["actual_captured_pids"])
require(row["stage_before"] == row["stage_after"] if row["phase"] != "import"
else row["stage_preserved"] is True, "stage changed")
require(row["source_preserved"] is True and row["player_preserved"] is True, "phase preservation")
startup = row["startup_project"]
require(startup["fresh_before"] is True and sha(startup["path"]) == startup["sha256"], "startup profile")
if report:
guard = row["guard"]
expected = {"verified": True, "conditions": [True] * 5, "conditions_checked": 5,
"actual_user_data_dir": row["runtime_profile"],
"expected_user_data_dir": row["runtime_profile"],
"globalized_probe": str(Path(row["runtime_profile"]) / "guard-probe"),
"custom_user_dir_name": row["runtime_name"], "fresh_before_parent_initialize": True,
"profile_writes_before_guard": 0, "project_settings_persisted": False}
require(all(type(guard.get(k)) is type(v) and guard[k] == v for k, v in expected.items()),
"guard mismatch")
guard_path = out / (row["phase"] + "-guard.json")
require(sha(guard_path) == row["guard_sha256"] and json.loads(guard_path.read_text()) == guard,
"guard raw binding")
for name, evidence in report["states"].items():
require(pin(out / (row["phase"] + "-states") / (name + ".bin")) ==
{k: evidence[k] for k in ("sha256", "bytes")}, "state bytes SHA")
require(receipt["profiles"][row["runtime_profile"]].get(SIDECAR) ==
{k: row["sidecar"][k] for k in ("sha256", "bytes")}, "sidecar absent from file map")
require(len(set(pids)) == len(pids), "reused PID")
require({r["pid"] for r in receipt["cleanup"]} == set(pids) and all(
r["engine_ended"] is True and r["outer_cleanup_errors"] == [] and
r["foreign_process_or_group_signals"] == 0 for r in receipt["cleanup"]), "cleanup mismatch")
for start in (3, 5):
check_pair(rows[start]["report"], rows[start + 1]["report"],
bound_sidecar(out, rows[start]), bound_sidecar(out, rows[start + 1]))
transfer = out / (rows[start]["phase"][0] + "-transfer")
manifest_path = transfer / "manifest.json"
manifest = json.loads(manifest_path.read_text())
check_transfer(transfer, manifest)
require(rows[start + 1]["report"]["transfer_manifest_sha256"] == sha(manifest_path),
"reader manifest SHA")
for phase_index, kinds in ((start, ("good",)), (start + 1, ("good", "tampered"))):
profile = rows[phase_index]["runtime_profile"]
for kind in kinds:
for name, expected in manifest["files"][kind].items():
relative = "p28_restart/" + kind + "/" + name
require(receipt["profiles"][profile].get(relative) == expected,
"private package differs from transfer")
for path, expected in receipt["script_pins"].items():
require(sha(path) == expected, "executed script changed")
check_probe((out / "restart_probe.gd").read_text())
require(sha(out / "restart_probe.gd") == receipt["worker_before"]["restart_probe.gd"],
"executed probe differs from submitted source")
require(receipt["owned_writes"] == [], "probe/driver wrote owned folder")
require(receipt["coverage"] == coverage([bound_sidecar(out, r)["report"] for r in rows[3:]]),
"overload coverage/persistence claim")
return True
def main():
import argparse
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("execution", type=Path)
args = parser.parse_args()
check_receipt(json.loads(args.execution.read_text()), args.execution.parent)
print("P28_RESTART_CHECK=PASS")
if __name__ == "__main__":
main()
@@ -0,0 +1,322 @@
#!/usr/bin/env python3
"""Root-only four-PID RESTART driver. --check performs no writes or launches."""
import argparse
import importlib.util
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import uuid
sys.dont_write_bytecode = True
import check_restart as check
HERE, ROOT = check.HERE, check.ROOT
COLLECTOR = check.BASE + "collector/collect_p28_01.py"
COLLECTOR_PINS = {
"collect_p28_01.py": check.DEPENDENCIES[COLLECTOR],
"check_p28_01_report.py": check.DEPENDENCIES[check.BASE + "collector/check_p28_01_report.py"],
"measure_p28_01.gd": "4acef88bce4ac77f3f5d2659d766afcc5fd139cee381118839012022772946bb",
"test_collect_p28_01.py": "99d86ea723c976c95dbd283acbb85981eabf427b30994e652002ec0e76dc4ab0",
}
def load_dependencies():
check.check_dependencies()
for name in check.DEPENDENCIES:
check.check_imports((ROOT / name).read_text(), external=name)
for name in ("restart_pair.py", "check_restart.py", "test_restart.py"):
check.check_imports((HERE / name).read_text())
check.check_modules()
sys.path.insert(0, str((ROOT / COLLECTOR).parent))
spec = importlib.util.spec_from_file_location("restart_collector", ROOT / COLLECTOR)
collector = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = collector
spec.loader.exec_module(collector)
standard = collector.load_tool(collector.EXTERNAL_IMPORTS[0])
outer = collector.load_tool(collector.EXTERNAL_IMPORTS[1])
check.check_modules()
check.check_modules({"collector": collector, "standard": standard, "outer": outer, "native": outer.native})
check.require(Path(outer.native.helper["__file__"]).resolve() ==
ROOT / "tools/regression/p09_owned_engine_process.py", "exec helper closure")
return collector, standard, outer
def collector_pins():
actual = {name: check.sha((ROOT / COLLECTOR).parent / name) for name in COLLECTOR_PINS}
check.require(actual == COLLECTOR_PINS, "collector differs from Q")
return actual
def plan(collector, engine, out):
stage, wrapper = out / "stage", out / "guarded.gd"
return [collector.argv_for(engine, stage, wrapper, True),
collector.parse_argv(engine, stage, out / "restart_probe.gd"),
collector.parse_argv(engine, stage, wrapper)] + [
collector.argv_for(engine, stage, wrapper) for _ in range(4)]
def schedule(rows):
for index, label in enumerate(check.PHASES):
check.require(all(row["passed"] is True for row in rows), "previous phase failed")
if label.endswith("reader"):
check.require(rows and rows[-1]["phase"] == label.replace("reader", "writer") and
rows[-1].get("report", {}).get("stop_reason") == "complete",
"reader requires successful writer")
yield index, label
check.require(len(rows) == index + 1 and rows[-1]["phase"] == label and rows[-1]["passed"] is True,
"phase did not complete")
def safe_inventory(directory):
directory = Path(directory)
check.require(directory.is_dir() and not directory.is_symlink(), "package missing/symlink")
result = {}
for path in sorted(directory.rglob("*")):
check.require(not path.is_symlink(), "package symlink")
if path.is_file():
result[path.relative_to(directory).as_posix()] = check.pin(path)
check.require(result, "empty package")
return result
def create_transfer(source, destination, write):
"""Copy only after writer exit; never pre-populate the reader profile."""
before = safe_inventory(source)
check.require("world.bin" in before and not destination.exists(), "transfer admission")
destination.mkdir()
shutil.copytree(source, destination / "good")
check.require(safe_inventory(destination / "good") == before, "good copy differs")
shutil.copytree(destination / "good", destination / "tampered")
world = destination / "tampered/world.bin"
data = bytearray(world.read_bytes())
check.require(data, "empty world")
offset = len(data) // 2
data[offset] ^= 1
world.write_bytes(data)
manifest = {"files": {"good": before, "tampered": safe_inventory(destination / "tampered")},
"tamper": {"file": "world.bin", "offset": offset, "xor": 1,
"before_sha256": before["world.bin"]["sha256"], "after_sha256": check.sha(world)}}
write(destination / "manifest.json", manifest)
check_transfer(destination, manifest)
check.require(safe_inventory(source) == before, "writer package changed")
return manifest
def check_transfer(directory, manifest):
check.require(set(manifest["files"]) == {"good", "tampered"}, "transfer kinds")
for kind in ("good", "tampered"):
check.require(safe_inventory(directory / kind) == manifest["files"][kind], "transfer SHA mismatch")
good = (directory / "good/world.bin").read_bytes()
bad = (directory / "tampered/world.bin").read_bytes()
tamper = manifest["tamper"]
check.require(len(good) == len(bad) > 0 and tamper["offset"] == len(good) // 2 and tamper["xor"] == 1,
"tamper location")
expected = bytearray(good)
expected[len(good) // 2] ^= 1
check.require(bytes(expected) == bad and tamper["before_sha256"] == check.sha(directory / "good/world.bin")
and tamper["after_sha256"] == check.sha(directory / "tampered/world.bin"), "tamper bytes")
for name, value in manifest["files"]["good"].items():
if name != "world.bin":
check.require(manifest["files"]["tampered"].get(name) == value, "extra tamper difference")
check.require(set(manifest["files"]["good"]) == set(manifest["files"]["tampered"]), "tamper inventory")
def fresh_profile(path):
check.require(not path.exists(), "profile must be fresh; pre-guard writes forbidden")
def committed_source(source, commit):
"""Read-only Git operations: the 1407 files must be the actual HEAD bytes."""
tracked = subprocess.check_output(["git", "-C", str(ROOT), "ls-tree", "-r", commit], text=True)
selected = {}
for line in tracked.splitlines():
metadata, name = line.split("\t", 1)
if name.split("/", 1)[0] in ("autoload", "scripts", "scenes", "data", "tests", "assets", "tools") or \
name in ("project.godot", "export_presets.cfg", "Makefile", "AGENTS.md"):
if Path(name).name != ".DS_Store" and "__pycache__" not in Path(name).parts:
selected[name] = metadata.split()[2]
check.require(set(selected) == set(source), "source map differs from HEAD")
for name, expected in selected.items():
actual = subprocess.check_output(["git", "-C", str(ROOT), "hash-object", str(ROOT / name)], text=True).strip()
check.require(actual == expected, "dirty product source: " + name)
def bind_report(out, label, row):
text = (out / label / "stdout.log").read_text()
reports = [s.partition("=")[2] for s in text.splitlines() if s.startswith("P28_RESTART_REPORT=")]
check.require(len(reports) == 1, "one raw report required")
row["report"] = json.loads(reports[0])
copy_states(out, row)
check.bound_raw(out / label, row)
return row["report"]
def copy_states(out, row):
folder = out / (row["phase"] + "-states")
folder.mkdir()
profile = Path(row["runtime_profile"])
source = profile / check.SIDECAR
row["sidecar"] = {"path": check.SIDECAR, **check.pin(source)}
shutil.copyfile(source, folder / "report_full.json")
check.require(check.pin(source) == check.pin(folder / "report_full.json"), "sidecar copy differs")
for name, expected in row["report"]["states"].items():
source = profile / expected["path"]
check.require(source.resolve().is_relative_to(profile.resolve()) and
check.pin(source) == {k: expected[k] for k in ("bytes", "sha256")}, "state binding")
shutil.copyfile(source, folder / (name + ".bin"))
check.require(check.pin(source) == check.pin(folder / (name + ".bin")), "state copy differs")
def main():
parser = argparse.ArgumentParser(description=__doc__)
mode = parser.add_mutually_exclusive_group(required=True)
mode.add_argument("--check", action="store_true")
mode.add_argument("--run", action="store_true")
for name in ("readonly", "fixture", "engine", "output"):
parser.add_argument("--" + name, type=Path, required=True)
args = parser.parse_args()
collector, standard, outer = load_dependencies()
pinned = collector_pins()
readonly, fixture, engine, out = (p.resolve() for p in (args.readonly, args.fixture, args.engine, args.output))
inputs = collector.inputs(readonly)
check.require(check.sha(fixture) == collector.FIXTURE_SHA and check.sha(engine) == collector.ENGINE_SHA,
"fixture/engine SHA")
check.check_probe((HERE / "restart_probe.gd").read_text())
source = collector.source_map(standard, ROOT)
check.require(len(source) == 1407, "source count")
commit = subprocess.check_output(["git", "-C", str(ROOT), "rev-parse", "HEAD"], text=True).strip()
committed_source(source, commit)
worker_pins = {name: check.sha(HERE / name) for name in
("restart_pair.py", "restart_probe.gd", "check_restart.py", "test_restart.py")}
commands = plan(collector, engine, out)
admission = {"commit": commit, "source_map": source, "readonly": inputs, "planned_argv": commands,
"engine_sha256": check.sha(engine), "fixture_sha256": check.sha(fixture),
"dependencies": check.DEPENDENCIES, "collector_Q": pinned,
"worker_pins": worker_pins,
"phases": check.PHASES, "engines_started": 0}
check.require(not out.exists(), "new output required")
if args.check:
print(json.dumps(admission, ensure_ascii=False, indent=2))
return 0
check.require(sys.platform == "darwin", "reviewed native platform is macOS")
collector.no_live_engine()
check.require(shutil.disk_usage(out.parent).free >= 1200000000, "disk space")
player = standard.default_player(ROOT)
out.mkdir(parents=True)
collector.write(out / "admission.json", admission)
rows, profiles = [], []
error = None
scripts = {}
receipt = {}
try:
stage = out / "stage"
stage.mkdir()
for name in source:
target = stage / name
target.parent.mkdir(parents=True, exist_ok=True)
standard.copy_source(ROOT / name, target)
expected = standard.inventory(stage, stage=True)
check.require(expected == source, "stage source differs")
probe, guard, wrapper = (out / n for n in ("restart_probe.gd", "profile_guard.gd", "guarded.gd"))
probe.write_bytes((HERE / probe.name).read_bytes())
guard.write_bytes((readonly / "run-r02/profile_guard.gd").read_bytes())
wrapper.write_text("extends " + json.dumps(str(probe)) + "\nconst Guard = preload(" +
json.dumps(str(guard)) + ")\nfunc _initialize() -> void:\n"
"\tif not Guard.activate():\n\t\tquit(97)\n\t\treturn\n\tsuper._initialize()\n")
scripts = {str(p): check.sha(p) for p in (probe, guard, wrapper)}
public = (stage / "project.godot").read_bytes()
for index, label in schedule(rows):
check.check_dependencies()
collector_pins()
check.check_modules()
check.require(collector.source_map(standard, ROOT) == source and standard.default_player(ROOT) == player,
"source/player changed before phase")
check.require(standard.inventory(stage, stage=True) == expected and
all(check.sha(p) == value for p, value in scripts.items()) and
all(check.sha(HERE / p) == value for p, value in worker_pins.items()),
"stage/scripts changed")
startup_name = "TheTree-PCK-tests-" + uuid.uuid4().hex + "-restart-startup"
runtime_name = "TheTree-PCK-tests-" + uuid.uuid4().hex + "-restart-runtime"
startup, runtime = (standard.profile_path(n) for n in (startup_name, runtime_name))
fresh_profile(startup)
fresh_profile(runtime)
profiles.extend([startup, runtime])
transfer = out / (label[0] + "-transfer")
env = {"THE_TREE_PACK_PROFILE_NAME": runtime_name, "THE_TREE_PACK_PROFILE_EXPECTED": str(runtime),
"THE_TREE_PACK_PROFILE_REPORT": str(out / (label + "-guard.json")),
"THE_TREE_RESTART_ROLE": label, "THE_TREE_RESTART_K": "30",
"THE_TREE_RESTART_TRANSFER": str(transfer),
"THE_TREE_RESTART_TRANSFER_MANIFEST": str(transfer / "manifest.json"),
"THE_TREE_P28_FIXTURE": str(fixture), "THE_TREE_P28_FIXTURE_SHA": collector.FIXTURE_SHA}
if label.endswith("reader"):
check_transfer(transfer, json.loads((transfer / "manifest.json").read_text()))
before_stage = collector.digest(expected)
row = collector.run_private_engine(standard, outer, commands[index], out / label, env,
stage, public, startup_name)
row["phase"] = label
rows.append(row)
check.require(row["passed"], "owned engine failure: " + label)
after_stage = standard.inventory(stage, stage=True)
collector.stage_gate(expected, after_stage, importing=label == "import")
row.update(stage_before=before_stage, stage_after=collector.digest(after_stage), stage_preserved=True,
source_preserved=collector.source_map(standard, ROOT) == source,
player_preserved=standard.default_player(ROOT) == player)
expected = after_stage
if label in check.PHASES[3:]:
guard_path = out / (label + "-guard.json")
observation = json.loads(guard_path.read_text())
collector.guard_gate(observation, runtime, runtime_name)
row.update(runtime_profile=str(runtime), runtime_name=runtime_name,
guard=observation, guard_sha256=check.sha(guard_path))
report = bind_report(out, label, row)
collector.write(out / (label + "-report.json"), report)
if label.endswith("writer"):
create_transfer(runtime / "p28_restart/good", transfer, collector.write)
else:
check.require(report["transfer_manifest_sha256"] == check.sha(transfer / "manifest.json"),
"reader transfer manifest binding")
check.check_pair(rows[-2]["report"], report, check.bound_sidecar(out, rows[-2]),
check.bound_sidecar(out, row))
else:
check.bound_raw(out / label, row)
check.require(row["source_preserved"] and row["player_preserved"] and
check.sha(fixture) == collector.FIXTURE_SHA and
all(check.sha(p) == value for p, value in scripts.items()), "post-phase preservation")
except BaseException as caught:
error = repr(caught)
finally:
cleanup, cleanup_errors = outer.finish_captured(outer.OWNED)
receipt = {"admission": admission, "phases": rows, "error": error, "passed": error is None,
"source_before": source, "source_after": collector.source_map(standard, ROOT),
"default_player_before": player, "default_player_after": standard.default_player(ROOT),
"dependencies_before": check.DEPENDENCIES,
"dependencies_after": {p: check.sha(ROOT / p) for p in check.DEPENDENCIES},
"collector_before": pinned,
"collector_after": {p: check.sha((ROOT / COLLECTOR).parent / p) for p in pinned},
"script_pins": scripts, "cleanup": cleanup, "cleanup_errors": cleanup_errors,
"worker_before": worker_pins,
"worker_after": {p: check.sha(HERE / p) for p in worker_pins},
"profiles": {str(p): collector.profile_files(p) for p in profiles}, "owned_writes": [],
"cross_cutting": check.CROSS, "original_credit": 0,
"windows_verified": False, "operations_200_guests_verified": False}
try:
receipt["coverage"] = check.coverage([
check.bound_sidecar(out, row)["report"] for row in rows if "sidecar" in row])
except (ValueError, KeyError, TypeError, OSError) as caught:
receipt["coverage"] = {"overload_nonzero_backlog": "not_exercised",
"error": repr(caught)}
receipt.update(passed=False, error=receipt["error"] or "coverage: " + repr(caught))
if receipt["passed"]:
try:
check.check_receipt(receipt, out)
except (ValueError, KeyError, TypeError, OSError) as caught:
receipt.update(passed=False, error="checker: " + repr(caught))
collector.write(out / "execution.json", receipt)
return 0 if receipt["passed"] else 1
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,603 @@
extends SceneTree
## Root-owned execution only. All files are written after Guard.activate().
var GameClock: Variant
var runtime: Variant
var main: Variant
var report: Dictionary = {}
var signals: Array = []
var key_forms: Dictionary = {}
var role := ""
var start_minute := 0
var selected_tick := false
var overloaded := false
var io_ready := false
var finished := false
var E := ""
var package: Dictionary = {}
var failure_event: Dictionary = {}
var boundary: Variant = null
var at_390_event_verbatim: Array = []
var at_390_pending: Array = []
var redaction_ok := true
var canonical_key_collision := false
const SAVE_EVENTS := ["SAVE_CHECKPOINT_SUCCEEDED", "SAVE_CHECKPOINT_FAILED", "SAVE_LOADED",
"SAVE_LOAD_FAILED", "SAVE_MIGRATION_SUCCEEDED", "SAVE_MIGRATION_FAILED",
"SAVE_RECOVERY_LOADED", "SAVE_RECOVERY_CANDIDATE_LOADED", "SAVE_RECOVERY_FAILED"]
func canonical_json(value: Variant) -> String:
if value is Dictionary:
var keys: Array = value.keys()
keys.sort_custom(func(a, b): return str(a) < str(b))
for index: int in range(1, keys.size()):
if str(keys[index - 1]) == str(keys[index]):
canonical_key_collision = true
# Unwind serialization before emitting failure evidence.
call_deferred("finish", "canonical_key_collision")
return ""
var parts: PackedStringArray = []
for key: Variant in keys:
parts.append(JSON.stringify(str(key)) + ":" + canonical_json(value[key]))
return "{" + ",".join(parts) + "}"
if value is Array:
var parts: PackedStringArray = []
for child: Variant in value:
parts.append(canonical_json(child))
return "[" + ",".join(parts) + "]"
if value is int or value is float:
return "%.17f" % float(value)
return JSON.stringify(value)
func event_summary(event: Dictionary) -> Dictionary:
var canonical: Dictionary = {"event_id": E, "replaced_for_cross_pid_compare": true} \
if field(event, "event_id") == E else event
return {"event_id": field(event, "event_id"), "event_type": field(event, "event_type"),
"absolute_minute": field(event, "absolute_minute"),
"raw_event_sha256": bytes_hash(canonical_json(event).to_utf8_buffer()),
"canonical_sha256": bytes_hash(canonical_json(canonical).to_utf8_buffer())}
func observe_390() -> void:
if not role.begins_with("O-") or GameClock.absolute_minute != 390 or report.at_390 != null:
return
var observed := operations_observation()
var state := witness(runtime.create_snapshot())
report.at_390 = {"clock": {"absolute_minute": GameClock.absolute_minute},
"operations": observed.operations, "processed_arrival_minutes": observed.processed_arrival_minutes,
"guest_auto_ids": observed.guest_auto_ids, "guest_auto_count": observed.guest_auto_count,
"published_ids_count": state.published_ids.size(), "domain_event_counter": state.counter,
"events": []}
at_390_pending = state.recent_events.duplicate(true)
if report.has("saved_minute"):
bind_390_events()
func bind_390_events() -> void:
if report.at_390 == null:
return
at_390_event_verbatim = []
report.at_390.events = []
for event: Dictionary in at_390_pending:
var minute: int = field(event, "absolute_minute")
if minute > report.saved_minute and minute <= 390:
at_390_event_verbatim.append(event.duplicate(true))
report.at_390.events.append(event_summary(event))
func deadline_timer_seconds() -> float:
return Time.get_ticks_msec() / 1000.0
func field(d: Variant, name: String) -> Variant:
if d is Dictionary:
if d.has(StringName(name)):
key_forms[name] = "StringName"
return d[StringName(name)]
if d.has(String(name)):
key_forms[name] = "String"
return d[String(name)]
key_forms[name] = "missing_product_field"
return null
func _initialize() -> void:
call_deferred("begin")
func bytes_hash(data: PackedByteArray) -> String:
var context := HashingContext.new()
context.start(HashingContext.HASH_SHA256)
context.update(data)
return context.finish().hex_encode()
func runtime_part(snapshot: Dictionary) -> Dictionary:
return field(field(snapshot, "systems"), "runtime")
func witness(snapshot: Dictionary) -> Dictionary:
var part := runtime_part(snapshot)
var events: Dictionary = field(part, "domain_events")
return {"counter": field(field(field(part, "id_generator"), "counters"), "domain_event"),
"published_ids": field(events, "published_ids").duplicate(true),
"recent_events": field(events, "recent_events").duplicate(true)}
func different_paths(a: Variant, b: Variant, path := "$", depth := 0) -> Array:
var result: Array = []
if var_to_bytes(a) == var_to_bytes(b):
return result
if depth >= 4 or typeof(a) != typeof(b):
return [path]
if a is Dictionary:
for key: Variant in a:
if not b.has(key):
result.append(path + "." + str(key))
else:
result.append_array(different_paths(a[key], b[key], path + "." + str(key), depth + 1))
for key: Variant in b:
if not a.has(key):
result.append(path + "." + str(key))
elif a is Array and a.size() == b.size():
for index in range(a.size()):
result.append_array(different_paths(a[index], b[index], path + "[%d]" % index, depth + 1))
else:
result.append(path)
# Typed container/key/order differences can exist without value differences.
if result.is_empty():
result.append(path)
return result
func compare(expected: Dictionary, actual: Dictionary) -> Dictionary:
var a := var_to_bytes(expected)
var b := var_to_bytes(actual)
return {"method": "var_to_bytes", "equal": a == b, "expected_sha256": bytes_hash(a),
"actual_sha256": bytes_hash(b), "excluded_paths": [],
"diff_paths": different_paths(expected, actual)}
func record_state(name: String, value: Dictionary) -> bool:
var path := "user://p28_restart/evidence/" + name + ".bin"
if DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(path).get_base_dir()) != OK:
return false
var data := var_to_bytes(value)
var file := FileAccess.open(path, FileAccess.WRITE)
if file == null:
return false
file.store_buffer(data)
file.close()
report.states[name] = {"path": path.trim_prefix("user://"), "bytes": data.size(),
"sha256": bytes_hash(data)}
return FileAccess.get_sha256(path) == report.states[name].sha256
func on_save(result: Dictionary) -> void:
signals.append(result.duplicate(true))
func auto_ids() -> Array:
var ids: Array = []
for guest: Variant in runtime.guest_service.get_guests():
if str(guest.guest_id).begins_with("guest-auto-"):
ids.append(str(guest.guest_id))
ids.sort()
return ids
func operations_observation() -> Dictionary:
var ids := auto_ids()
var processed: Array = []
var arrivals: Array = []
if runtime.operations_coordinator != null:
var state: Dictionary = runtime.operations_coordinator.create_snapshot()
processed = field(state, "processed_arrival_minutes").duplicate()
arrivals = runtime.operations_coordinator.get_arrival_reports().duplicate(true)
return {"clock": GameClock.absolute_minute, "guest_auto_ids": ids, "guest_auto_count": ids.size(),
"operations": runtime.get_operations_report(), "processed_arrival_minutes": processed,
"arrival_reports": arrivals}
func on_tick(minute: int) -> void:
# During deterministic stepping the observation is made after advance returns.
if not io_ready:
observe_390()
if io_ready or finished or selected_tick:
return
var observed := operations_observation()
if role == "O-writer":
report.ui_ticks.append(observed)
var stop: bool = (role == "R-writer" and minute - start_minute >= 10) or \
(role == "O-writer" and (observed.guest_auto_count > 0 or minute - start_minute >= 120))
if stop:
GameClock.set_paused(true)
selected_tick = true
func on_overload(backlog: int) -> void:
overloaded = true
report.overloads.append({"minute": GameClock.absolute_minute, "backlog": backlog})
func clock_observation() -> Dictionary:
return {"minute": GameClock.absolute_minute, "paused": GameClock.paused,
"backlog": GameClock.get_backlog_minutes(),
"accumulator_hex": PackedFloat64Array([GameClock.get("_accumulator")]).to_byte_array().hex_encode()}
func begin() -> void:
GameClock = root.get_node("GameClock")
runtime = root.get_node("SimulationRuntime")
role = OS.get_environment("THE_TREE_RESTART_ROLE")
report = {"schema": "p28-restart-v1", "role": role, "pid": OS.get_process_id(),
"main_added": false, "k_target": 30, "actual_k": 0, "io": [], "states": {},
"minutes": [], "ui_ticks": [], "overloads": [], "boundary": null, "next_boundary": null,
"at_390": null,
"comparison_scope": "complete_typed_var_to_bytes", "excluded_paths": [],
"transfer_before_guard_writes": 0, "transfer_verified": false,
"probe_deadline_seconds": 1740}
var elapsed := deadline_timer_seconds()
var interval := 1740.0 - elapsed
report["probe_deadline"] = {"limit_seconds_from_engine_start": 1740,
"engine_elapsed_at_begin_seconds": elapsed, "timer_seconds": interval}
if interval <= 0:
finish("probe_deadline")
return
create_timer(interval).timeout.connect(func() -> void: finish("probe_deadline"))
if OS.get_environment("THE_TREE_RESTART_K") != "30" or role not in ["R-writer", "R-reader", "O-writer", "O-reader"]:
finish("invalid_environment")
return
# No await before main: the default autoload clock cannot process here.
if role == "R-writer":
var fixture := OS.get_environment("THE_TREE_P28_FIXTURE")
if FileAccess.get_sha256(fixture) != OS.get_environment("THE_TREE_P28_FIXTURE_SHA"):
finish("fixture_sha")
return
var file := FileAccess.open(fixture, FileAccess.READ)
if file == null:
finish("fixture_missing")
return
var value: Variant = file.get_var(false)
file.close()
if not value is Dictionary or not runtime.restore_snapshot(value):
finish("fixture_restore")
return
main = load("res://scenes/main/main.tscn").instantiate()
root.add_child(main)
report.main_added = true
report["startup"] = {"start_report": main.get("_operations_start_report").duplicate(true),
"operations": runtime.get_operations_report(), "clock": clock_observation()}
if role != "R-writer" and not GameClock.paused:
finish("main_did_not_pause")
return
var start_result: Dictionary = report.startup.start_report
var operations_enabled: Variant = field(report.startup.operations, "enabled")
if role == "R-writer":
if operations_enabled != false or field(start_result, "code") != "INVALID_START_TIME":
finish("unexpected_R_start")
return
elif operations_enabled != true or field(start_result, "ok") != true or GameClock.absolute_minute != 360:
finish("unexpected_fresh_start")
return
runtime.save_operation_completed.connect(on_save)
GameClock.tick_completed.connect(on_tick)
GameClock.simulation_overloaded.connect(on_overload)
start_minute = GameClock.absolute_minute
report["start_minute"] = start_minute
if role.ends_with("writer"):
main.call("_set_speed", 1)
while not GameClock.paused and not finished:
await process_frame
if finished:
return
if not selected_tick and not overloaded:
finish("unexpected_ui_stop")
return
if role == "O-writer" and auto_ids().is_empty():
report["boundary"] = null
report["boundary_reason"] = "no_arrival_within_cap" if GameClock.absolute_minute - start_minute >= 120 else "stopped_before_arrival"
finish(report.boundary_reason)
return
if not writer_save():
finish("save_comparison_failed")
return
else:
if not import_transfer():
finish("transfer_failed")
return
if not reader_load():
finish("load_comparison_failed")
return
report["event_id"] = E
report["saved_minute"] = GameClock.absolute_minute
bind_390_events()
boundary = operations_observation() if role.begins_with("O-") else null
report["boundary"] = boundary
var idle_before: Dictionary = runtime.create_snapshot()
var clock_before := clock_observation()
await process_frame
await process_frame
if finished:
return
var idle_after: Dictionary = runtime.create_snapshot()
report["paused_idle"] = {"before": clock_before, "after": clock_observation(),
"comparison": compare(idle_before, idle_after)}
if not report.paused_idle.comparison.equal or report.paused_idle.before != report.paused_idle.after:
finish("paused_backlog_consumed")
return
io_ready = true
for _index in range(30):
if not deterministic_step():
finish("no_tick_advance_or_invalid_state")
return
# Keep the event loop responsive to deadline/audio while remaining paused.
await process_frame
if finished:
return
if not record_state("final", runtime.create_snapshot()):
finish("state_write_failed")
return
report["final_minute"] = GameClock.absolute_minute
if role.begins_with("O-"):
if report.at_390 == null:
finish("at_390_not_reached")
return
var last := operations_observation()
var added: Array = []
for minute: Variant in last.processed_arrival_minutes:
if minute not in boundary.processed_arrival_minutes:
added.append(minute)
report["next_boundary"] = {"minute": added[0] if added.size() == 1 else null,
"processed_once": added.size() == 1, "before": boundary.processed_arrival_minutes,
"after": last.processed_arrival_minutes, "arrival_reports": last.arrival_reports,
"guest_auto_ids": last.guest_auto_ids}
if added.size() != 1:
finish("next_arrival_boundary_missing_or_duplicate")
return
finish("complete")
func io_proof(base: Dictionary, after: Dictionary, kind: String, returned: Variant) -> bool:
var row := {"kind": kind, "signal_count": signals.size(),
"return_kind": "bool" if kind == "save" else "void", "return_value": returned}
report.io.append(row)
if signals.size() != 1:
return false
var signal_result: Dictionary = signals[0]
var payload: Dictionary = runtime.call("_save_event_payload", signal_result)
var latest: Dictionary = runtime.latest_save_operation_result.duplicate(true)
row["signal_projection"] = "_save_event_payload"
row["signal_payload"] = payload
row["latest"] = latest
row["payload_bytes_equal"] = var_to_bytes(payload) == var_to_bytes(latest)
var before := witness(base)
var after_witness := witness(after)
var eid := "domain_event.%012d" % (int(before.counter) + 1)
var found: Array = []
for event: Dictionary in after_witness.recent_events:
if field(event, "event_id") == eid:
found.append(event)
if found.size() != 1 or before.published_ids.has(eid):
return false
var event: Dictionary = found[0]
row["event"] = event
row["before"] = before
row["after"] = after_witness
row["minute_before"] = field(field(base, "clock"), "absolute_minute")
row["minute_after"] = field(field(after, "clock"), "absolute_minute")
row["paused_before"] = field(field(base, "clock"), "paused")
row["paused_after"] = field(field(after, "clock"), "paused")
row["dropped"] = before.recent_events[0] if before.recent_events.size() == 256 else null
var expected := base.duplicate(true)
var part := runtime_part(expected)
var counters: Dictionary = field(field(part, "id_generator"), "counters")
counters["domain_event"] = int(before.counter) + 1
var events: Dictionary = field(part, "domain_events")
var ids: Array = field(events, "published_ids")
ids.append(eid)
ids.sort()
var recent: Array = field(events, "recent_events")
if recent.size() > 256:
return false
if recent.size() == 256:
recent.pop_front()
recent.append(event.duplicate(true))
row["comparison"] = compare(expected, after)
var expected_type := {"save": "SAVE_CHECKPOINT_SUCCEEDED", "load": "SAVE_LOADED", "tamper": "SAVE_LOAD_FAILED"}
var ok: bool = row.payload_bytes_equal and row.comparison.equal and \
var_to_bytes(field(event, "payload")) == var_to_bytes(payload) and \
field(event, "event_type") == expected_type[kind] and field(event, "source_service") == "save_service" and \
field(event, "entity_ids").is_empty() and field(event, "causation_command_id") == 0 and \
row.minute_before == row.minute_after and field(event, "absolute_minute") == row.minute_after
if kind == "tamper":
var recovery: Variant = field(signal_result, "recovery_report")
var migration: Variant = field(signal_result, "migration_attempted")
row["failure"] = {"preload_pause_restored": field(signal_result, "preload_pause_restored"),
"loaded_clock_paused": field(signal_result, "loaded_clock_paused"), "recovery_report": recovery,
"migration_attempted": migration == true}
failure_event = event.duplicate(true)
return ok and field(payload, "ok") == false and field(payload, "code") != "OK" and \
row.failure.preload_pause_restored == true and row.failure.loaded_clock_paused == row.paused_before and \
row.paused_before == row.paused_after and (recovery == null or field(recovery, "restore_committed") == false)
E = eid
return ok and field(payload, "ok") == true and field(payload, "code") == "OK" and \
(returned == true if kind == "save" else returned == null) and row.paused_after == true and \
field(payload, "saved_absolute_minute") == row.minute_after
func writer_save() -> bool:
var before: Dictionary = runtime.create_snapshot()
var backlog: int = GameClock.get_backlog_minutes()
report["overload_case"] = {"exercised": not report.overloads.is_empty() and backlog > 0,
"overloads": report.overloads.size(), "backlog_at_save": backlog}
signals = []
var returned: bool = main.call("_save_manual_at_path", "user://p28_restart/good", "P28 RESTART")
var after: Dictionary = runtime.create_snapshot()
var loaded := SaveService.load_snapshot("user://p28_restart/good")
if field(loaded, "ok") != true:
return false
package = field(loaded, "snapshot")
report["package_matches_before"] = compare(before, package)
if not record_state("P", package) or not record_state("after_save", after):
return false
return report.package_matches_before.equal and io_proof(package, after, "save", returned)
func import_transfer() -> bool:
var transfer := OS.get_environment("THE_TREE_RESTART_TRANSFER")
var manifest_path := OS.get_environment("THE_TREE_RESTART_TRANSFER_MANIFEST")
if not transfer.is_absolute_path() or not manifest_path.is_absolute_path():
return false
var manifest: Variant = JSON.parse_string(FileAccess.get_file_as_string(manifest_path))
if not manifest is Dictionary:
return false
for kind: String in ["good", "tampered"]:
var target := "user://p28_restart/" + kind
if DirAccess.dir_exists_absolute(target):
return false
for relative: String in manifest.files[kind]:
if relative.is_absolute_path() or ".." in relative.split("/") or "\\" in relative:
return false
var source := transfer.path_join(kind).path_join(relative)
var expected: Dictionary = manifest.files[kind][relative]
if FileAccess.get_sha256(source) != expected.sha256:
return false
var data := FileAccess.get_file_as_bytes(source)
if data.size() != int(expected.bytes):
return false
var destination := target.path_join(relative)
if DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(destination).get_base_dir()) != OK:
return false
var file := FileAccess.open(destination, FileAccess.WRITE)
if file == null:
return false
file.store_buffer(data)
file.close()
if FileAccess.get_sha256(destination) != expected.sha256:
return false
report["transfer_manifest_sha256"] = FileAccess.get_sha256(manifest_path)
report["transfer_verified"] = true
return true
func reader_load() -> bool:
var loaded := SaveService.load_snapshot("user://p28_restart/good")
if field(loaded, "ok") != true:
return false
package = field(loaded, "snapshot")
var before: Dictionary = runtime.create_snapshot()
if not record_state("P", package) or not record_state("B", before):
return false
signals = []
main.call("_load_manual_at_path", "user://p28_restart/tampered", true)
var failed: Dictionary = runtime.create_snapshot()
if not record_state("after_tamper", failed) or not io_proof(before, failed, "tamper", null):
return false
signals = []
main.call("_load_manual_at_path", "user://p28_restart/good", true)
var after: Dictionary = runtime.create_snapshot()
if not record_state("after_load", after) or not io_proof(package, after, "load", null):
return false
report["failure_event_absent"] = true
for event: Dictionary in witness(after).recent_events:
if var_to_bytes(event) == var_to_bytes(failure_event):
report.failure_event_absent = false
return report.failure_event_absent
func deterministic_step() -> bool:
if not io_ready or not GameClock.paused:
return false
var before: int = GameClock.absolute_minute
var backlog: int = GameClock.get_backlog_minutes()
GameClock.advance_minutes(1)
var after: int = GameClock.absolute_minute
if after != before + 1:
return false
observe_390()
var state: Dictionary = runtime.create_snapshot()
var normalized := state.duplicate(true)
var recent: Array = field(field(runtime_part(normalized), "domain_events"), "recent_events")
var replacement: Variant = null
var count := 0
var recent_ids: Array = []
for index in range(recent.size()):
recent_ids.append(field(recent[index], "event_id"))
if field(recent[index], "event_id") == E:
replacement = recent[index].duplicate(true)
recent[index] = {"event_id": E, "replaced_for_cross_pid_compare": true}
count += 1
if count > 1:
return false
report.minutes.append({"before": before, "after": after, "paused": GameClock.paused,
"backlog_before": backlog, "backlog_after": GameClock.get_backlog_minutes(),
"sha256": bytes_hash(var_to_bytes(normalized)), "scope": "complete_typed_var_to_bytes",
"excluded_paths": [], "replacement": replacement, "replacement_count": count,
"recent_count": recent.size(), "recent_ids": recent_ids})
report.actual_k += after - before
if role.begins_with("O-") and after == 390:
var observation: Dictionary = report.at_390.duplicate(true)
observation.erase("events")
report.minutes[-1]["operations_observation"] = observation
return GameClock.paused and backlog == GameClock.get_backlog_minutes()
func is_save_event(event: Variant) -> bool:
return event is Dictionary and field(event, "source_service") == "save_service" and \
field(event, "event_type") in SAVE_EVENTS
func redact_payload(payload: Dictionary, pointer: String) -> void:
if payload.has("timing_redactions"):
redaction_ok = false
return
var markers: Array = []
for key: String in ["duration_us", "runtime_duration_us"]:
if not payload.has(key):
redaction_ok = false
return
markers.append({"original_key": key, "sidecar_ref": pointer + "/" + key})
payload.erase(key)
payload["timing_redactions"] = markers
func redact_event(event: Variant, pointer: String) -> void:
if is_save_event(event):
redact_payload(event.payload, pointer + "/payload")
func public_report(full: Dictionary) -> Dictionary:
var result: Dictionary = full.duplicate(true)
for i in range(result.io.size()):
var row: Dictionary = result.io[i]
var pointer := "/report/io/%d" % i
for name: String in ["signal_payload", "latest"]:
if row.has(name):
redact_payload(row[name], pointer + "/" + name)
for name: String in ["event", "dropped"]:
if row.has(name):
redact_event(row[name], pointer + "/" + name)
for side: String in ["before", "after"]:
if row.has(side):
for j in range(row[side].recent_events.size()):
redact_event(row[side].recent_events[j], pointer + "/" + side + "/recent_events/%d" % j)
for k in range(result.minutes.size()):
redact_event(result.minutes[k].replacement, "/report/minutes/%d/replacement" % k)
return result
func public_has_forbidden(value: Variant) -> bool:
if value is Dictionary:
for key: Variant in value:
if str(key).ends_with("_" + "us") or str(key).ends_with("_" + "ms") or \
str(key) in ["performance", "statistics", "fps", "budget_verdict"]:
return true
if public_has_forbidden(value[key]):
return true
elif value is Array:
for child: Variant in value:
if public_has_forbidden(child):
return true
return false
func finish(reason: String) -> void:
if finished:
return
if canonical_key_collision:
reason = "canonical_key_collision"
finished = true
report["stop_reason"] = reason
report["key_forms"] = key_forms
var sidecar_path := "user://p28_restart/evidence/report_full.json"
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(sidecar_path).get_base_dir())
var file := FileAccess.open(sidecar_path, FileAccess.WRITE)
if file == null:
quit(1)
return
file.store_string(JSON.stringify({"report": report, "at_390_event_verbatim": at_390_event_verbatim}, "", true, true))
file.close()
# Partial failure evidence stays in the sidecar. Never emit a leaking public payload.
var public: Dictionary = public_report(report)
if not redaction_ok or public_has_forbidden(public) or public.is_empty():
print("P28_RESTART_EVIDENCE_FAILURE=" + reason)
else:
print("P28_RESTART_REPORT=" + JSON.stringify(public, "", true, true))
if is_instance_valid(main) and main.is_inside_tree():
main.ui_audio_window_close_drained.connect(emit_audio_close, CONNECT_ONE_SHOT)
get_root().close_requested.emit()
else:
quit(1)
func emit_audio_close(result: Dictionary) -> void:
print("P28_RESTART_AUDIO_CLOSE=" + JSON.stringify(result))
@@ -0,0 +1,876 @@
#!/usr/bin/env python3
"""Engine-free positive and adversarial controls. No native acceptance claimed."""
import copy
import hashlib
import json
import os
from pathlib import Path
import sys
import tempfile
import time
from types import SimpleNamespace
import unittest
from unittest.mock import patch
sys.dont_write_bytecode = True
import check_restart as check
import restart_pair as driver
DATA = b"synthetic typed bytes fixture (not engine evidence)"
HASH = hashlib.sha256(DATA).hexdigest()
def comparison():
return {"method": "var_to_bytes", "equal": True, "diff_paths": [], "excluded_paths": [],
"expected_sha256": HASH, "actual_sha256": HASH}
def history(count=256):
ids = ["domain_event.%012d" % n for n in range(1, count + 1)]
return {"counter": count, "published_ids": ids,
"recent_events": [{"event_id": eid, "event_type": "OLD", "payload": {"n": n}}
for n, eid in enumerate(ids)]}
def io(kind, minute=612, count=256):
before = history(count)
payload = {"ok": kind != "tamper", "code": "OK" if kind != "tamper" else "CORRUPT_WORLD",
"operation": "save" if kind == "save" else "load",
"save_path": "user://p28_restart/" + ("tampered" if kind == "tamper" else "good"),
"save_id": "synthetic", "saved_absolute_minute": minute,
"duration_us": 124, "runtime_duration_us": 57}
event = {"event_id": check.event_id(count),
"event_type": {"save": "SAVE_CHECKPOINT_SUCCEEDED", "load": "SAVE_LOADED",
"tamper": "SAVE_LOAD_FAILED"}[kind],
"source_service": "save_service", "entity_ids": [], "causation_command_id": 0,
"absolute_minute": minute, "payload": copy.deepcopy(payload)}
return {"kind": kind, "signal_count": 1, "signal_payload": payload, "latest": copy.deepcopy(payload),
"event": event, "signal_projection": "_save_event_payload", "payload_bytes_equal": True,
"return_kind": "bool" if kind == "save" else "void",
"return_value": True if kind == "save" else None,
"before": before, "after": check.transform(before, event),
"dropped": before["recent_events"][0] if count == 256 else None,
"comparison": comparison(), "minute_before": minute, "minute_after": minute,
"paused_before": True, "paused_after": True,
"failure": {"preload_pause_restored": True, "loaded_clock_paused": True,
"migration_attempted": False, "recovery_report": {"restore_committed": False}}}
def report(role="R-writer", pid=100):
writer, ops = role.endswith("writer"), role.startswith("O-")
minute = 361 if ops else 612
rows = [io("save", minute)] if writer else [io("tamper", 360, 3), io("load", minute)]
names = ["P", "after_save", "final"] if writer else ["P", "B", "after_tamper", "after_load", "final"]
event = rows[-1]["event"]
boundary = {"clock": minute, "guest_auto_ids": ["guest-auto-00000001"], "guest_auto_count": 1,
"operations": {"enabled": True}, "processed_arrival_minutes": [360],
"arrival_reports": [{"minute": 360}]} if ops else None
next_boundary = {"minute": 390, "processed_once": True, "before": [360], "after": [360, 390],
"arrival_reports": [{"minute": 360}, {"minute": 390}],
"guest_auto_ids": ["guest-auto-00000001", "guest-auto-00000002"]} if ops else None
clock = {"minute": minute, "paused": True, "backlog": 121, "accumulator_hex": "00"}
result = {"schema": "p28-restart-v1", "role": role, "pid": pid, "stop_reason": "complete",
"main_added": True, "k_target": 30, "actual_k": 30, "comparison_scope": "complete_typed_var_to_bytes",
"excluded_paths": [], "transfer_before_guard_writes": 0, "probe_deadline_seconds": 1740,
"probe_deadline": {"limit_seconds_from_engine_start": 1740,
"engine_elapsed_at_begin_seconds": 12.25, "timer_seconds": 1727.75},
"overloads": [],
"overload_case": {"exercised": False, "overloads": 0, "backlog_at_save": 121},
"io": rows, "package_matches_before": comparison(), "failure_event_absent": True,
"transfer_verified": True, "event_id": event["event_id"], "saved_minute": minute,
"start_minute": 360 if ops else 602, "final_minute": minute + 30,
"states": {n: {"path": "p28_restart/evidence/" + n + ".bin", "bytes": len(DATA), "sha256": HASH}
for n in names},
"paused_idle": {"before": clock, "after": copy.deepcopy(clock), "comparison": comparison()},
"boundary": boundary, "next_boundary": next_boundary, "ui_ticks": [copy.deepcopy(boundary)] if ops else [],
"minutes": [{"before": minute + n, "after": minute + n + 1, "paused": True,
"backlog_before": 121, "backlog_after": 121, "sha256": HASH,
"scope": "complete_typed_var_to_bytes", "excluded_paths": [],
"replacement": copy.deepcopy(event) if n < 5 else None,
"replacement_count": 1 if n < 5 else 0, "recent_count": 256,
"recent_ids": history(255)["published_ids"] +
([event["event_id"]] if n < 5 else ["domain_event.000000000256"])}
for n in range(30)], "at_390": None}
if ops:
result["at_390"] = {"clock": {"absolute_minute": 390}, "operations": {"enabled": True},
"processed_arrival_minutes": [360],
"guest_auto_ids": ["guest-auto-00000001"], "guest_auto_count": 1,
"domain_event_counter": 300, "published_ids_count": 300, "events": []}
result["minutes"][28]["operations_observation"] = {
k: copy.deepcopy(v) for k, v in result["at_390"].items() if k != "events"}
return result
def evidence(full, events=None):
sidecar = {"report": copy.deepcopy(full), "at_390_event_verbatim": copy.deepcopy(events or [])}
return check.redact_report(full), sidecar
def validate_report(full):
public, sidecar = evidence(full)
return check.check_report(public, sidecar)
def validate_pair(writer, reader):
public_writer, sw = evidence(writer)
public_reader, sr = evidence(reader)
return check.check_pair(public_writer, public_reader, sw, sr)
def summarize(event, eid):
return {**{k: event[k] for k in ("event_id", "event_type", "absolute_minute")},
"raw_event_sha256": check.json_sha(event),
"canonical_sha256": check.json_sha(check.canonical_event(event, eid))}
def write(path, value):
with Path(path).open("x") as stream:
json.dump(value, stream)
def audio(pid):
return {"coordinator": True, "passed": True, "owned_engine_pid": pid,
"all_owned_targets_released": True, "deadline_reached": False,
"clock_process_held_stopped": True, "window_input_held_disabled": True,
"restored_before_quit": False, "shared_bus_deleted": False, "settings_mutated": False}
def synthetic_receipt(out):
rows = []
profiles = {}
source_package = out / "synthetic-package"
source_package.mkdir()
(source_package / "world.bin").write_bytes(DATA)
(source_package / "manifest.json").write_text("{}")
transfers = {kind: driver.create_transfer(source_package, out / (kind + "-transfer"), write)
for kind in ("R", "O")}
for index, label in enumerate(check.PHASES):
folder = out / label
folder.mkdir()
pid = 100 + index
process = {"exit_code": 0, "helper_exit_code": 0, "timed_out": False, "error_lines": [],
"lifecycle_error": None, "external_process_or_group_signals": 0,
"owned_popen_ended": True, "old_helper_engine_ended": True,
"start_receipt_written": True, "end_receipt_written": True}
capture = {"passed": True, "all_captured_ended": True, "actual_captured_pids": [pid],
"outer_cleanup_errors": [], "adapter_exception": None, "foreign_process_or_group_signals": 0,
"all_cleanup_before_outer_receipt": True, "outer_receipt_written": True,
"outer_receipt_error": None, "cleanup": []}
write(folder / "outer-owned-finally.json", {k: v for k, v in capture.items() if k not in
("passed", "outer_receipt_written", "outer_receipt_error")})
for filename, key in (("started.json", "actual_start_binding"), ("ended.json", "actual_end_binding")):
binding = {"pid": pid, "actual_pid": pid, "owner_pid": 99,
"argv": ["fake", "--check-only"], "command": ["fake", "--check-only"]}
write(folder / filename, binding)
process[key] = binding
process["adapter_owned_cleanup"] = {"engine_ended": True, "errors": []}
write(folder / "adapter-owned-cleanup.json", process["adapter_owned_cleanup"])
process.update(pid=pid, argv=["fake", "--check-only"])
raw = ""
row = {"phase": label, "passed": True, "process": process, "capture": capture,
"timeout_seconds": 1800, "diagnostics": [], "argv": ["fake", "--check-only"],
"stage_before": HASH, "stage_after": HASH, "stage_preserved": True,
"source_preserved": True, "player_preserved": True}
startup = out / (label + "-startup")
startup.write_bytes(DATA)
row["startup_project"] = {"fresh_before": True, "path": str(startup), "sha256": HASH}
if index >= 3:
observed = report(label, pid)
if label.endswith("reader"):
observed["transfer_manifest_sha256"] = check.sha(out / (label[0] + "-transfer/manifest.json"))
public, sidecar = evidence(observed)
row["report"] = public
raw = "P28_RESTART_REPORT=" + json.dumps(public) + "\nP28_RESTART_AUDIO_CLOSE=" + json.dumps(audio(pid)) + "\n"
profile = str(out / (label + "-private"))
row.update(runtime_profile=profile, runtime_name=label)
profiles[profile] = {}
for kind in (("good",) if label.endswith("writer") else ("good", "tampered")):
for name, value in transfers[label[0]]["files"][kind].items():
profiles[profile]["p28_restart/" + kind + "/" + name] = value
guard = {"verified": True, "conditions": [True] * 5, "conditions_checked": 5,
"actual_user_data_dir": profile, "expected_user_data_dir": profile,
"globalized_probe": str(Path(profile) / "guard-probe"), "custom_user_dir_name": label,
"fresh_before_parent_initialize": True, "profile_writes_before_guard": 0,
"project_settings_persisted": False}
guard_path = out / (label + "-guard.json")
write(guard_path, guard)
row.update(guard=guard, guard_sha256=check.sha(guard_path))
states = out / (label + "-states")
states.mkdir()
sidecar_path = Path(profile) / check.SIDECAR
sidecar_path.parent.mkdir(parents=True)
write(sidecar_path, sidecar)
(states / "report_full.json").write_bytes(sidecar_path.read_bytes())
row["sidecar"] = {"path": check.SIDECAR, **check.pin(sidecar_path)}
profiles[profile][check.SIDECAR] = check.pin(sidecar_path)
for name in observed["states"]:
(states / (name + ".bin")).write_bytes(DATA)
for name, content in (("stdout.log", raw), ("stderr.log", ""), ("engine-native.log", "native\n")):
(folder / name).write_text(content)
row["raw"] = {n: check.pin(folder / n) for n in ("stdout.log", "stderr.log", "engine-native.log")}
process.update(stdout_sha256=row["raw"]["stdout.log"]["sha256"],
stderr_sha256=row["raw"]["stderr.log"]["sha256"])
write(folder / "process.json", process)
row["owned_files"] = {n: check.pin(folder / n) for n in
("process.json", "started.json", "ended.json", "adapter-owned-cleanup.json", "outer-owned-finally.json")}
rows.append(row)
probe = out / "restart_probe.gd"
probe.write_bytes((check.HERE / probe.name).read_bytes())
source = {str(i): {"bytes": 1, "sha256": HASH} for i in range(1407)}
worker = {n: check.sha(check.HERE / n) for n in
("restart_pair.py", "restart_probe.gd", "check_restart.py", "test_restart.py")}
return {"passed": True, "error": None, "cleanup_errors": [], "phases": rows,
"source_before": source, "source_after": copy.deepcopy(source),
"default_player_before": {}, "default_player_after": {},
"dependencies_before": check.DEPENDENCIES.copy(), "dependencies_after": check.DEPENDENCIES.copy(),
"collector_before": driver.COLLECTOR_PINS.copy(), "collector_after": driver.COLLECTOR_PINS.copy(),
"worker_before": worker, "worker_after": worker.copy(), "profiles": profiles,
"cross_cutting": copy.deepcopy(check.CROSS), "original_credit": 0,
"windows_verified": False, "operations_200_guests_verified": False,
"coverage": check.coverage([report("R-writer"), report("O-writer")]),
"script_pins": {str(probe): check.sha(probe)}, "owned_writes": [],
"cleanup": [{"pid": 100 + n, "engine_ended": True, "outer_cleanup_errors": [],
"foreign_process_or_group_signals": 0} for n in range(7)]}
class RestartTests(unittest.TestCase):
@staticmethod
def here_inventory():
return {str(path.relative_to(check.HERE)): hashlib.sha256(path.read_bytes()).hexdigest()
for path in check.HERE.rglob("*") if path.is_file()}
@classmethod
def setUpClass(cls):
cls.inventory_before = cls.here_inventory()
def setUp(self):
# Check after every test, including failures, independently of test order.
self.addCleanup(lambda: self.assertEqual(self.here_inventory(), self.inventory_before))
def test_zz_here_inventory_unchanged(self):
# unittest's default ordering places this after all twelve existing tests.
self.assertIn("test_restart.py", self.inventory_before)
self.assertEqual(self.here_inventory(), self.inventory_before)
def actual_canonical_sidecar(self):
relative = Path("native-e524ff2-canonical-failure-r01/report_full.json")
roots = [check.ROOT / "build",
check.ROOT.parent / ".runtime" / "P28-01-RESTART" / "build"]
if os.environ.get("BUILD_OUTPUT_DIR"):
roots.insert(0, Path(os.environ["BUILD_OUTPUT_DIR"]))
path = next((root / relative for root in roots if (root / relative).is_file()), None)
self.assertIsNotNone(path, "required retained native-e524ff2 sidecar is missing")
raw = path.read_bytes()
self.addCleanup(lambda: self.assertEqual(path.read_bytes(), raw))
return json.loads(raw)
def test_z1_actual_text_key_order_hash(self):
sidecar = self.actual_canonical_sidecar()
events = sidecar["at_390_event_verbatim"]
self.assertEqual(len(events), 16)
first = events[0]
self.assertEqual(first["event_id"], "domain_event.000000000009")
self.assertEqual(first["absolute_minute"], 362)
self.assertEqual(first["payload"],
{"old_state": 1, "reason": "ENTRY_COMPLETED", "state": 2})
self.assertEqual(check.json_sha(first),
"9ca80bec0c605ecd288f7671952d30fe66c67f291c5a618ea54623f07394edb9")
for key in ("raw_event_sha256", "canonical_sha256"):
self.assertEqual(sidecar["report"]["at_390"]["events"][0][key],
"f28afa0899d7efea59ab99ae06276ba354779a73cac705fa4801162f27c592d7")
with self.assertRaisesRegex(ValueError, "at390 raw/canonical SHA"):
check.check_sidecar(check.redact_report(sidecar["report"]), sidecar)
def test_z1_all_actual_event_bindings(self):
original = self.actual_canonical_sidecar()
sidecar = copy.deepcopy(original)
full = sidecar["report"]
self.assertEqual(len(sidecar["at_390_event_verbatim"]), 16)
self.assertEqual(len(full["at_390"]["events"]), 16)
for event, summary in zip(sidecar["at_390_event_verbatim"], full["at_390"]["events"]):
summary["raw_event_sha256"] = check.json_sha(event)
summary["canonical_sha256"] = check.json_sha(
check.canonical_event(event, full["event_id"]))
self.assertEqual(sidecar["at_390_event_verbatim"], original["at_390_event_verbatim"])
self.assertEqual(check.check_sidecar(check.redact_report(full), sidecar), full)
for index in range(16):
with self.subTest(index=index):
changed = copy.deepcopy(sidecar)
changed["report"]["at_390"]["events"][index]["raw_event_sha256"] = "0" * 64
with self.assertRaisesRegex(ValueError, "at390 raw/canonical SHA"):
check.check_sidecar(check.redact_report(changed["report"]), changed)
def test_z2_collision_rejected(self):
for ambiguous in ({1: "numeric", "1": "text"},
{"nested": [{1: "numeric", "1": "text"}]}):
with self.subTest(value=ambiguous), self.assertRaisesRegex(
ValueError, "canonical_key_collision"):
check.json_sha(ambiguous)
full = report()
full["stop_reason"] = "canonical_key_collision"
public, sidecar = evidence(full)
with self.assertRaisesRegex(ValueError, "canonical_key_collision"):
check.check_report(public, sidecar)
public["stop_reason"] = "complete"
with self.assertRaises(ValueError):
check.check_report(public, sidecar)
def rejects(self, original, mutations, validator):
for name, mutation in mutations.items():
with self.subTest(rejection=name):
value = copy.deepcopy(original)
mutation(value)
with self.assertRaises((ValueError, KeyError, TypeError)):
validator(value)
def test_rs1_signal_bool_void(self):
for kind in ("save", "load", "tamper"):
check.check_io(io(kind), kind)
self.rejects(io("save"), {
"true only": lambda x: x.pop("signal_count"),
"no signal": lambda x: x.update(signal_count=0),
"duplicate signal": lambda x: x.update(signal_count=2),
"bool differs": lambda x: x.update(return_value=False),
"latest differs": lambda x: x["latest"].update(code="FAILED"),
"payload typed mismatch": lambda x: x.update(payload_bytes_equal=False),
"state mismatch": lambda x: x["comparison"].update(equal=False),
}, lambda x: check.check_io(x, "save"))
self.rejects(io("load"), {
"void success": lambda x: x.update(return_value=True),
"void coerced bool": lambda x: x.update(return_kind="bool"),
"missing signal": lambda x: x.update(signal_count=0),
}, lambda x: check.check_io(x, "load"))
def test_rs2_exact_event_transform(self):
for kind in ("save", "load", "tamper"):
for count in (0, 255, 256):
check.check_io(io(kind, count=count), kind)
self.rejects(io(kind), {
"two events": lambda x: x["after"]["recent_events"].append(copy.deepcopy(x["event"])),
"different E": lambda x: x["event"].update(event_id="domain_event.000009999999"),
"counter": lambda x: x["after"].update(counter=x["before"]["counter"] + 2),
"missing ID": lambda x: x["after"]["published_ids"].pop(0),
"duplicate ID": lambda x: x["after"]["published_ids"].append(x["event"]["event_id"]),
"unsorted IDs": lambda x: x["after"]["published_ids"].reverse(),
"drop tail": lambda x: x["after"].update(recent_events=x["before"]["recent_events"][:-1] + [x["event"]]),
"wrong dropped record": lambda x: x.update(dropped=x["before"]["recent_events"][-1]),
"excluded path": lambda x: x["comparison"].update(excluded_paths=["systems.runtime.economy"]),
"diff hidden": lambda x: x["comparison"].update(diff_paths=["$.clock"]),
"digest only": lambda x: x["comparison"].update(method="SimulationDigest"),
"bytes SHA disagreement": lambda x: x["comparison"].update(actual_sha256="f" * 64),
}, lambda x: check.check_io(x, kind))
def test_clarification01_tamper(self):
self.rejects(io("tamper"), {
"failure event ignored": lambda x: x.update(after=x["before"]),
"failure ok": lambda x: x["signal_payload"].update(ok=True),
"failure OK code": lambda x: x["signal_payload"].update(code="OK"),
"not restored": lambda x: x["failure"].update(preload_pause_restored=False),
"paused differs": lambda x: x.update(paused_after=False),
"loaded pause differs": lambda x: x["failure"].update(loaded_clock_paused=False),
"restore committed": lambda x: x["failure"]["recovery_report"].update(restore_committed=True),
"migration unrecorded": lambda x: x["failure"].pop("migration_attempted"),
}, lambda x: check.check_io(x, "tamper"))
self.rejects(report("R-reader"), {
"failed event retained": lambda x: x.update(failure_event_absent=False),
"backlog consumed": lambda x: x["paused_idle"]["after"].update(backlog=120),
"reader not paused": lambda x: x["io"][1].update(paused_after=False),
}, validate_report)
def test_rs3_actual_k_full_typed_cross_pid(self):
writer, reader = report(), report("R-reader", 101)
validate_pair(writer, reader)
self.rejects(reader, {
"K call count": lambda x: x["minutes"][0].update(after=x["saved_minute"]),
"different K": lambda x: x.update(actual_k=29),
"missing minute": lambda x: x["minutes"].pop(),
"partial digest": lambda x: x["minutes"][0].update(scope="SimulationDigest"),
"minute SHA": lambda x: x["minutes"][0].update(sha256="f" * 64),
"wrong replacement": lambda x: x["minutes"][0]["replacement"].update(event_id="other"),
"two replacements": lambda x: x["minutes"][0].update(replacement_count=2),
"after window": lambda x: x["minutes"][6].update(replacement=x["io"][-1]["event"], replacement_count=1),
"excluded path": lambda x: x["minutes"][0].update(excluded_paths=["clock"]),
"same PID": lambda x: x.update(pid=100),
}, lambda x: validate_pair(writer, x))
def test_rs4_rs5_arrival_boundary(self):
writer, reader = report("O-writer"), report("O-reader", 101)
validate_pair(writer, reader)
self.rejects(writer, {
"boundary only": lambda x: x["boundary"].update(guest_auto_count=0),
"null arrival": lambda x: x.update(boundary=None),
"unprocessed": lambda x: x["boundary"].update(processed_arrival_minutes=[]),
"not first tick": lambda x: x["ui_ticks"].insert(0, copy.deepcopy(x["boundary"])),
"duplicate guest": lambda x: x["boundary"]["guest_auto_ids"].append("guest-auto-00000001"),
"next missing": lambda x: x["next_boundary"].update(processed_once=False),
"next duplicate": lambda x: x["next_boundary"]["after"].append(420),
"cap exceeded": lambda x: x.update(start_minute=200),
}, validate_report)
def test_d1_import_closure(self):
check.check_dependencies()
check.check_modules()
for name in ("restart_pair.py", "check_restart.py", "test_restart.py"):
check.check_imports((check.HERE / name).read_text())
for text in ("import forbidden_project_module", "from tools.strict_test_markers import main",
"importlib.util.spec_from_file_location('x', 'tools/evil.py')",
"__import__('tools.evil')", "exec('import tools.evil')"):
with self.subTest(text=text), self.assertRaises(ValueError):
check.check_imports(text)
with self.assertRaises(ValueError):
check.check_modules({"bad": SimpleNamespace(__file__=str(check.ROOT / "tools/evil.py"))})
for path in check.DEPENDENCIES:
original = check.sha
with self.subTest(pin=path), patch.object(check, "sha", side_effect=lambda p:
"0" * 64 if Path(p) == check.ROOT / path else original(p)), self.assertRaises(ValueError):
check.check_dependencies()
def test_d2_order_and_check_plan(self):
collector, _, _ = driver.load_dependencies()
commands = driver.plan(collector, Path("/engine"), Path("/out"))
self.assertEqual(len(commands), 7)
self.assertIn("--import", commands[0])
self.assertIn("--check-only", commands[1])
self.assertIn("--check-only", commands[2])
rows = []
for _, label in driver.schedule(rows):
rows.append({"phase": label, "passed": True, "report": {"stop_reason": "complete"}})
self.assertEqual([r["phase"] for r in rows], check.PHASES)
rows = []
iterator = driver.schedule(rows)
for _ in range(4):
_, label = next(iterator)
rows.append({"phase": label, "passed": True, "report": {"stop_reason": "complete"}})
rows[-1]["passed"] = False
with self.assertRaises(ValueError):
next(iterator)
rows[-1]["passed"] = True
rows[-1]["report"]["stop_reason"] = "failed"
iterator = driver.schedule([])
next(iterator)
with self.assertRaises(ValueError):
next(iterator)
def test_d3_transfer_and_fresh_profiles(self):
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
base = Path(temporary)
source = base / "source"
source.mkdir()
(source / "world.bin").write_bytes(b"0123456789")
(source / "manifest.json").write_text("{}")
target = base / "transfer"
manifest = driver.create_transfer(source, target, write)
driver.check_transfer(target, manifest)
self.assertEqual((target / "tampered/world.bin").read_bytes(), b"0123446789")
driver.fresh_profile(base / "new-profile")
with self.assertRaises(ValueError):
driver.fresh_profile(source)
self.rejects(manifest, {
"SHA": lambda x: x["files"]["good"]["world.bin"].update(sha256="f" * 64),
"offset": lambda x: x["tamper"].update(offset=0),
"xor": lambda x: x["tamper"].update(xor=2),
}, lambda x: driver.check_transfer(target, x))
(target / "tampered/manifest.json").write_text("changed")
with self.assertRaises(ValueError):
driver.check_transfer(target, manifest)
def test_d4_d5_d7_probe_static(self):
text = (check.HERE / "restart_probe.gd").read_text()
check.check_probe(text)
snippets = ["GameClock.advance_minutes(1)", "GameClock.set_paused(false)",
"x.clear()", "spawn_guest()", "SimulationRuntime.new()", "initialize()",
"enable_production_checkpoint()", "main._toggle_pause()", "GameClock.set_paused(true)",
"var elapsed_us = 1", "Time.get_ticks_usec()"]
for snippet in snippets:
with self.subTest(snippet=snippet), self.assertRaises(ValueError):
check.check_probe(text + "\nfunc bad():\n\t" + snippet + "\n")
for replacement in ("GameClock.advance_minutes(2)", "Time.get_ticks_usec()",
"GameClock.advance_one_minute()"):
with self.subTest(step=replacement), self.assertRaises(ValueError):
check.check_probe(text.replace("GameClock.advance_minutes(1)", replacement))
def test_y2_direct_variant_inference_guard(self):
text = (check.HERE / "restart_probe.gd").read_text()
check.check_probe(text)
snippets = [
"var x := GameClock.get_backlog_minutes()",
'var y := field(d,"k")',
"var x := runtime.create_snapshot()",
"var x := main",
"var x := other_variant.value",
"var x := other_field(d)",
]
declarations = "\nvar other_variant: Variant\nfunc other_field(d) -> Variant:\n\treturn d\n"
for snippet in snippets:
with self.subTest(snippet=snippet), self.assertRaisesRegex(ValueError, "direct Variant inference"):
check.check_probe(text + declarations + "\nfunc bad():\n\t" + snippet + "\n")
for snippet in (
"var x: int = GameClock.get_backlog_minutes()",
'var y: Variant = field(d,"k")',
"var x := 1",
"var x := witness(d)",
"var x := GameClock_extra.get_backlog_minutes()",
):
with self.subTest(allowed=snippet):
check.check_probe(text + "\nfunc allowed():\n\t" + snippet + "\n")
def test_rs7_rs8_full_receipt_rejections(self):
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
out = Path(temporary)
receipt = synthetic_receipt(out)
check.check_receipt(receipt, out)
self.rejects(receipt, {
"source map": lambda x: x["source_after"].pop("0"),
"ordinary player": lambda x: x["default_player_after"].update(changed=True),
"guard": lambda x: x["phases"][3]["guard"].update(profile_writes_before_guard=1),
"raw SHA": lambda x: x["phases"][3]["raw"]["stdout.log"].update(sha256="f" * 64),
"PID": lambda x: x["phases"][3]["capture"].update(actual_captured_pids=[999]),
"owned write": lambda x: x["owned_writes"].append("R-writer/report.json"),
"cleanup": lambda x: x["cleanup"][0].update(engine_ended=False),
"stage": lambda x: x["phases"][1].update(stage_after="f" * 64),
"collector": lambda x: x["collector_after"].pop("measure_p28_01.gd"),
"dependency": lambda x: x["dependencies_after"].update({"tools/run_all_tests.py": "f" * 64}),
"cross-cutting": lambda x: x["cross_cutting"].pop(),
"source count": lambda x: (x["source_after"].pop("1"), x["source_before"].pop("1")),
"phase order": lambda x: x["phases"].reverse(),
"foreign signal": lambda x: x["phases"][0]["capture"].update(foreign_process_or_group_signals=1),
}, lambda x: check.check_receipt(x, out))
(out / "R-reader-states/B.bin").write_bytes(b"changed")
with self.assertRaises(ValueError):
check.check_receipt(receipt, out)
def test_d6_raw_report_and_audio(self):
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
out = Path(temporary)
receipt = synthetic_receipt(out)
row = receipt["phases"][3]
folder = out / "R-writer"
original = (folder / "stdout.log").read_text()
for text in ("", original + original, original.split("P28_RESTART_AUDIO_CLOSE=")[0],
original.replace('"owned_engine_pid": 103', '"owned_engine_pid": 999')):
(folder / "stdout.log").write_text(text)
row["raw"]["stdout.log"] = check.pin(folder / "stdout.log")
with self.assertRaises(ValueError):
check.bound_raw(folder, row)
def test_d2_d6_real_owned_outer_fake_child(self):
collector, _, outer = driver.load_dependencies()
child = (
"import os,sys,json,time,pathlib\n"
"mode=sys.argv[1]\n"
"identity={'pid':os.getpid(),'ppid':os.getppid(),'pgid':os.getpgrp(),"
"'args':' '.join([sys.executable]+sys.argv)}\n"
"path=pathlib.Path(sys.argv[0]).parent/(mode+'-identity')\n"
"tmp=path.with_suffix('.tmp'); tmp.write_text(json.dumps(identity)); tmp.replace(path)\n"
"pathlib.Path(sys.argv[sys.argv.index('--log-file')+1]).write_text('native raw\\n')\n"
"print('Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org',flush=True)\n"
"time.sleep(0.15)\n"
"if mode=='timeout': time.sleep(5)\n"
"sys.exit(3 if mode=='exit' else 0)\n")
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
base = Path(temporary)
script = base / "fake-child"
script.write_text(child)
def diagnostic(command, folder, timeout, env, **kwargs):
def probe(pid):
path = base / (command[2] + "-identity")
deadline = time.monotonic() + 2
while time.monotonic() < deadline:
if path.exists():
identity = json.loads(path.read_text())
if identity["pid"] == pid:
return identity
time.sleep(.005)
raise RuntimeError("fake child identity unavailable")
return outer.native.run_owned_diagnostic(command, folder, timeout, env, probe_fn=probe, **kwargs)
for mode in ("ok", "exit", "timeout"):
folder = base / mode
def run_phase(command, destination, limit, env, **kwargs):
self.assertEqual(limit, 1800)
return outer.run_phase(command, destination, .3 if mode == "timeout" else 5,
env, diagnostic_fn=diagnostic, **kwargs)
def guarded_write(path, value):
self.assertFalse(Path(path).is_relative_to(folder), "driver writes owned folder")
write(path, value)
def real_phase(*args, **kwargs):
kwargs["dump_fn"] = write
return run_phase(*args, **kwargs)
with patch.object(collector, "live_engines", return_value=[]), \
patch.object(collector, "write", side_effect=guarded_write):
row = collector.run_engine(SimpleNamespace(run_phase=real_phase),
[sys.executable, str(script), mode], folder, {})
row["phase"] = "import"
self.assertEqual(row["passed"], mode == "ok", row)
self.assertTrue(row["capture"]["all_captured_ended"])
if mode == "ok":
check.bound_raw(folder, row)
else:
with self.assertRaises(ValueError):
check.bound_raw(folder, row)
_, errors = outer.finish_captured(outer.OWNED)
self.assertEqual(errors, [])
def test_v1_at390_required_and_pair_consistency(self):
writer, reader = report("O-writer"), report("O-reader", 101)
validate_pair(writer, reader)
self.rejects(writer, {
"absent": lambda x: x.pop("at_390"),
"null": lambda x: x.update(at_390=None),
"not reached": lambda x: x.update(stop_reason="at_390_not_reached"),
"clock": lambda x: x["at_390"]["clock"].update(absolute_minute=391),
"counter type": lambda x: x["at_390"].update(domain_event_counter="300"),
"row differs": lambda x: x["minutes"][28]["operations_observation"].update(guest_auto_count=2),
}, validate_report)
for mutate in (lambda x: x.pop("at_390"), lambda x: x.update(at_390=None)):
w, r = copy.deepcopy(writer), copy.deepcopy(reader)
mutate(w)
mutate(r)
with self.assertRaises((ValueError, KeyError)):
validate_pair(w, r)
different = copy.deepcopy(reader)
different["at_390"]["operations"]["population"] = 3
different["minutes"][28]["operations_observation"]["operations"]["population"] = 3
validate_report(different)
with self.assertRaises(ValueError):
validate_pair(writer, different)
with self.assertRaises((ValueError, KeyError)):
validate_pair(writer, {**reader, "at_390": None})
def test_v2_all_seven_families_restore_verbatim(self):
full = report()
# T4 and T6 are conditional: an earlier SAVE event is the dropped head.
old = io("save", minute=600, count=0)["event"]
row = full["io"][0]
row["before"]["recent_events"][0] = old
row["dropped"] = copy.deepcopy(old)
row["after"] = check.transform(row["before"], row["event"])
public, sidecar = evidence(full)
check.check_report(public, sidecar)
paths = check.payload_paths(public)
for path in ("/report/io/0/signal_payload", "/report/io/0/latest",
"/report/io/0/event/payload", "/report/io/0/before/recent_events/0/payload",
"/report/io/0/after/recent_events/255/payload", "/report/io/0/dropped/payload",
"/report/minutes/0/replacement/payload"):
self.assertEqual(paths[path]["timing_redactions"], [
{"original_key": key, "sidecar_ref": path + "/" + key} for key in check.TIMINGS])
self.assertNotIn("duration_us", paths[path])
self.assertEqual(public["io"][0]["after"]["recent_events"][0],
full["io"][0]["after"]["recent_events"][0])
self.assertEqual(check.check_sidecar(public, sidecar), full)
for kind in ("save", "load", "tamper"):
full_row = io(kind)
check.check_io(full_row, kind)
self.rejects(sidecar, {
"root extra": lambda x: x.update(extra={}),
"performance use": lambda x: x["report"].update(statistics={"average": 1}),
"outside closure": lambda x: x["report"].update(elapsed_ms=1),
"nested timing": lambda x: x["report"]["io"][0]["event"]["payload"].update(nested={"latency_us": 1}),
"missing timing": lambda x: x["report"]["io"][0]["latest"].pop("duration_us"),
"tamper value": lambda x: x["report"]["io"][0]["latest"].update(code="CHANGED"),
"nonSAVE": lambda x: x["report"]["io"][0]["before"]["recent_events"][0].update(event_type="OLD"),
"wrong service": lambda x: x["report"]["io"][0]["before"]["recent_events"][0].update(source_service="other"),
}, lambda x: check.check_sidecar(public, x))
self.rejects(public, {
"leaked key": lambda x: x["io"][0]["signal_payload"].update(duration_us=124),
"hidden payload leak": lambda x: x.update(payload={"hidden_ms": 1}),
"extra marker": lambda x: x["io"][0]["latest"]["timing_redactions"].append(
{"original_key": "other", "sidecar_ref": "/report/other"}),
"missing marker": lambda x: x["io"][0]["latest"].pop("timing_redactions"),
"one marker": lambda x: x["io"][0]["latest"]["timing_redactions"].pop(),
"wrong pointer": lambda x: x["io"][0]["latest"]["timing_redactions"][0].update(
sidecar_ref="/report/io/0/signal_payload/duration_us"),
"unresolved pointer": lambda x: x["io"][0]["latest"]["timing_redactions"][0].update(
sidecar_ref="/report/io/999/latest/duration_us"),
"extra marker field": lambda x: x["io"][0]["latest"]["timing_redactions"][0].update(extra=1),
"nonSAVE marker": lambda x: x["io"][0]["after"]["recent_events"][0]["payload"].update(
timing_redactions=copy.deepcopy(x["io"][0]["latest"]["timing_redactions"])),
"restore differs": lambda x: x.update(pid=999),
}, lambda x: check.check_sidecar(x, sidecar))
with self.assertRaises(ValueError):
check.check_report(public)
# The raw equality check must see differences hidden by public redaction.
tampered = copy.deepcopy(sidecar)
tampered["report"]["io"][0]["latest"]["duration_us"] += 1
self.assertEqual(check.redact_report(tampered["report"]), public)
with self.assertRaises(ValueError):
check.check_report(public, tampered)
def test_v2_at390_full_array_binding(self):
full = report("O-writer")
events = [
{"event_id": "domain_event.%012d" % n, "event_type": "ARRIVAL",
"absolute_minute": 380 + i, "source_service": "operations", "payload": {"count": i + 1}}
for i, n in enumerate((250, 251))]
full["at_390"]["events"] = [summarize(e, full["event_id"]) for e in events]
public, sidecar = evidence(full, events)
check.check_report(public, sidecar)
self.rejects(sidecar, {
"missing array": lambda x: x.pop("at_390_event_verbatim"),
"missing entry": lambda x: x["at_390_event_verbatim"].pop(),
"extra entry": lambda x: x["at_390_event_verbatim"].append(copy.deepcopy(events[0])),
"reordered": lambda x: x["at_390_event_verbatim"].reverse(),
"raw differs": lambda x: x["at_390_event_verbatim"][0]["payload"].update(count=7),
"nonSAVE timing": lambda x: x["at_390_event_verbatim"][0]["payload"].update(duration_us=1),
}, lambda x: check.check_sidecar(public, x))
for field in ("raw_event_sha256", "canonical_sha256"):
changed = copy.deepcopy(full)
changed["at_390"]["events"][0][field] = "f" * 64
pub, sc = evidence(changed, events)
with self.assertRaises(ValueError):
check.check_sidecar(pub, sc)
changed = copy.deepcopy(full)
changed["at_390"]["events"][0]["canonical_sha256"] = check.json_sha(
{"event_id": events[0]["event_id"], "replaced_for_cross_pid_compare": True})
pub, sc = evidence(changed, events)
with self.assertRaises(ValueError):
check.check_sidecar(pub, sc)
# D5 operates on an entire E element, including type and timing differences.
# This exercises the binding independently of the strict > saved_minute filter.
canonical_observations = []
raw_shas = []
for kind in ("save", "load"):
raw_event = io(kind, 361)["event"]
raw_event["payload"]["duration_us"] += 1 if kind == "load" else 0
value = copy.deepcopy(full)
value["at_390"]["events"] = [summarize(raw_event, value["event_id"])]
pub, sc = evidence(value, [raw_event])
check.check_sidecar(pub, sc)
canonical_observations.append(check.canonical_observation(value["at_390"], value["event_id"]))
raw_shas.append(value["at_390"]["events"][0]["raw_event_sha256"])
with self.assertRaises(ValueError):
check.check_report(pub, sc) # E at saved_minute is outside this observation's window.
self.assertNotEqual(raw_shas[0], raw_shas[1])
self.assertEqual(*canonical_observations)
# All other event fields and canonical hashes remain significant cross PID.
reader = report("O-reader", 101)
reader["at_390"]["events"] = copy.deepcopy(full["at_390"]["events"])
rp, rs = evidence(reader, events)
check.check_pair(public, rp, sidecar, rs)
changed_events = copy.deepcopy(events)
changed_events[0]["payload"]["count"] = 9
reader["at_390"]["events"] = [summarize(e, reader["event_id"]) for e in changed_events]
rp, rs = evidence(reader, changed_events)
check.check_report(rp, rs)
with self.assertRaises(ValueError):
check.check_pair(public, rp, sidecar, rs)
def test_v2_receipt_sidecar_binding_rejections(self):
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
out = Path(temporary)
receipt = synthetic_receipt(out)
check.check_receipt(receipt, out)
self.rejects(receipt, {
"unbound": lambda x: x["phases"][3].pop("sidecar"),
"wrong SHA": lambda x: x["phases"][3]["sidecar"].update(sha256="f" * 64),
"missing map": lambda x: x["profiles"][x["phases"][3]["runtime_profile"]].pop(check.SIDECAR),
"wrong path": lambda x: x["phases"][3]["sidecar"].update(path="other.json"),
"coverage omitted": lambda x: x.pop("coverage"),
"false coverage": lambda x: x["coverage"].update(overload_nonzero_backlog="exercised_recorded"),
"persistence claim": lambda x: x["coverage"].update(across_restart_backlog_persistence_claimed=True),
}, lambda x: check.check_receipt(x, out))
path = out / "R-writer-states/report_full.json"
saved = path.read_bytes()
path.write_bytes(b"{}")
with self.assertRaises(ValueError):
check.check_receipt(receipt, out)
path.unlink()
with self.assertRaises(ValueError):
check.check_receipt(receipt, out)
path.write_bytes(saved)
private = Path(receipt["phases"][3]["runtime_profile"]) / check.SIDECAR
private.write_bytes(b"{}")
with self.assertRaises(ValueError):
check.check_receipt(receipt, out)
def test_v3_overload_is_observation_not_persistence(self):
for count, backlog in ((0, 0), (0, 121), (1, 0), (1, 121)):
full = report()
full["overloads"] = [{"minute": 612, "backlog": backlog}] * count
full["paused_idle"]["before"]["backlog"] = backlog
full["paused_idle"]["after"]["backlog"] = backlog
full["overload_case"] = {"exercised": bool(count and backlog > 0),
"overloads": count, "backlog_at_save": backlog}
validate_report(full)
observed = check.coverage([full])
self.assertEqual(observed["overload_nonzero_backlog"],
"exercised_recorded" if count and backlog else "not_exercised")
self.assertFalse(observed["across_restart_backlog_persistence_claimed"])
self.rejects(full, {
"missing disclosure": lambda x: x.pop("overload_case"),
"wrong exercised": lambda x: x["overload_case"].update(exercised=not bool(count and backlog)),
"wrong count": lambda x: x["overload_case"].update(overloads=count + 1),
"wrong backlog": lambda x: x["overload_case"].update(backlog_at_save=backlog + 1),
"consumption": lambda x: x["paused_idle"]["after"].update(backlog=backlog + 1),
"persistence claim": lambda x: x.update(across_restart_backlog_persistence_claimed=True),
"nonzero claim": lambda x: x.update(nonzero_backlog_preserved=True),
}, validate_report)
writer, reader = report(), report("R-reader", 101)
reader["paused_idle"]["before"]["backlog"] = 0
reader["paused_idle"]["after"]["backlog"] = 0
for row in reader["minutes"]:
row.update(backlog_before=0, backlog_after=0)
validate_pair(writer, reader) # No across-restart accumulator persistence requirement.
def test_v4_no_arrival_is_diagnostic_failure(self):
full = report("O-writer")
full.update(boundary=None, boundary_reason="no_arrival_within_cap",
stop_reason="no_arrival_within_cap", next_boundary=None, io=[], minutes=[], actual_k=0)
full["ui_ticks"] = [{"clock": n, "guest_auto_ids": [], "guest_auto_count": 0}
for n in range(361, 481)]
self.assertTrue(check.check_no_arrival_diagnostic(full))
with self.assertRaisesRegex(ValueError, "incomplete probe"):
validate_report(full)
self.rejects(full, {
"missing reason": lambda x: x.pop("boundary_reason"),
"wrong reason": lambda x: x.update(boundary_reason="complete"),
"not null": lambda x: x.update(boundary={}),
"short cap": lambda x: x["ui_ticks"].pop(),
}, check.check_no_arrival_diagnostic)
with tempfile.TemporaryDirectory(dir=os.environ.get("BUILD_OUTPUT_DIR") or None) as temporary:
out = Path(temporary)
receipt = synthetic_receipt(out)
row = receipt["phases"][5]
full["pid"] = row["report"]["pid"]
public, sidecar = evidence(full)
row["report"] = public
text = "P28_RESTART_REPORT=" + json.dumps(public) + "\nP28_RESTART_AUDIO_CLOSE=" + json.dumps(audio(full["pid"])) + "\n"
(out / "O-writer/stdout.log").write_text(text)
row["raw"]["stdout.log"] = check.pin(out / "O-writer/stdout.log")
row["process"]["stdout_sha256"] = row["raw"]["stdout.log"]["sha256"]
(out / "O-writer/process.json").write_text(json.dumps(row["process"]))
row["owned_files"]["process.json"] = check.pin(out / "O-writer/process.json")
for path in (out / "O-writer-states/report_full.json",
Path(row["runtime_profile"]) / check.SIDECAR):
path.write_text(json.dumps(sidecar))
binding = check.pin(out / "O-writer-states/report_full.json")
row["sidecar"] = {"path": check.SIDECAR, **binding}
receipt["profiles"][row["runtime_profile"]][check.SIDECAR] = binding
with self.assertRaisesRegex(ValueError, "incomplete probe"):
check.check_receipt(receipt, out)
def test_v5_engine_elapsed_deadline(self):
for elapsed in (0, .25, 37, 1739.5):
full = report()
full["probe_deadline"].update(engine_elapsed_at_begin_seconds=elapsed, timer_seconds=1740-elapsed)
validate_report(full)
value = report()["probe_deadline"]
self.rejects(value, {
"old relative timer": lambda x: x.update(timer_seconds=1740),
"wrong limit": lambda x: x.update(limit_seconds_from_engine_start=1800),
"negative elapsed": lambda x: x.update(engine_elapsed_at_begin_seconds=-1, timer_seconds=1741),
"missing elapsed": lambda x: x.pop("engine_elapsed_at_begin_seconds"),
"expired": lambda x: x.update(engine_elapsed_at_begin_seconds=1740, timer_seconds=0),
"nonfinite": lambda x: x.update(engine_elapsed_at_begin_seconds=float("inf")),
}, check.check_deadline)
check.check_deadline({**value, "engine_elapsed_at_begin_seconds": 1750, "timer_seconds": -10}, complete=False)
text = (check.HERE / "restart_probe.gd").read_text()
for altered in (text + "\nfunc forbidden():\n\tTime.get_ticks_msec()\n",
text.replace("deadline_timer_seconds() ->", "other_watchdog() ->"),
text.replace("GameClock.advance_minutes(1)", "Time.get_ticks_msec()"),
text + "\nfunc forbidden():\n\tTime.get_unix_time_from_system()\n"):
with self.assertRaises(ValueError):
check.check_probe(altered)
if __name__ == "__main__":
unittest.main(verbosity=2)