feat(model-grounded-detection): 4.2 constant abstraction, the third arbiter form

A configuration bug has no flow to follow and no guard to dominate.
CORS(app, origins="*") is dangerous because of the value it is SET TO, so the
arbiter evaluates the setting's arguments against the closed permissive set in
the obligation facts -- the third form beside taint reachability and guard
dominance, and the one Req 6.3 names.

  ENTAILED      a security setting is passed a literal in the permissive set
  CORROBORATED  the argument is computed, so constant abstraction cannot decide
                it -- that residual is the judge's, never silently "safe"
  (none)        every literal is outside the set, or the call is not a setting

Two Joern node-shape bugs, both found by running it and both of the same class
as group 2's receiver bug -- the graph's indexing is not what the source text
suggests:

  * a keyword argument (`origins="*"`) is an assignment-shaped node, so
    isLiteral is false on the argument itself and the literal sits in its
    subtree; literals are collected from the argument's AST now.
  * Joern indexes the receiver at 0, positional arguments from 1, and NAMED
    arguments at -1. Settings are configured overwhelmingly by keyword, so
    argumentIndexGt(0) -- correct when counting arity for the taint shape test
    -- dropped exactly the arguments that matter and every keyword-configured
    setting read as "computed".

Live, deterministic, zero model calls:
  create_app -> model_entailed  CORS(app, origins = "*"): permissive literal "*"
  safe_app   -> no finding      (origins = "https://app.example")

All three arbiter forms now work against a real CPG: taint reachability for the
flow families, guard dominance for absence, constant abstraction for config.

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 15:00:41 +02:00
co-authored by Claude Opus 5
parent fec67253f3
commit d9ceeb6a09
6 changed files with 245 additions and 3 deletions
@@ -1,13 +1,13 @@
{
"counts": {
"load_bearing": 81,
"load_bearing": 82,
"standalone_capability": 7
},
"generated": "2026-09-08 (regenerated after group 4 added the dominance arbiter)",
"generated": "2026-09-08 (regenerated after group 4: dominance and constant abstraction)",
"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": 88,
"modules": 89,
"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": {
@@ -128,6 +128,7 @@
"classification": "load_bearing",
"importers": [
"cpg.backend",
"model.config_value",
"model.dominance",
"model.judge",
"model.taint"
@@ -138,6 +139,7 @@
{
"classification": "load_bearing",
"importers": [
"model.config_value",
"model.dominance",
"model.judge",
"model.taint"
@@ -326,6 +328,7 @@
"importers": [
"cli",
"model.candidates",
"model.config_value",
"model.dominance",
"model.judge",
"model.specs",
@@ -348,6 +351,12 @@
"module": "model.candidates",
"reason": "reachable from gate, map_gate, pair_gate or the CLI"
},
{
"classification": "load_bearing",
"importers": [],
"module": "model.config_value",
"reason": "model-grounded-detection Req 6.3: constant abstraction for the configuration families"
},
{
"classification": "load_bearing",
"importers": [],
@@ -369,6 +378,7 @@
{
"classification": "load_bearing",
"importers": [
"model.config_value",
"model.dominance",
"model.judge",
"model.taint"
@@ -379,6 +389,7 @@
{
"classification": "load_bearing",
"importers": [
"model.config_value",
"model.dominance",
"model.judge",
"model.taint"