feat(model-grounded-detection): tasks 2.1-2.2, the Joern seam and the taint verdict

The whole engine integration is one subprocess boundary: joern-parse builds a
cpg.bin, joern --script runs a shipped CPGQL query that prints its JSON between
fence markers, because Joern's stdout carries a banner and a REPL prompt around
whatever a script emits. Nothing is imported in-process, so the core install
keeps dependencies = [] -- a test walks the seam's AST to assert it imports
only the standard library and names no JVM binding.

Fail closed everywhere. A build or query that errors, times out, or prints
something unparseable yields no verdict and the caller reports suspicion. The
taint verdict distinguishes this from absence deliberately: a query returning
None means "the engine could not decide", which is not "there is no flow", and
conflating them is how a missing engine silently becomes a clean bill of health.

The verdict is where the ladder earns its keep. An unsanitized source->sink
path is model_entailed -- the graph establishes it and the LLM's claim is no
longer load-bearing. A path a sanitizer may break is model_corroborated: the
flow is real, but whether the sanitizer suffices is the semantic residual the
LLM answers, checked against this verdict rather than averaged over runs. The
chosen flow is picked by a total order (shortest, then lexicographic), so two
runs over one CPG cannot disagree -- Req 6.4 asserted directly.

The query itself is the part our flat IR could not do: reachableByFlows walks
the PDG, so `q = "..." + request.args["x"]; execute(q)` is found, which is
exactly the one-hop limit that held measured entailment at 2.2%.

Capability detection reuses semantic/engines.joern_available rather than
growing a second notion of "installed". The audit manifest is regenerated; the
new modules are named by Req 4/5/6 rather than counted as orphans.

Task 2.3, the go/no-go measurement, needs Joern installed and has not run.

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 12:23:40 +02:00
co-authored by Claude Opus 5
parent 9ed0e45c5f
commit 2b973dc0db
10 changed files with 632 additions and 5 deletions
@@ -1,13 +1,13 @@
{
"counts": {
"load_bearing": 74,
"load_bearing": 79,
"standalone_capability": 7
},
"generated": "2026-09-08",
"generated": "2026-09-08 (regenerated after group 2 added the cpg/ seam)",
"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": 81,
"modules": 86,
"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": {
@@ -124,6 +124,31 @@
"module": "config",
"reason": "reachable from gate, map_gate, pair_gate or the CLI"
},
{
"classification": "load_bearing",
"importers": [
"cpg.backend",
"model.taint"
],
"module": "cpg",
"reason": "model-grounded-detection Req 4: the CPG seam package"
},
{
"classification": "load_bearing",
"importers": [
"model.taint"
],
"module": "cpg.backend",
"reason": "model-grounded-detection Req 4.1/4.5: the single Joern subprocess boundary"
},
{
"classification": "load_bearing",
"importers": [
"cpg.backend"
],
"module": "cpg.capability",
"reason": "model-grounded-detection Req 4.2/4.3: the engine probe that degrades to suspicion"
},
{
"classification": "load_bearing",
"importers": [
@@ -295,7 +320,8 @@
"classification": "load_bearing",
"importers": [
"cli",
"model.specs"
"model.specs",
"model.taint"
],
"module": "model",
"reason": "reachable from gate, map_gate, pair_gate or the CLI"
@@ -322,10 +348,26 @@
},
{
"classification": "load_bearing",
"importers": [],
"importers": [
"model.taint"
],
"module": "model.ladder",
"reason": "model-grounded-detection Req 5: the evidence ladder every finding carries"
},
{
"classification": "load_bearing",
"importers": [
"model.taint"
],
"module": "model.specs",
"reason": "model-grounded-detection Req 7.2-7.4: the security vocabularies the CPG queries are parameterised by"
},
{
"classification": "load_bearing",
"importers": [],
"module": "model.taint",
"reason": "model-grounded-detection Req 6.1: taint reachability over the CPG, the flow-family arbiter"
},
{
"classification": "load_bearing",
"importers": [
@@ -598,6 +640,7 @@
"classification": "load_bearing",
"importers": [
"cli",
"cpg.capability",
"hunter_tools",
"model.candidates",
"model.specs",
@@ -627,6 +670,7 @@
{
"classification": "load_bearing",
"importers": [
"cpg.capability",
"semantic",
"semantic.overlay"
],