diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/check_restart.py b/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/check_restart.py index 939d6d8..8dd6c3e 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/check_restart.py +++ b/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/check_restart.py @@ -125,12 +125,29 @@ def check_modules(modules=None, root=ROOT): 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] diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/restart_probe.gd b/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/restart_probe.gd index aaeecc8..e9b88eb 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/restart_probe.gd +++ b/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/restart_probe.gd @@ -399,7 +399,7 @@ func io_proof(base: Dictionary, after: Dictionary, kind: String, returned: Varia func writer_save() -> bool: var before: Dictionary = runtime.create_snapshot() - var backlog := GameClock.get_backlog_minutes() + 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 = [] diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/test_restart.py b/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/test_restart.py index b388384..fdbbebc 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/test_restart.py +++ b/docs/plans/original-completion-2026-10-02/execution/p28-01/restart/probe/test_restart.py @@ -426,6 +426,31 @@ class RestartTests(unittest.TestCase): 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)