diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR24_STATUS.md b/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR24_STATUS.md new file mode 100644 index 0000000..d70ba97 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR24_STATUS.md @@ -0,0 +1,77 @@ +# Repair24 — source-ready submission + +Bounded continuation of P04-01 request-repair24; tests NOT RUN. +Existing wrapper edits and the untracked identity fixture were read first and +preserved/corrected. Only this execution subtree was written. No Git, engine, +Runner, agent, commit or integration operation was performed. + +Changed source/runbook SHA256 (exact bytes): + +| File | SHA256 | +| --- | --- | +| s4/run_s4_native.py | dda495d33566eae14c8a707e77f8ec9dc6c7bd043076a091e90dd53f6a7490db | +| p04_native_series.py | 348197759c169c2094db3b1114ca3abe5525b8d4bc9aca611d4579871a130b40 | +| s4/engine_identity_negative_fixtures.py | f9148ef79cb62ec6631e7e3f23e1d3b062434f7152977aab3b9d18d82672255e | +| s4/S4_ROOT_RUN.md | c1a00e3dad8d91d28df1a7f868f6e4e905f1df721baac964865e341c84356135 | + +This new status document records the hashes above; its own hash must be taken +from the submitted checkout, outside its own contents. + +Wrapper pins changed: the own-B bare Godot copy is replaced with exactly +`/Applications/Godot.app/Contents/MacOS/Godot`, rejecting symlinks and any +different resolved path. Its constant SHA remains +`c7cccbf8fb143e34e02fd6521e09be2c2b974f0d5db080b19071c9c570718ccf`. +Engine identity no longer depends on an old cache runner-input. Fresh NO-CACHE +is the default at plan and native collection. Optional explicit cache mode +rejects failed receipts before reading their inputs or cache contents. +No default cache or cache PASS is required. No engine is copied, re-signed or +modified, and no codesign/xattr/security operation is added. + +Before-launch, during-collection and explicit after-cleanup re-pins retain the +full runtime descriptor (path/resolved path, bytes, SHA, device, inode, mode, +mtime and ctime). Runner-input and execution retain equal before/during/after +identity records and execution retains labeled observations. fixed_guard still +re-pins the engine. The verifier permits only this exact installed engine +outside B, reads/hashes it exactly and checks the recorded identities. +Fixed inputs and QA remain own-B only; actual command[0] must equal the pin. + +Defaults and Root staging are now: +`p04-s4-native-r24`, `p04-s4-plan-r24.json`, +`audit-support/p04-s4-source-r24`. Only RUNS S4 changes to r24. +C/S1-S3 bindings, other series and the frozen C block (20916) are unchanged. +Source1338, parse316, sole QA override, default-player protection, owned +four-distinct-PID capture, live-engine refusal, disk admission, fresh output, +cleanup-before-fixed-guard, formal Writer/Reader, NO_POWER, typed declarations, +forbidden mutations/bypasses and mana constants guards remain. + +Untouched checker: SHA256 +`a61c5b496e656f60c66898e42500bc9a2d45f947690ce8f5f19a03984ebbc850`, +78399 B. Untouched probe: SHA256 +`ceb592d853fd50063f20496c7b6df05257528dbe1c0d0d80bc6a8ccb1f9dd6d7`. +All 1338 game files are unchanged; no game source was written. No new claim of +executed 1338-file verification is made. + +The formal reviewer's five findings are carried forward unchanged, with no +closure claimed. Their individual review text was not supplied in this dispatch +or found in the local execution records searched; it is not reconstructed here. +Main 9b remains frozen at original 13/88. Support 53cb remains review pending. +D05 remains pending. No acceptance denominator, specification, main integration +or original completion state changes. + +r22 is an immutable failed proof and remains ineligible. Diagnostics: +`audit-support/p04-root-d393-s4-r01/ENGINE_STAGING_DIAGNOSTICS.json`. +Its pre-banner staged-copy failure is an environment/staging fault; no product +logic or probe/checker repair is claimed. Root uses the installed executable +directly and preserves r22. Do not rerun S1-S3, C or full178. + +Validation: static AST parsing and in-memory compile completed for the wrapper, +series verifier and identity fixture; no module was imported or executed. +Read-only SHA/byte inspection completed for the four listed files, checker and +probe. These are source checks only. Tests NOT RUN: identity fixtures, all other +fixtures/suites, check-only plan generation, native S4, full178, registered +validation and independent review. No unexecuted result is reported as passed. + +Registered validation stays exit 2 until Root generates the current +MANIFEST.json collection; the gate is not changed. This is the carried-forward +expected gate state, not a newly executed validation result. Root execution, +current exact-version evidence and formal independent review remain pending. diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/p04_native_series.py b/docs/plans/original-completion-2026-10-02/execution/p04-01/p04_native_series.py index f4f3017..8aa1aae 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p04-01/p04_native_series.py +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/p04_native_series.py @@ -17,7 +17,7 @@ MANIFEST_SHA256 = 'a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c MANIFEST_BYTES = 1244135 PRODUCT = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1' RUNS = {'s1': 'p04-s1-native-r02', 's2a': 'p04-s2a-native-r03', - 's2b': 'p04-s2b-native-r02', 's3': 'p04-s3-native-r01', 's4': 'p04-s4-native-r22'} + 's2b': 'p04-s2b-native-r02', 's3': 'p04-s3-native-r01', 's4': 'p04-s4-native-r24'} # Native descriptors pinned from literal files, never ROOT result passed fields. NATIVE_PINS = { 's1': ('1e26d9585396da9415747d87d77b70f23425a3ee0714e4fca114748f9479fd4e', '01372beb0ffec181c892d3b4e88bce32001e08fb2007938d7bf19135511a7acc', '0b6d11eb34d8af64b22cb806caeb06eed4ec521fa9ee24d1204ea185345e655c'), @@ -968,8 +968,33 @@ def power_stop(s): 'service_id': sid, 'transaction_id': paid[0]['transaction_id'], 'priority_approved': False} +S4_ENGINE_PATH = '/Applications/Godot.app/Contents/MacOS/Godot' +S4_ENGINE_SHA256 = 'c7cccbf8fb143e34e02fd6521e09be2c2b974f0d5db080b19071c9c570718ccf' + + +def verify_s4_engine(pin, identity): + require(pin['path'] == S4_ENGINE_PATH and pin['sha256'] == S4_ENGINE_SHA256, + 'S4 exact installed engine pin required') + path = ordinary(pin['path']) + require(str(path.resolve(strict=True)) == S4_ENGINE_PATH, 'S4 engine resolved path') + before = path.stat() + require(type(pin['bytes']) is int, 'S4 recorded engine bytes required') + checked(path.read_bytes(), pin, 'S4 installed engine') + after = path.stat() + fields = {'bytes': 'st_size', 'mtime_ns': 'st_mtime_ns', 'mode': 'st_mode', + 'device': 'st_dev', 'inode': 'st_ino', 'ctime_ns': 'st_ctime_ns'} + require(all(getattr(before, f) == getattr(after, f) for f in fields.values()), + 'S4 engine changed while reading') + ordinary(path) + require(pin['resolved_path'] == S4_ENGINE_PATH and + all(pin[k] == getattr(after, f) for k, f in fields.items()), 'S4 runtime engine descriptor') + require(set(identity) == {'before', 'during', 'after'} and identity['before'] == pin and + identity['after'] == pin and isinstance(identity['during'], list) and identity['during'] and + all(value == pin for value in identity['during']), 'S4 before/during/after engine identity') + + class S4Series(Series): - """Fresh S4: all verifier inputs live in own B; profile paths are provenance.""" + """Fresh S4: own-B materials and exact installed engine; profiles are provenance.""" def __init__(self, build): self.name, self.build, self.run = 's4', Path(build), RUNS['s4'] self.base = self.build / self.run @@ -993,10 +1018,16 @@ class S4Series(Series): require(inputs['QA_overrides'] == ['tests/s3/test_runtime_staff_assignment.gd'], 'S4 sole QA override') selected[inputs['QA_overrides'][0]] = digest(qa.read_bytes()) require(selected == inputs['selected_source_map'], 'S4 selected source map') - for pin in inputs['fixed_input_pins'] + [inputs['QA'], inputs['engine']]: + for pin in inputs['fixed_input_pins'] + [inputs['QA']]: path = Path(pin['path']) require(path.is_relative_to(self.build), 'S4 material outside own B') self.read_build(path.relative_to(self.build).as_posix(), pin) + verify_s4_engine(inputs['engine'], execution['engine_identity']) + require(inputs['engine_identity'] == execution['engine_identity'], 'S4 input/execution engine identity') + observations = execution['engine_observations'] + require(any(row['stage'] == 'after-cleanup' for row in observations) and + all(row.get('descriptor') == inputs['engine'] for row in observations), + 'S4 runtime engine observations') require(execution['error'] is None and execution['guard_errors'] == [] and execution['cleanup_errors'] == [] and [p['phase'] for p in execution['phases']] == ['import', 'parse', 'writer', 'reader'], 'S4 native phase/guard failure') for phase in execution['phases']: diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/S4_ROOT_RUN.md b/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/S4_ROOT_RUN.md index 93ea845..f55ab08 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/S4_ROOT_RUN.md +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/S4_ROOT_RUN.md @@ -6,26 +6,24 @@ source batch is auto-submitted. Do not rerun C/S1/S2a/S2b/S3. Do not run the ful product suite now. Preserve all existing raw and REPAIR17–21 history. From the clean auto-submitted checkout, stage these three exact reviewed files -in the fresh own-B source directory. Copy the installed engine executable there as an independently pinned native input. This staging is a Root action, not a worker -execution. The wrapper refuses QA outside own B. All input/QA/source footprints -below are within the registered B; external manifest paths are lookup keys and +in the fresh own-B source directory. Run the installed executable directly; do not stage or copy it. This staging is a Root action, not a worker +execution. The wrapper refuses QA outside own B. QA and fixed inputs stay within registered B; only the exact installed engine is external; external manifest paths are lookup keys and provenance only. Never open their original production locations. ```sh export B=/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build export E=docs/plans/original-completion-2026-10-02/execution/p04-01 export PYTHONDONTWRITEBYTECODE=1 -mkdir "$B/audit-support/p04-s4-source-r23" -cp "$E/s4/run_s4_native.py" "$E/s4/p04_s4_power_probe.gd" "$E/s4/S4_ROOT_RUN.md" "$B/audit-support/p04-s4-source-r23/" -cp /Applications/Godot.app/Contents/MacOS/Godot "$B/audit-support/p04-s4-source-r23/Godot" -python3 "$B/audit-support/p04-s4-source-r23/run_s4_native.py" \ +mkdir "$B/audit-support/p04-s4-source-r24" +cp "$E/s4/run_s4_native.py" "$E/s4/p04_s4_power_probe.gd" "$E/s4/S4_ROOT_RUN.md" "$B/audit-support/p04-s4-source-r24/" +python3 "$B/audit-support/p04-s4-source-r24/run_s4_native.py" \ --project-root "$B/audit-support/p04-r17-full-inputs-r01/product" \ - --output "$B/p04-s4-native-r22" --plan "$B/p04-s4-plan-r23.json" \ - --godot "$B/audit-support/p04-s4-source-r23/Godot" --check-only -python3 "$B/audit-support/p04-s4-source-r23/run_s4_native.py" \ + --output "$B/p04-s4-native-r24" --plan "$B/p04-s4-plan-r24.json" \ + --godot /Applications/Godot.app/Contents/MacOS/Godot --check-only +python3 "$B/audit-support/p04-s4-source-r24/run_s4_native.py" \ --project-root "$B/audit-support/p04-r17-full-inputs-r01/product" \ - --output "$B/p04-s4-native-r22" --plan "$B/p04-s4-plan-r23.json" \ - --godot "$B/audit-support/p04-s4-source-r23/Godot" + --output "$B/p04-s4-native-r24" --plan "$B/p04-s4-plan-r24.json" \ + --godot /Applications/Godot.app/Contents/MacOS/Godot ``` The first invocation only prepares the pinned plan: zero engine launches. The @@ -39,20 +37,18 @@ inputs. Reader uses only the existing IO1 formal package mapping. Exact input footprints: -- Current S4 wrapper SHA256: - `6d5f4e05e87607413bfb5498dc9c9e17c2bfd96bf751c9e645050ca6f8e69d5c`. - The plan pins these exact bytes; `p04_native_series.py` checks the wrapper - against the current source file dynamically. Historical r22 receipts remain - unchanged and do not describe this r23 wrapper. +- Current wrapper SHA256 is recorded in `../REPAIR24_STATUS.md`. The plan pins + its exact bytes and Stage R checks them against the current source checkout. - `B/audit-support/p04-r17-full-inputs-r01/MANIFEST.json`, SHA256 `a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c8a8`. - All 1338 files below that relocation's `product/`, each matched to the manifest by bytes/SHA. No source is omitted and no old path is followed. - Its `fixed/6ce6b28c5985e8a4f13b78bfeb1f1e09f6216d874fb01e0656ec1633bfa01cd7/completion_marker_contracts.json`. - `B/audit-support/p04-review-repair22-r01/ACTUAL_CURRENT_PUBLIC_POWER_FUNCTIONS.json`. -- The three staged S4 files above, pinned by the plan, and the staged native - executable at B/audit-support/p04-s4-source-r23/Godot, pinned before native - admission and checked unchanged after collection. The only stage override +- The three staged S4 files above, pinned by the plan, and the installed executable + `/Applications/Godot.app/Contents/MacOS/Godot`, pinned directly against the + constant SHA before launch, during collection, and explicitly after cleanup. + Before/during/after descriptors are retained in runner-input and execution. The only stage override is `tests/s3/test_runtime_staff_assignment.gd` with the S4 probe. Harness and kitchen fixture are the unchanged product files; inherited sources are included in the full1338 map. The parse roster is all316 `.gd` inputs. @@ -61,14 +57,15 @@ Exact input footprints: the actual full import. All316 scripts are parsed before Writer and Reader. - The engine SHA256 is `c7cccbf8fb143e34e02fd6521e09be2c2b974f0d5db080b19071c9c570718ccf`, - matching the installed executable and preserved r22 staged executable during - source preparation. Fresh mode does not obtain engine identity from a cache. + required directly of the installed executable. Fresh mode does not obtain engine identity from a cache. - Optional `--cache-run` retains the registered path, passed-run, complete-source and engine identity guards. The known red run remains ineligible. The commands - above use no cache. Preserve the old r22 staging and plan unchanged. + above use no cache. Preserve the old r22 staging and plan unchanged. r22 is an immutable failed + proof and remains ineligible. Its diagnostics are at + `audit-support/p04-root-d393-s4-r01/ENGINE_STAGING_DIAGNOSTICS.json`. -Exact output footprints are `B/p04-s4-plan-r23.json` and the fresh -`B/p04-s4-native-r22/**`: private selected source stage, complete phase receipts +Exact output footprints are `B/p04-s4-plan-r24.json` and the fresh +`B/p04-s4-native-r24/**`: private selected source stage, complete phase receipts and logs, raw JSON/Variant points and all phase observations, full source maps, PID and cleanup receipts. `formal/{writer,reader}/S4-{boundary,held,recovered}/` mirrors all four formal members (`journal.log`, `manifest.json`, `thumbnail.png`, @@ -109,10 +106,9 @@ capacity and consumer allocation. Transient `_last_report` is cleared on normal restore and is not part of Runtime snapshot equality. The derived `related_facility_operating` flag is measured separately and checked after restore. -After successful S4, Root can perform the eight local suites and fresh read-only -R collection described in EVIDENCE_COLLECTION.md. S4 is missing until the actual -collection succeeds. Subsequent index/cross-gate work is not a source-preparation -blocker. Rebind support53cb through its normal registered task against the new -source. Preserve the21615-check proof. Only if exact final1339 evidence is -required, perform one full run after all fixes, S4, local checks, eight suites -and rebind are bundled. Never splice different-version raw or claim1339 identity. +This source-only dispatch authorizes no worker execution. Root stages the three +files, creates the r24 plan with --check-only, then collects once to the fresh +r24 output. Do not rerun S1-S3, C or full178. No engine copy, signing, xattr, +codesign call or security-setting change is part of this procedure. +Native evidence, registered validation, independent review, support53cb rebind +and formal acceptance remain pending. D05 remains pending. diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/engine_identity_negative_fixtures.py b/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/engine_identity_negative_fixtures.py new file mode 100644 index 0000000..f1a7403 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/engine_identity_negative_fixtures.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""Root-only engine identity controls; tests NOT RUN by worker.""" +import copy +import importlib.util +import json +from pathlib import Path +import sys +from unittest.mock import patch + +sys.dont_write_bytecode = True +HERE = Path(__file__).resolve().parent +spec = importlib.util.spec_from_file_location("series", HERE.parent / "p04_native_series.py") +series = importlib.util.module_from_spec(spec) +spec.loader.exec_module(series) +spec = importlib.util.spec_from_file_location("s4", HERE / "run_s4_native.py") +s4 = importlib.util.module_from_spec(spec) +spec.loader.exec_module(s4) + + +def run(): + # Read only the real installed executable. Never copy or write an engine. + pin = s4.engine_pin(s4.ENGINE) + identity = dict(before=pin, during=[pin], after=pin) + results = [] + + def reject(label, action): + try: + action() + except (ValueError, OSError, KeyError, TypeError) as caught: + results.append(dict(case=label, result="rejected", error=str(caught))) + else: + raise AssertionError("negative accepted: " + label) + + # Same bytes/SHA cannot admit an own-B bare copy or another outside-B path. + for label, path in [ + ("copied bare engine in B with same SHA", s4.BUILD / "audit-support/p04-s4-source-r24/Godot"), + ("other outside-B path", Path("/Applications/OtherGodot.app/Contents/MacOS/Godot")), + ]: + other = dict(pin, path=str(path)) + reject(label, lambda other=other: series.verify_s4_engine(other, identity)) + reject(label + " wrapper", lambda path=path: s4.engine_pin(path)) + reject("SHA mismatch", lambda: series.verify_s4_engine(dict(pin, sha256="0" * 64), identity)) + with patch.object(s4, "ENGINE_SHA256", "0" * 64): + reject("wrapper SHA mismatch", lambda: s4.engine_pin(s4.ENGINE)) + changed = copy.deepcopy(identity) + changed["after"]["inode"] += 1 + reject("after-identity mismatch", lambda: series.verify_s4_engine(pin, changed)) + reject("wrapper after-identity mismatch", + lambda: s4.engine_pin(s4.ENGINE, dict(pin, inode=pin["inode"] + 1))) + series.verify_s4_engine(pin, identity) + results.append(dict(case="exact installed path", result="accepted")) + return dict(scope="read-only engine identity fixtures", results=results, formal_acceptance=False) + + +if __name__ == "__main__": + print(json.dumps(run(), indent=2, sort_keys=True)) diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/run_s4_native.py b/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/run_s4_native.py index 5cd39f4..27a19b4 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/run_s4_native.py +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/s4/run_s4_native.py @@ -8,6 +8,7 @@ import json import os import shutil import subprocess +import stat import sys sys.dont_write_bytecode = True @@ -17,7 +18,7 @@ PRODUCT = BUILD / "audit-support/p04-r17-full-inputs-r01/product" CACHE_RUN = BUILD / "p04-final-product-full-r01" TEST = "tests/s3/test_runtime_staff_assignment.gd" QA = HERE / "p04_s4_power_probe.gd" -ENGINE = HERE / "Godot" +ENGINE = Path("/Applications/Godot.app/Contents/MacOS/Godot") ENGINE_SHA256 = "c7cccbf8fb143e34e02fd6521e09be2c2b974f0d5db080b19071c9c570718ccf" MANIFEST = BUILD / "audit-support/p04-r17-full-inputs-r01/MANIFEST.json" MANIFEST_SHA = "a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c8a8" @@ -69,24 +70,52 @@ def pin(path): data = path.read_bytes() return dict(path=str(path), bytes=len(data), sha256=hashlib.sha256(data).hexdigest()) +def engine_pin(path, expected=None): + path = Path(path) + if path != ENGINE or any(p.is_symlink() for p in (path, *path.parents)): + raise ValueError("exact installed engine required; no symlink or relocated input") + if path.resolve(strict=True) != ENGINE: + raise ValueError("installed engine resolved path changed") + before = path.stat() + if not stat.S_ISREG(before.st_mode): + raise ValueError("installed engine must be regular") + digest = hashlib.sha256(path.read_bytes()).hexdigest() + after = path.stat() + fields = ("st_dev", "st_ino", "st_size", "st_mtime_ns", "st_ctime_ns", "st_mode") + if any(getattr(before, k) != getattr(after, k) for k in fields): + raise ValueError("engine changed while hashing") + if any(p.is_symlink() for p in (path, *path.parents)) or path.resolve(strict=True) != ENGINE: + raise ValueError("engine path changed while hashing") + value = dict(path=str(path), resolved_path=str(path.resolve(strict=True)), + bytes=after.st_size, mtime_ns=after.st_mtime_ns, mode=after.st_mode, + device=after.st_dev, inode=after.st_ino, ctime_ns=after.st_ctime_ns, sha256=digest) + if digest != ENGINE_SHA256: + raise ValueError("engine differs from installed engine constant") + if expected is not None and value != expected: + raise ValueError("engine identity changed") + return value + def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--project-root", type=Path, default=PRODUCT) - parser.add_argument("--output", type=Path, default=BUILD / "p04-s4-native-r22") - parser.add_argument("--plan", type=Path, default=BUILD / "p04-s4-plan-r23.json") + parser.add_argument("--output", type=Path, default=BUILD / "p04-s4-native-r24") + parser.add_argument("--plan", type=Path, default=BUILD / "p04-s4-plan-r24.json") parser.add_argument("--cache-run", type=Path, default=None, help="optional passed registered cache; default is fresh, without cache access") parser.add_argument("--godot", type=Path, default=ENGINE) parser.add_argument("--check-only", action="store_true") args = parser.parse_args() - if args.godot.resolve() != ENGINE.resolve(): - raise ValueError("use the exact own-B staged engine") + engine_descriptor = engine_pin(args.godot) if args.cache_run is not None and args.cache_run.resolve() != CACHE_RUN.resolve(): raise ValueError("only registered own-B full-run cache") root = args.project_root.resolve() out = args.output.resolve() if not out.is_relative_to(BUILD.resolve()) or not args.plan.resolve().is_relative_to(BUILD.resolve()): raise ValueError("plan/output must stay in task build") + if out.exists() or out.is_symlink(): + raise ValueError("fresh output required") + if args.check_only and (args.plan.exists() or args.plan.is_symlink()): + raise ValueError("fresh plan required") r = module("s4_standard_runner", root / "tools/run_all_tests.py") # Preserve the reviewed source_refs -> exactly one QA override order. source_before = r.source_refs(root) @@ -103,6 +132,10 @@ def main(): selected = dict(root_before=source_before, map={n: p["sha256"] for n, p in refs.items()}, timeout=1200) cache_note = None cache_receipts = [] + if args.cache_run is not None: + # Reject failed caches before reading their inputs or cache contents. + r.require(r.read(args.cache_run / "runner-ended.json")["passed"] is True, + "failed cache is ineligible") for leaf in (["runner-ended.json", "runner-input.json"] if args.cache_run is not None else []): path = args.cache_run / leaf try: @@ -116,29 +149,37 @@ def main(): QA_overrides=[TEST], fixed_input_pins=fixed, cache_run=str(args.cache_run) if args.cache_run is not None else None, import_mode="cache" if args.cache_run is not None else "fresh", - engine_sha256=ENGINE_SHA256, + engine_sha256=ENGINE_SHA256, engine=engine_descriptor, cache_receipts=cache_receipts, cache_access=cache_note, phases=["import", "parse", "writer", "reader"], native_engine_launches=0, whole_goal_accepted=False, unit_accepted=False) # Check-only only reads source/materials and writes the plan in task build. - # It deliberately does not read default-player data, inspect processes or stat Godot. + # Reads engine identity; never launches Godot or inspects players/processes. if args.check_only: args.plan.parent.mkdir(parents=True, exist_ok=True) - if args.plan.exists(): - r.require(r.read(args.plan) == plan, "existing plan differs; use a fresh plan path") - else: - r.write(args.plan, plan) + r.write(args.plan, plan) print(json.dumps(dict(check_only=True, engines=0, source_files=len(source_before), QA_overrides=[TEST], fixed_pins=len(fixed), plan=str(args.plan), plan_sha256=r.sha(args.plan), cache_access=cache_note), ensure_ascii=False)) return 0 r.require(root == PRODUCT.resolve() and len(source_before) == 1338, "Root native requires product 1338; worker plan is not native evidence") r.require(args.plan.is_file() and r.read(args.plan) == plan, "run exact check-only plan first") - engine_descriptor = None + engine_observations = [] + engine_identity = dict(before=engine_descriptor, during=[], after=None) + def repin(label): + try: + value = engine_pin(args.godot, engine_descriptor) + engine_observations.append(dict(stage=label, descriptor=value)) + if label == "after-cleanup": + engine_identity["after"] = value + else: + engine_identity["during"].append(value) + except BaseException as caught: + engine_observations.append(dict(stage=label, error=str(caught))) + raise def fixed_guard(): + repin("cleanup-fixed-guard") template_guard(root) - if engine_descriptor is not None: - r.require(pin(engine_descriptor["path"]) == engine_descriptor, "engine changed during collection") for value in fixed + cache_receipts: r.require(pin(value["path"]) == value, "fixed input changed: " + value["path"]) fixed_guard() @@ -147,20 +188,16 @@ def main(): # Native cache admission remains Root-only and fails closed. r.require(cache_note is None, "Root must read exact cache receipts: " + str(cache_note)) r.require(r.read(old / "runner-ended.json")["passed"], "ended cache run must have passed") - old_map = r.read(old / "runner-input.json")["selected_source_map"] + cache_input = r.read(old / "runner-input.json") + r.require(cache_input["engine_sha256"] == ENGINE_SHA256, "cache engine identity") + old_map = cache_input["selected_source_map"] current_map = {n: p["sha256"] for n, p in source_before.items()} r.require({k: v for k, v in old_map.items() if k != "tools/check_p04_order_evidence.py"} == current_map and len(old_map) == 1339, "immutable full cache: all 1338 product inputs equal; checker is not parsed/executed by product suites") protected = r.default_player(root) outer = module("s4_owned_outer", r.SUPPORT / "owned_outer.py") r.require(not outer.native.helper["live_engines"](), "another Godot owns CPU") - engine = args.godot.resolve() - r.require(engine.is_file(), "Root native Godot path") - engine_descriptor = pin(engine) - r.require(engine_descriptor["sha256"] == ENGINE_SHA256, - "exact reviewed staged engine; no environment substitution") - if old is not None: - r.require(engine_descriptor["sha256"] == r.read(old / "runner-input.json")["engine_sha256"], - "staged engine matches preserved full proof; no environment substitution") + engine = ENGINE + repin("native-admission") r.require(shutil.disk_usage(out.parent).free >= 1024**3 + engine.stat().st_size + 136*1024**2, "reviewed native disk admission") r.require(not out.exists(), "fresh output required; preserve previous attempts") @@ -225,7 +262,7 @@ def main(): r.require(TEST not in policy["suite_policies"], "no normal suite watchdog/policy override") r.write(out / "contracts.json", contracts) r.write(out / "runner-input.json", dict(plan, owner_runner_pid=os.getpid(), - wrapper_sha256=r.sha(__file__), QA=pin(QA), engine=engine_descriptor, runner_sha256=r.sha(root / "tools/run_all_tests.py"), + wrapper_sha256=r.sha(__file__), QA=pin(QA), engine=engine_descriptor, engine_identity=engine_identity, runner_sha256=r.sha(root / "tools/run_all_tests.py"), default_player_before=protected, fixed_input_pins=fixed, functional_watchdog_seconds=1200, source_adoption=False)) diagnostics = module("s4_diagnostics", r.SUPPORT / "diagnostic_gate.py") @@ -240,6 +277,8 @@ def main(): if phase == "import" and old is None: r.require(not (stage / ".godot").exists() and not (stage / ".godot").is_symlink(), "fresh private .godot absent at actual import") + repin("before-" + phase) + r.write(out / "engine-identity.json", engine_observations) row = r.execute_phase(str(engine), stage, out, phase, test, selected, expected, previous, policy, contracts, paths, public, protected, root, outer, markers, diagnostics, owners, audio) @@ -260,6 +299,7 @@ def main(): "exact one independent Writer/Reader case") r.require(sorted(receipt["slots"]) == SLOTS, "all formal point slots") r.require(receipt["pid"] == row["actual_pid"], "actual native PID/receipt") + repin("after-collection") writer = r.read(out / "raw/writer.json") reader = r.read(out / "raw/reader.json") r.require(writer["pid"] != reader["pid"] and writer["profile"] != reader["profile"], "distinct formal processes") @@ -268,11 +308,19 @@ def main(): except BaseException as caught: error = type(caught).__name__ + ": " + str(caught) finally: - cleanup, cleanup_errors = outer.finish_captured(outer.OWNED) + try: + cleanup, cleanup_errors = outer.finish_captured(outer.OWNED) + except BaseException as caught: + cleanup_errors.append(str(caught)) try: r.write(out / "outer-owned-finally.json", dict(cleanup=cleanup, errors=cleanup_errors)) except BaseException as caught: guards.append("finally receipt: " + type(caught).__name__ + ": " + str(caught)) + # Explicit re-pin after cleanup is independent of other fixed-input guards. + try: + repin("after-cleanup") + except BaseException as caught: + guards.append(type(caught).__name__ + ": " + str(caught)) # Fixed guard always follows ownership cleanup, even if setup or an engine failed. try: fixed_guard() @@ -318,6 +366,19 @@ def main(): r.write(out / "formal-relocation.json", relocated) r.write(out / "raw-inventory.json", r.inventory(out / "raw")) r.write(out / "PID-set.json", dict(owner_runner_pid=os.getpid(), engine_PIDs=pids)) + try: + repin("after-output-collection") + except BaseException as caught: + guards.append(str(caught)) + passed = False + execution["passed"] = False + r.write(out / "engine-identity.json", engine_observations) + execution["engine_observations"] = engine_observations + execution["engine_identity"] = engine_identity + if (out / "runner-input.json").is_file(): + final_inputs = r.read(out / "runner-input.json") + final_inputs["engine_identity"] = engine_identity + r.write(out / "runner-input.json", final_inputs) r.write(out / "execution.json", execution) r.write(out / "runner-ended.json", dict(execution, ended=r.now())) print(json.dumps(dict(passed=passed, error=error, guard_errors=guards, output=str(out))))