diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR35_STATIC_CHECKS.json b/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR35_STATIC_CHECKS.json new file mode 100644 index 0000000..3b276b1 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR35_STATIC_CHECKS.json @@ -0,0 +1,72 @@ +{ + "validation": "py_compile and ast only", + "results": [ + { + "file": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/run_s5_native.py", + "py_compile": "passed", + "ast.parse": "passed", + "ast.required_functions": "passed", + "ast.no_fixed_counts": "passed" + }, + { + "file": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/s5_wrapper_fixtures.py", + "py_compile": "passed", + "ast.parse": "passed" + } + ], + "fixtures": [ + { + "name": "partial-triple", + "status": "unexecuted" + }, + { + "name": "non-hex", + "status": "unexecuted" + }, + { + "name": "short", + "status": "unexecuted" + }, + { + "name": "mixed-modes", + "status": "unexecuted" + }, + { + "name": "historical-native", + "status": "unexecuted" + }, + { + "name": "no-flags", + "status": "unexecuted" + }, + { + "name": "fresh-q", + "status": "unexecuted" + }, + { + "name": "historical-check-only", + "status": "unexecuted" + }, + { + "name": "git-dirty-file", + "status": "unexecuted" + }, + { + "name": "git-untracked-file", + "status": "unexecuted" + }, + { + "name": "git-wrong-head-tree", + "status": "unexecuted" + }, + { + "name": "git-wrong-submission", + "status": "unexecuted" + }, + { + "name": "git-wrong-main", + "status": "unexecuted" + } + ], + "accepted": false +} diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR35_STATUS.md b/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR35_STATUS.md new file mode 100644 index 0000000..3f52b60 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/REPAIR35_STATUS.md @@ -0,0 +1,37 @@ +# REPAIR35 — submitted preparation, no acceptance credit + +Scope is the S5 wrapper fresh-Q mode, pure mode-selection fixtures and status +documents only. The wrapper now binds M/S/Q_tree, the clean checkout carrier, +selection authority, selected source bytes and Q marker contracts. Fixed-input +rechecks require identical provenance. Cache comparisons remove only checker +and TEST from both maps and otherwise compare keys and hashes. R17 is explicitly +check-only/read-only. Fresh-Q counts are derived; historical material is listed +as historical_not_inputs rather than pinned as fresh-Q input. + +R34 structural C, Root normal_c_join, probe, adapter, ownership/PID/cleanup, +Writer/Reader, formal mirror and inventory remain unchanged. Product, Clock, +values, tests/, Runner, core and Owner CLI were read-only. No Git commands, +engines, Runner operations or fixture execution were performed. No /tmp or +permission additions were used. A shell heredoc could not be created by the +environment; that edit attempt exited before running Python or changing files. +Edits were then applied directly in place. + +Only py_compile and AST static validation are recorded in +REPAIR35_STATIC_CHECKS.json. Pure fixtures (partial triple, non-hex, short, +mixed modes, historical native, no flags, full triple, historical check-only) +and all five Root Git negatives are **unexecuted**. No functional pass is claimed. + +Pending: S5 destruction/midnight/exit drivers; fresh Q for S1–S4 and collector; +184 suites / 329 parse; truthful index; Root run order; Root exact-candidate +qualification. Root next builds Qt and parentless X, stages under its own B, +then runs check-only, pure fixtures and Git negatives as described in +s5/S5_ROOT_RUN.md. No native/batch admission until the pending prerequisites +are ready. + +All 7 domains + EV, formal 16/88, original 30/88, P04 credit 0, all six D05 +approvals, frozen M c0ea009b28a7649aca6a433a1a24dc0be5e7ab81 and allowed_paths +remain fixed. This is an internal step of P04-01, no new counted unit and no +completion claim. Unchanged support gates including owned_outer.py were not +read or executed; their qualification remains with Root, as recorded in the +direction. Source commit identity was not independently checked because Git +commands are prohibited for this worker. diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/S5_ROOT_RUN.md b/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/S5_ROOT_RUN.md index 02e47d2..4c4e9dd 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/S5_ROOT_RUN.md +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/S5_ROOT_RUN.md @@ -6,10 +6,45 @@ Both use public resource commands, observed recovery, formal packages, independe Reader replay, phase raw and resource-command replay receipts. The bath has no item reservation; the dependent case retains and consumes the actual meal ID. -`run_s5_native.py` retains the S4 ownership/engine/cleanup safeguards and historical -template bindings. It is not fresh-Q plumbing. Do not run it against Q or start -the once-only native/full batch until the separately pending identity work is -finished. No old S1–S4 record is renamed or reused as fresh proof. +`run_s5_native.py` retains the S4 ownership/engine/cleanup safeguards. REPAIR35 +adds fresh-Q input binding and separates historical R17 relocation checks from +the unchanged probe checks. All source and parse counts are derived. Historical +R17 requires `--historical-r17 --check-only` and is read-only. Only historical +mode defaults `--project-root` to PRODUCT. Fresh-Q requires an explicit root and +all three full lowercase HEX40 inputs. R17 MANIFEST and repair22 power-functions +JSON are historical_not_inputs in fresh-Q plans, never fresh-Q fixed pins. +No old S1–S4 record is renamed or reused as fresh proof. + +REPAIR35 is check-only only; no native/batch admission until S5 +destruction/midnight/exit, S1–S4/collector fresh Q, 184 suites / 329 parse and the +truthful index are ready. Root run order and exact-candidate qualification also +remain pending. The native implementation is retained for later Root admission; +this change and a check-only plan give no admission or acceptance credit. + +After final S35, Root alone performs these steps (not performed by the worker): + +1. Set S to the final submission and M to + `c0ea009b28a7649aca6a433a1a24dc0be5e7ab81`; derive Qt with + `git merge-tree --write-tree "$M" "$S"`. +2. Create X with `git commit-tree "$Qt" -m 'nonproduction Q checkout'` with + **no parents**, then create a clean worktree at X. X is a nonproduction + checkout carrier of Q, never normal Runner C. R34 and Root normal_c_join + remain unchanged. +3. Stage the s5 directory under Root's own B, the registered BUILD directory. +4. Run only the check-only path, with fresh output and plan paths: + +```sh +BUILD_OUTPUT_DIR="$B" python3 "$B/.../run_s5_native.py" \ + --project-root "$wt" --main "$M" --submission "$S" --tested-tree "$Qt" \ + --check-only --plan "$B/p04-s5-plan-r35.json" --output "$B/p04-s5-native-r35" +``` + +5. Run `s5_wrapper_fixtures.py` separately. Its JSON always has accepted=false. +6. In separate controlled check-only cases, require rejection for: a dirty file; + an untracked file; HEAD tree unequal to --tested-tree; wrong --submission; + --main unequal to the frozen anchor. Preserve each actual rejection receipt + and restore a clean carrier between cases. These Git negatives and all pure + fixtures are unexecuted in this worker submission. No engine runs. Root later stages the wrapper, probe and this document in its own build area. The adapter takes `--raw-root`, `--writer-sha256`, `--reader-sha256` from verified @@ -19,4 +54,5 @@ measurement keys. It does not qualify source, engine, settings or full evidence. S5 destruction, midnight and exit cases remain unimplemented. The preserved `PENDING.md` is historical partial31 text; this document records only the added, unexecuted power pair. D05 six approvals, A01, frozen M, 16/88 and P04 credit 0 -are unchanged. Root alone runs engines and scratch fixtures. +are unchanged. All 7 domains + EV and original 30/88 remain fixed. Root alone +performs later qualification; no engine is authorized by REPAIR35. diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/run_s5_native.py b/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/run_s5_native.py index 4a588f2..93f59aa 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/run_s5_native.py +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/run_s5_native.py @@ -7,6 +7,7 @@ import hashlib import importlib.util import json import os +import re import shutil import subprocess import stat @@ -29,7 +30,7 @@ LABELS = {case: ["boundary", "held", "recovered"] for case in CASES} SLOTS = sorted(case + "-" + label for case in CASES for label in LABELS[case]) MATERIALS = [MANIFEST, BUILD / "audit-support/p04-review-repair22-r01/ACTUAL_CURRENT_PUBLIC_POWER_FUNCTIONS.json"] -def template_guard(root): +def r17_relocation_guard(root): if root != PRODUCT.resolve() or not HERE.is_relative_to(BUILD.resolve()): raise ValueError("Root must stage this exact QA/wrapper/plan inside own B") if pin(MANIFEST)["sha256"] != MANIFEST_SHA: @@ -42,6 +43,8 @@ def template_guard(root): if Path(row["relocated"]).resolve() != root / name or any( actual[k] != source[k] or actual[k] != row[k] for k in ("bytes", "sha256")): raise ValueError("relocated product differs: " + name) + +def probe_guard(root): probe = QA.read_text() import re if ":=" in probe or re.search(r"\bvar\s+\w+\s*=", probe) or re.search(r"\bfor\s+\w+\s+in\b", probe): @@ -96,20 +99,94 @@ def engine_pin(path, expected=None): raise ValueError("engine identity changed") return value +C_REL = "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json" + + +def select_mode(args): + """Pure CLI mode selection; no filesystem or Git access.""" + triple = (args.main, args.submission, args.tested_tree) + if any(value is not None for value in triple): + if (not all(isinstance(value, str) and re.fullmatch(r"[0-9a-f]{40}", value) + for value in triple) or args.historical_r17): + raise ValueError("fresh-q requires a full HEX40 triple without --historical-r17") + return "fresh-q" + if args.historical_r17 and args.check_only: + return "historical-r17-readonly" + raise ValueError("historical R17 is read-only; require --historical-r17 --check-only") + + +def fresh_q_guard(root, M, S, Qt): + gate = module("s5_gate", root / "tools/check_p04_order_evidence.py") + gate.require(Path(gate.__file__).resolve() == root / gate.CHECKER_PATH + and not root.is_symlink(), "fresh-q checker/root location") + gate.require(M == gate.MAIN_ANCHOR, "fresh-q main anchor") + commit, tree, entries = gate.actual_checkout() + gate.require(tree == Qt and commit != S and commit != M, "fresh-q checkout carrier") + gate.require(Path(os.environ["BUILD_OUTPUT_DIR"]).resolve() == BUILD.resolve(), + "fresh-q own BUILD_OUTPUT_DIR") + with gate.isolated_objects(): + for value in (M, S): + gate.require(gate.git_bytes("cat-file", "-t", value) == b"commit\n", "commit input") + gate.submission_role(S) + composed = gate.git_bytes("-c", "rerere.enabled=false", "merge-tree", "--write-tree", M, S).decode().strip() + gate.require(re.fullmatch(r"[0-9a-f]{40}", composed) is not None and composed == Qt, + "fresh-q recomputed tree") + gate.require(hashlib.sha256(gate.git_bytes("show", M + ":tools/run_all_tests.py")).hexdigest() + == gate.SELECTION_SHA, "selection authority") + gate.require(gate.product_manifest(gate.tree_entries(M)) == gate.product_manifest(entries), + "fresh-q product unchanged") + sel = gate.selected_manifest(entries, require_checker=True) + r = module("s5_guard_runner", root / "tools/run_all_tests.py") + source_before = r.source_refs(root) + gate.require(source_before.keys() == sel.keys() and TEST in sel, + "fresh-q selected source keys") + gate.require({name: {key: value[key] for key in ("bytes", "sha256")} + for name, value in source_before.items()} == sel, "fresh-q selected bytes") + gate.require(C_REL in entries, "fresh-q contracts entry") + blob = gate.git_bytes("cat-file", "blob", entries[C_REL][1]) + contract_pin = pin(root / C_REL) + gate.require(contract_pin["bytes"] == len(blob) + and contract_pin["sha256"] == hashlib.sha256(blob).hexdigest(), + "fresh-q contracts pin") + build = BUILD.resolve() + gate.require(HERE.is_relative_to(build), "fresh-q staged HERE inside BUILD") + for staged in [HERE, *HERE.rglob("*")]: + current = build + for part in staged.relative_to(build).parts: + current = current / part + gate.require(not current.is_symlink(), "fresh-q staged symlink") + gate.require(staged.is_dir() or stat.S_ISREG(staged.stat().st_mode), + "fresh-q staged regular file") + return dict(M=M, S=S, Q_tree=Qt, recomputed_Q=composed, checkout_commit=commit, + checkout_role="nonproduction Root checkout carrier of tree Q; NOT normal Runner C", + selected_manifest_sha256=gate.manifest_digest(sel), selected_file_count=len(sel), + product_file_count=len(sel)-1, selection_authority_sha256=gate.SELECTION_SHA) + + def main(): parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--project-root", type=Path, default=PRODUCT) + parser.add_argument("--project-root", type=Path, default=None) parser.add_argument("--output", type=Path, default=BUILD / "p04-s5-native-r32") parser.add_argument("--plan", type=Path, default=BUILD / "p04-s5-plan-r32.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") + parser.add_argument("--main") + parser.add_argument("--submission") + parser.add_argument("--tested-tree") + parser.add_argument("--historical-r17", action="store_true") args = parser.parse_args() + mode = select_mode(args) + if mode == "fresh-q" and args.project_root is None: + raise ValueError("fresh-q requires explicit --project-root") + project_root = args.project_root if args.project_root is not None else PRODUCT + if project_root.is_symlink(): + raise ValueError("project root symlink") 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() + root = 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") @@ -122,13 +199,19 @@ def main(): source_before = r.source_refs(root) refs = dict(source_before) refs[TEST] = pin(QA) - template_guard(root) + provenance = None + if mode == "fresh-q": + provenance = fresh_q_guard(root, args.main, args.submission, args.tested_tree) + else: + r17_relocation_guard(root) + probe_guard(root) expected = {n: dict(bytes=p["bytes"], sha256=p["sha256"]) for n, p in refs.items()} - fixed = [pin(p) for p in MATERIALS + [ + contracts_path = root / C_REL if mode == "fresh-q" else CONTRACTS + fixed = [pin(p) for p in ([] if mode == "fresh-q" else MATERIALS) + [ QA, Path(__file__), HERE / "S5_ROOT_RUN.md", root / "tests/transport/test_runtime_transport.gd", root / "tests/staff/test_rescue_elevator.gd", - CONTRACTS, + contracts_path, ]] selected = dict(root_before=source_before, map={n: p["sha256"] for n, p in refs.items()}, timeout=1200) cache_note = None @@ -145,7 +228,11 @@ def main(): cache_note = dict(path=str(path), error=type(caught).__name__ + ": " + str(caught), required_before_native=True) break - plan = dict(protocol="p04-s5-preparation-v1", project_root=str(root), output=str(out), engine_path=str(args.godot.resolve()), + plan = dict(protocol=("p04-s5-fresh-q-v1" if mode == "fresh-q" else "p04-s5-historical-r17-readonly-v1"), + mode=mode, provenance=provenance, historical_r17=mode != "fresh-q", + native_admissible=False, fresh_q_evidence=False, + historical_not_inputs=[str(p) for p in MATERIALS] if mode == "fresh-q" else [], + project_root=str(root), output=str(out), engine_path=str(args.godot.resolve()), source_before=source_before, selected_source_map=selected["map"], QA_overrides=[TEST], fixed_input_pins=fixed, cache_run=str(args.cache_run) if args.cache_run is not None else None, @@ -163,7 +250,9 @@ def main(): 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") + if mode != "fresh-q": + raise ValueError("historical R17 is read-only") + r.require(len(source_before) == provenance["selected_file_count"], "fresh-q selected count") r.require(args.plan.is_file() and r.read(args.plan) == plan, "run exact check-only plan first") engine_observations = [] engine_identity = dict(before=engine_descriptor, during=[], after=None) @@ -180,7 +269,9 @@ def main(): raise def fixed_guard(): repin("cleanup-fixed-guard") - template_guard(root) + r.require(fresh_q_guard(root, args.main, args.submission, args.tested_tree) == provenance, + "fresh-q provenance changed") + probe_guard(root) for value in fixed + cache_receipts: r.require(pin(value["path"]) == value, "fixed input changed: " + value["path"]) fixed_guard() @@ -193,7 +284,10 @@ def main(): 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") + excluded = {"tools/check_p04_order_evidence.py", TEST} + r.require({k: v for k, v in old_map.items() if k not in excluded} + == {k: v for k, v in current_map.items() if k not in excluded}, + "immutable cache selected inputs except checker and QA override") protected = r.default_player(root) outer = module("s5_owned_outer", r.SUPPORT / "owned_outer.py") r.require(not outer.native.helper["live_engines"](), "another Godot owns CPU") @@ -254,10 +348,10 @@ def main(): whole_cache=cache_before, independent_inode=True, ordinary_import_required=True, ordinary_parse_required=True)) paths = ["res://" + n for n in sorted(refs) if n.endswith(".gd")] - r.require(len(paths) == 316, "complete 316-script parse roster") + r.require(len(paths) == sum(name.endswith(".gd") for name in refs), "complete derived parse roster") r.write(out / "parse-paths.json", paths) markers = module("s5_markers", root / "tools/strict_test_markers.py") - contracts = markers.load_contracts(CONTRACTS) + contracts = markers.load_contracts(contracts_path) contracts[TEST] = dict(test=TEST, template="S5 power: checks, failures", required=True) policy = r.read(r.SUPPORT / "suite-policy.json") r.require(TEST not in policy["suite_policies"], "no normal suite watchdog/policy override") diff --git a/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/s5_wrapper_fixtures.py b/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/s5_wrapper_fixtures.py new file mode 100644 index 0000000..c970de1 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p04-01/s5/s5_wrapper_fixtures.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +"""Pure select_mode fixtures; no Git, engine, temporary files or environment access.""" +import argparse +import importlib.util +import json +from pathlib import Path +import sys + +sys.dont_write_bytecode = True + + +def main(): + path = Path(__file__).parent / "run_s5_native.py" + spec = importlib.util.spec_from_file_location("s5_wrapper_fixture_target", path) + wrapper = importlib.util.module_from_spec(spec) + spec.loader.exec_module(wrapper) + cases = [ + ("partial-triple", argparse.Namespace(main="a" * 40, submission=None, tested_tree=None, + historical_r17=False, check_only=True), None), + ("non-hex", argparse.Namespace(main="z" * 40, submission="b" * 40, tested_tree="c" * 40, + historical_r17=False, check_only=True), None), + ("short", argparse.Namespace(main="a" * 39, submission="b" * 40, tested_tree="c" * 40, + historical_r17=False, check_only=True), None), + ("mixed-modes", argparse.Namespace(main="a" * 40, submission="b" * 40, tested_tree="c" * 40, + historical_r17=True, check_only=True), None), + ("historical-native", argparse.Namespace(main=None, submission=None, tested_tree=None, + historical_r17=True, check_only=False), None), + ("no-flags", argparse.Namespace(main=None, submission=None, tested_tree=None, + historical_r17=False, check_only=False), None), + ("fresh-q", argparse.Namespace(main="a" * 40, submission="b" * 40, tested_tree="c" * 40, + historical_r17=False, check_only=True), "fresh-q"), + ("historical-check-only", argparse.Namespace(main=None, submission=None, tested_tree=None, + historical_r17=True, check_only=True), + "historical-r17-readonly"), + ] + results = [] + for name, args, expected in cases: + try: + actual = wrapper.select_mode(args) + passed = expected is not None and actual == expected + except ValueError: + actual = "ValueError" + passed = expected is None + results.append(dict(name=name, result=actual, passed=passed)) + print(json.dumps(dict(accepted=False, fixtures=results, passed=all(r["passed"] for r in results)))) + return 0 if all(r["passed"] for r in results) else 1 + + +if __name__ == "__main__": + raise SystemExit(main())