feat(model): one defect is one finding, however many regions reach it

contributor-scan 2.9. Task 2.4 let a region's question follow the call
graph, and the moment it did, many entry points could reach one shared
sink: libpng reported the same site twenty-six times. A contributor shown
the same defect twenty-six times learns to scroll past it.

Findings are deduplicated on (site, family), keeping the strongest rung
and counting the regions that reached it -- "reached from 26 regions" is
the useful half of that observation and one row is the readable half. Two
families at one site stay two findings, because `echo $_GET[...]` is an
injection question and an output-encoding question with different answers.

The duplication that motivated this was removed by another route: the 26
rows were all the `fgets`-matched-as-`gets` false positive, and the sink
matcher fix took them out. So this changes no current number and is a
structural guarantee rather than a measured reduction -- the mechanism that
produced them is untouched, and only the finding that made it visible is
gone.

+25 lines for a guarantee, in a session that has been asked to watch its
growth. The audit is unchanged at 97 modules, 90 load-bearing and 7
standalone, with no orphans.

Gates byte-identical.

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-09 15:56:01 +02:00
co-authored by Claude Opus 5
parent 60d2a1a92c
commit 47b00d739b
5 changed files with 79 additions and 4 deletions
+12 -1
View File
@@ -969,6 +969,17 @@ def _run_model_layer(
return findings, _model_payload(result, unjudged_paths=unjudged, coverage=coverage)
def _model_rationale(item: object, witness: str, family: str) -> str:
"""The witness, plus how many entry points reach this site when more than one does.
A site reached from twenty-six entry points is one defect with a wide blast radius, which is worth
saying once. It used to be said twenty-six times.
"""
base = witness or f"the model layer reported a {family} candidate"
reached = int(getattr(item, "reached_from", 1) or 1)
return base if reached <= 1 else f"{base} (reached from {reached} regions)"
def _finding_from_model(item: object) -> StaticFinding:
"""A model finding as a StaticFinding, carrying its rung and witness (Req 5.1)."""
site = str(getattr(item, "site", ""))
@@ -984,7 +995,7 @@ def _finding_from_model(item: object) -> StaticFinding:
severity="medium",
confidence="medium",
evidence_level="suspicion",
rationale=witness or f"the model layer reported a {family} candidate",
rationale=_model_rationale(item, witness, family),
line=int(line) if line.isdigit() else None,
function_name=function or None,
reachability_status="unknown",