diff --git a/docs/scratchpads/829-mutator-gate.md b/docs/scratchpads/829-mutator-gate.md index 858705d..5bcbbdc 100644 --- a/docs/scratchpads/829-mutator-gate.md +++ b/docs/scratchpads/829-mutator-gate.md @@ -115,3 +115,9 @@ Carried authority chain also verified/read for the locked T-B gate contract: SPE - Permanent guard suite now has 10 tests and 31 direct-launch forms, including 18 new round-4 marker/comment/indirection/prefix evasions plus harmless-marker and multiline-wrapper controls. Terra's exact add-ungated source is exercised through the CLI effectiveness test. Repository inventory remains exactly **14 gated / 14 total**. - Fresh round-4 coverage: guard **97%** branch-aware aggregate (241 statements, 110 branches); `launch-runtime.py` **100%**; `mutator-gate.py` **100%**. The daemon is byte-unchanged from the round-3 head whose WI-2 delta is **87.5%**. - Fresh round-4 gates: real-socket acceptance **49/49**; persistence **10/10**; launcher/gate **14/14**; guard **10/10**; coord **19/19**; Mosaic **1384/1384**; root **43/43**; typecheck **42/42**; lint **23/23**; format and diff checks green. + +## Remediation round 5 — terra 18116 + Opus 18114 + +- Both independent gates converged on one guard-only completeness gap at round-4 head `1eb77c17f3147d4fa9944f77f1826243135b9cc0`; all round-4 primitive anchoring, command-position parsing, 14/14 inventory, broker ordering, and coverage remain locked-good. +- Reproduced exactly: a temporary production source containing `launcher=claude` followed by `exec "$launcher" -p x` exits 0 with `0 gated / 0 total`. The literal command resolver skips prefixes but cannot resolve a tracked variable; the variable resolver handles only bare/eval references and cannot skip prefixes. +- Round-5 plan: add 10 permanent RED forms (quoted/unquoted `exec`, `command`, `nohup`, and `env` with assignment, each multiline and same-line), then unify shell command-position resolution so literal and tracked-variable terminal tokens traverse the same prefix parser. Retain an independent variable-reference backstop, the 14/14 inventory, and every round-4 regression. diff --git a/packages/mosaic/src/mutator-gate/runtime_launch_guard_unittest.py b/packages/mosaic/src/mutator-gate/runtime_launch_guard_unittest.py index e049b2c..4e8a372 100644 --- a/packages/mosaic/src/mutator-gate/runtime_launch_guard_unittest.py +++ b/packages/mosaic/src/mutator-gate/runtime_launch_guard_unittest.py @@ -76,6 +76,22 @@ class RuntimeLaunchGuardTest(unittest.TestCase): with self.subTest(filename=filename): self.assertEqual(GUARD.scan_text(Path(filename), source), []) + def test_detects_prefixed_tracked_runtime_variable_execution(self) -> None: + multiline = { + "exec-quoted": 'exec "$v" -p x', + "exec-unquoted": "exec $v -p x", + "command": 'command "$v" -p x', + "nohup": 'nohup "$v" -p x', + "env": 'env A=1 "$v" -p x', + } + cases = { + **{f"multiline-{name}.sh": f"v=claude\n{command}\n" for name, command in multiline.items()}, + **{f"same-line-{name}.sh": f"v=claude; {command}\n" for name, command in multiline.items()}, + } + for filename, source in cases.items(): + with self.subTest(filename=filename): + self.assertNotEqual(GUARD.scan_text(Path(filename), source), [], source) + def test_accepts_only_validated_multiline_typescript_wrapper_invocation(self) -> None: source = """execRuntime( 'python3',