feat(model-grounded-detection): group 6, the execution tier as a seam not a build

The rung this project deliberately does not build. Clearwing already runs
sandbox lifecycles, container pools, sanitizer images, PoC replay and stability
classification, and the corrective brief concluded -- from this project's own
defect history -- that reimplementing that machinery is where we go wrong. So
model/execution.py decides eligibility, calls an adopted tool, and records what
happened. A test asserts structurally that it imports no container or
subprocess machinery and defines no build/run/compile/patch function, because
the failure mode to prevent is this file quietly growing a sandbox.

Eligibility is narrow in both directions: only a family a static model cannot
arbitrate (memory safety in C, where the bug turns on runtime layout -- Req
10.3 forbids any web/logic family depending on this tier, and each now has
taint, dominance or constant abstraction instead), and only a finding the model
left undecided. The tier escalates uncertainty; it never re-checks a verdict.

One deliberate asymmetry: a failure to reproduce is NOT a refutation. A sandbox
that does not trigger a bug has not shown the bug is absent, only that this
attempt did not trigger it, so the candidate stays where the model left it.
Reading a failed reproduction as a clean bill of health is the same error class
as reading an absent engine as "no vulnerability".

With no adopted tool present -- the normal case -- the rung is never reached and
clearwing_unavailable is recorded.

All 16 tasks of model-grounded-detection are now done. 720 passing, mypy/ruff
clean, gates byte-identical, zero orphaned modules.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
Marius Ciepluch
2026-09-08 16:58:03 +02:00
co-authored by Claude Opus 5
parent 86f434ab89
commit 0c71c956fd
5 changed files with 269 additions and 4 deletions
+23 -1
View File
@@ -231,7 +231,7 @@ queries in group 4). The gates, `redaction.py`, `pairs.py` overlay/inventory pat
## Group 6 — The execution tier stub (deferred)
- [ ] 6.1 The execution_confirmed rung and the Clearwing adoption seam
- [x] 6.1 The execution_confirmed rung and the Clearwing adoption seam
- Wire `Rung.execution_confirmed` as an optional escalation reached only where the model cannot decide
(memory/C first), behind a capability probe for the Clearwing fork. Do **not** reimplement any sandbox
machinery; the seam calls the adopted tool. Not required for any web/logic class at v1.
@@ -533,3 +533,25 @@ These are the **pre-closure-fix** numbers. A full re-measure is in flight and th
regenerated from it.
713 tests passing, mypy and ruff clean, gates byte-identical, zero orphaned modules.
## Implementation Notes — group 6 (2026-09-08)
The rung this project deliberately does **not** build. Clearwing already runs sandbox lifecycles, container
pools, sanitizer images, PoC replay and stability classification, and the corrective brief concluded — from
this project's own defect history — that reimplementing that class of machinery is where we go wrong. So
`model/execution.py` is a seam: it decides eligibility, calls an adopted tool, records what happened. A test
asserts *structurally* that it imports no container/subprocess machinery and defines no build/run/compile/patch
function, because the failure mode to prevent is this file quietly growing a sandbox.
Eligibility is narrow in both directions. Only a family a static model cannot arbitrate (memory safety in C,
where the bug turns on runtime layout) — Req 10.3 forbids any web/logic family depending on this tier, and
each of them now has taint reachability, guard dominance or constant abstraction instead. And only a finding
the model left *undecided*: the tier escalates uncertainty, never re-checks a verdict already reached.
One deliberate asymmetry: **a failure to reproduce is not a refutation.** A sandbox that does not trigger a
bug has not shown the bug is absent, only that this attempt did not trigger it, so the candidate stays exactly
where the model left it and the reason says so. Reading a failed reproduction as a clean bill of health is the
same error class as reading an absent engine as "no vulnerability".
With no adopted tool present — the normal case — the rung is simply never reached and `clearwing_unavailable`
is recorded.
@@ -1,13 +1,13 @@
{
"counts": {
"load_bearing": 84,
"load_bearing": 85,
"standalone_capability": 7
},
"generated": "2026-09-08 (regenerated after group 5: calibration and reporting)",
"generated": "2026-09-08 (regenerated after group 6: the deferred execution tier)",
"kept_with_a_lever_stripped": {
"improve/evolve.py + improve/validator.py": "the design's Removed list named these whole, but each is a mix: the mechanism lever (removed) and the deterministic rule-status improve loop that `ousast improve` still runs from benchmark evidence, which has no LLM in it and is not what this feature supersedes. Deleting the files would have taken a retained capability with them."
},
"modules": 91,
"modules": 92,
"note": "Classification of every source module after the group-1 subtraction. load_bearing = reachable from a gate, the CLI, or named by a surviving requirement; standalone_capability = its own entry point or protocol, deliberately off the scan path; orphaned = no importer, no entry point, no surviving requirement -- removed, never carried.",
"orphaned": [],
"removed_in_this_pass": {
@@ -331,6 +331,7 @@
"model.candidates",
"model.config_value",
"model.dominance",
"model.execution",
"model.judge",
"model.specs",
"model.taint"
@@ -376,6 +377,12 @@
"module": "model.endpoint",
"reason": "model-grounded-detection Req 8: the judge client, wired by model/judge.py in group 3"
},
{
"classification": "load_bearing",
"importers": [],
"module": "model.execution",
"reason": "model-grounded-detection Req 10: the deferred execution tier seam, adopted not built"
},
{
"classification": "load_bearing",
"importers": [],
@@ -387,6 +394,7 @@
"importers": [
"model.config_value",
"model.dominance",
"model.execution",
"model.judge",
"model.taint"
],
+1
View File
@@ -38,6 +38,7 @@ SPEC_OWNED = {
"model.config_value": "model-grounded-detection Req 6.3: constant abstraction for the configuration families",
"model.calibrate": "model-grounded-detection Req 9: the corpus as the model's calibration set",
"model.report": "model-grounded-detection Req 9.3/11.1: per-slice reporting with the overfitting gap",
"model.execution": "model-grounded-detection Req 10: the deferred execution tier seam, adopted not built",
"cpg": "model-grounded-detection Req 4: the CPG seam package",
"cpg.backend": "model-grounded-detection Req 4.1/4.5: the single Joern subprocess boundary",
"cpg.capability": "model-grounded-detection Req 4.2/4.3: the engine probe that degrades to suspicion",
+118
View File
@@ -0,0 +1,118 @@
"""The execution tier: deferred, adopted, and deliberately narrow (model-grounded-detection, Req 10).
This is the rung this project does **not** build. Clearwing already runs sandbox lifecycles, container pools,
sanitizer images, PoC replay and stability classification, and the corrective brief that started this feature
concluded — from this project's own defect history — that reimplementing that class of machinery is exactly
where we go wrong. So the module is a seam: it decides *eligibility*, calls an adopted tool, and records what
happened. A test asserts structurally that it imports no container or subprocess machinery and defines no
build/run/compile/patch function, because the failure mode to prevent is this file quietly growing a sandbox.
Eligibility is narrow on purpose, and both halves matter:
* **Only a family a static model cannot arbitrate.** Memory safety in C turns on runtime layout, so a crash
is the right oracle. Every web/logic family has taint reachability, guard dominance or constant
abstraction, and Req 10.3 forbids any of them depending on this tier.
* **Only a finding the model could not decide.** The tier escalates uncertainty; it never re-checks a verdict
the model already reached.
And a failure to reproduce is *not* a refutation. A sandbox that does not trigger a bug has not shown the bug
is absent — it has shown this attempt did not trigger it. The candidate stays exactly where the model left it.
"""
from __future__ import annotations
import os
from dataclasses import dataclass
from typing import Protocol
from .ladder import Rung
# Families whose bugs a static model genuinely cannot arbitrate. Everything else is served by taint
# reachability, guard dominance or constant abstraction, and must not wait on a sandbox.
EXECUTION_FAMILIES = frozenset({"memory"})
# Rungs that mean "the model could not decide". Anything above is already arbitrated.
UNDECIDED = frozenset({"suspicion", ""})
CLEARWING_ENV = "OPENULTRASAST_CLEARWING"
_OFF = frozenset({"0", "off", "false", "no"})
_ON = frozenset({"1", "on", "true", "yes"})
@dataclass(frozen=True)
class Candidate:
"""What the execution tier is asked about: a finding the static model left undecided."""
finding_id: str
family: str
rung: str
path: str
line: int | None = None
@dataclass(frozen=True)
class Outcome:
"""What the tier concluded. ``rung`` is ``None`` whenever nothing was established."""
rung: Rung | None
reason: str
class ExecutionBackend(Protocol):
def available(self) -> bool: ...
def reproduce(self, candidate: Candidate) -> bool: ...
@dataclass
class NullExecutionBackend:
"""No adopted tool present. The normal case, and not an error."""
def available(self) -> bool:
return False
def reproduce(self, candidate: Candidate) -> bool:
del candidate
return False
def eligible(candidate: Candidate) -> bool:
"""Is this candidate one the execution tier should even look at?"""
return candidate.family in EXECUTION_FAMILIES and candidate.rung in UNDECIDED
def confirm(candidate: Candidate, *, backend: ExecutionBackend | None = None) -> Outcome:
"""Escalate one undecided candidate to the adopted execution tier, if there is one."""
if not eligible(candidate):
return Outcome(
rung=None,
reason=f"not_eligible: family {candidate.family!r} at rung {candidate.rung!r} is arbitrated statically",
)
engine = backend if backend is not None else resolve_execution_backend()
if not engine.available():
return Outcome(rung=None, reason="clearwing_unavailable: no adopted execution tier on this machine")
if not engine.reproduce(candidate):
# Deliberate wording: this is not a refutation. Failing to trigger a bug is not showing it is absent.
return Outcome(rung=None, reason="not_reproduced: the attempt did not trigger it; the finding is unchanged")
return Outcome(rung=Rung.EXECUTION_CONFIRMED, reason="reproduced in the adopted sandbox")
def resolve_execution_backend() -> ExecutionBackend:
"""The adopted tier for this machine. Absent by default; the environment flag is what the matrix drives."""
flag = os.environ.get(CLEARWING_ENV, "").strip().lower()
if flag in _OFF or flag not in _ON:
return NullExecutionBackend()
return NullExecutionBackend() # the adopted tool is wired here when a class needs it (Req 10.1)
__all__ = [
"CLEARWING_ENV",
"EXECUTION_FAMILIES",
"Candidate",
"ExecutionBackend",
"NullExecutionBackend",
"Outcome",
"confirm",
"eligible",
"resolve_execution_backend",
]
+116
View File
@@ -0,0 +1,116 @@
"""model-grounded-detection task 6.1: the execution tier is deferred, adopted, and narrow (Req 10).
The rung this project does NOT build. Clearwing already runs sandboxes, container pools, sanitizer images and
PoC stability, and this session's own history says reimplementing that class of machinery is where we go
wrong. So `execution_confirmed` exists as a rung, the seam calls an adopted tool, and the eligibility rule is
deliberately narrow: only a finding the static model could not decide, in a family a static model genuinely
cannot arbitrate.
Everything here runs with Clearwing absent, which is the normal case.
"""
from __future__ import annotations
import pytest
def _finding(family="memory", rung="suspicion"): # type: ignore[no-untyped-def]
from openultrasast.model.execution import Candidate
return Candidate(finding_id="f1", family=family, rung=rung, path="a.c", line=10)
def test_only_a_family_a_static_model_cannot_arbitrate_is_eligible() -> None:
"""Req 10.3: no web/logic class depends on this tier. They have taint, dominance and constant abstraction."""
from openultrasast.model.execution import eligible
assert eligible(_finding(family="memory")) is True
for family in ("injection", "access_control", "path", "config_secrets", "output_encoding"):
assert eligible(_finding(family=family)) is False, f"{family} must be arbitrated statically"
def test_a_finding_the_model_already_decided_is_not_escalated() -> None:
"""Req 10.1: the tier is reached only where the model could not decide -- never to double-check itself."""
from openultrasast.model.execution import eligible
assert eligible(_finding(rung="suspicion")) is True
assert eligible(_finding(rung="model_entailed")) is False
assert eligible(_finding(rung="model_corroborated")) is False
def test_without_clearwing_the_rung_is_never_reached_and_the_reason_is_recorded(monkeypatch: pytest.MonkeyPatch) -> None:
"""Req 11.3: an absent capability degrades to a recorded reason, never a traceback and never a verdict."""
from openultrasast.model.execution import confirm, resolve_execution_backend
monkeypatch.setenv("OPENULTRASAST_CLEARWING", "off")
backend = resolve_execution_backend()
assert backend.available() is False
outcome = confirm(_finding(), backend=backend)
assert outcome.rung is None, "no engine, no rung"
assert "clearwing_unavailable" in outcome.reason
def test_an_ineligible_finding_is_not_sent_to_the_sandbox_even_when_one_exists() -> None:
from openultrasast.model.execution import confirm
class _Backend:
def __init__(self) -> None:
self.calls = 0
def available(self) -> bool:
return True
def reproduce(self, candidate: object) -> bool:
self.calls += 1
return True
backend = _Backend()
outcome = confirm(_finding(family="injection"), backend=backend)
assert outcome.rung is None and backend.calls == 0
assert "not_eligible" in outcome.reason
def test_a_reproduced_candidate_reaches_execution_confirmed() -> None:
from openultrasast.model.execution import confirm
from openultrasast.model.ladder import Rung
class _Backend:
def available(self) -> bool:
return True
def reproduce(self, candidate: object) -> bool:
return True
assert confirm(_finding(), backend=_Backend()).rung is Rung.EXECUTION_CONFIRMED
def test_a_candidate_that_does_not_reproduce_stays_where_it_was() -> None:
"""Not reproducing is not a refutation: the sandbox failing to trigger a bug does not prove its absence."""
from openultrasast.model.execution import confirm
class _Backend:
def available(self) -> bool:
return True
def reproduce(self, candidate: object) -> bool:
return False
outcome = confirm(_finding(), backend=_Backend())
assert outcome.rung is None
assert "not_reproduced" in outcome.reason and "refut" not in outcome.reason.lower()
def test_the_seam_reimplements_no_sandbox_machinery() -> None:
"""Req 10.2, asserted structurally. The one thing this module must not grow is a sandbox."""
import ast
from pathlib import Path
source = Path("src/openultrasast/model/execution.py").read_text()
tree = ast.parse(source)
imported = {n.module.split(".")[0] for n in ast.walk(tree) if isinstance(n, ast.ImportFrom) and n.module}
imported |= {a.name.split(".")[0] for n in ast.walk(tree) if isinstance(n, ast.Import) for a in n.names}
for banned in ("docker", "podman", "subprocess", "container", "sandbox"):
assert banned not in imported, f"the execution tier must adopt, not build: {banned}"
names = {n.name for n in ast.walk(tree) if isinstance(n, ast.FunctionDef)}
for banned in ("build_image", "run_container", "compile_target", "apply_patch"):
assert banned not in names, f"{banned} belongs to the adopted tool, not here"