Commit Graph
3 Commits
Author SHA1 Message Date
Marius CiepluchandClaude Opus 5 52f2ab5b4d fix(model-grounded-detection): ask the residual question the arbiter actually raised
The corrected re-measure returned numbers IDENTICAL to the buggy one, which was
the clue. Routing was fixed, the dominance arbiter was reached, and the finding
was discarded anyway -- because every corroboration was put to the judge as a
TAINT question: "a sanitizer appears on the path: yes, does it suffice?".

For a missing authorization guard that question is meaningless. The judge
answers no to something that does not apply and the claim is dropped. All three
vibe-py access_control pairs scored both_silent this way even though the
dominance arbiter had returned model_corroborated for each of them, which I had
verified by hand earlier in the session.

Fourth instance in this feature of one shape: taint-specific behaviour applied
to every family. Sanitizer matching, config routing, family dispatch, now the
residual question. Each was exposed by a measurement rather than by a check.

The question is now phrased for the arbiter that raised it -- a guard asymmetry
for dominance, a permissive setting for constant abstraction, sanitizer
sufficiency only for taint.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
2026-09-08 18:19:18 +02:00
Marius CiepluchandClaude Opus 5 7a76fcb028 fix(model-grounded-detection): the pipeline arbitrated only flow families
scan_region took a TaintSpec and called taint_verdict, so access_control and
config_secrets -- whose dominance and constant-abstraction arbiters have worked
since group 4 -- had no pipeline path at all. On the first end-to-end vibe-py
run every one of their pairs scored `both_silent`, which reads as the model
failing when in fact no code reached the arbiter.

This is the same class as the ceiling harness routing config_secrets through
taint: family routing fixed in one place and not carried to the other. Third
time this shape has appeared in this feature, which is worth saying plainly.

Dispatch is on the spec TYPE rather than a family name, so a family without an
arbiter cannot be silently routed to the wrong one -- it simply has no spec and
is skipped, visibly.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
2026-09-08 17:53:56 +02:00
Marius CiepluchandClaude Opus 5 cdedb372dd feat(model-grounded-detection): wire the detector -- the enumerator proposes, the model disposes
Everything before this built an ARBITER: something that judges a flow taint
reachability had already found unaided. Nothing proposed to it. That is why its
recall was never comparable to a detector's, and why comparing 41.3% entailment
against the LLM hunter's 76.7% pair-correct was comparing two different kinds
of thing. model/judge.py and enumerate_candidates were called by no production
code at all; every number so far came from a measurement harness.

The wiring turns on a distinction judge() alone conflated:

  the model CONTRADICTS    it has coverage at this site and says no -- a
                           sanitizer on the path, or a declared-safe sink shape.
                           The claim is dropped (Req 8.2).
  the model CANNOT DECIDE  no modelled sink or source reaches the site at all.
                           The model is SILENT, not negative, so the claim is
                           reported at `suspicion` (Req 8.4).

Treating silence as refutation is the tempting mistake and would be wrong here:
23 of the 39 misses in the entailment ceiling were sinks simply absent from the
fact tables, so "no flow" usually means the model cannot see it rather than
that nothing is there. The rung carries that uncertainty on the finding's face
instead of a confidence score nobody can act on.

An entailed site still costs zero model calls. The candidate budget is bounded
so a dense region cannot become an unbounded spend.

Smoke-tested end to end against a live endpoint: 2 pairs, detection 100%,
$0.0024. The full vibe-py measurement -- the first like-for-like comparison
with the hunter's 76.7% pair-correct and 12.3% leak -- is running.

727 passing, mypy/ruff clean, zero orphaned modules.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
2026-09-08 17:41:45 +02:00