feat(three-stage-scan): select bounded regress candidates with sev-5 extras

This commit is contained in:
Marius Ciepluch
2026-09-03 22:36:02 +02:00
parent eb87ef85ec
commit 7a584d4578
4 changed files with 220 additions and 4 deletions
+2 -1
View File
@@ -1,6 +1,6 @@
"""Isolated regression snippets and verdicts."""
from .candidate import INCONCLUSIVE, SAFETY_REJECTED, RegressionRunner, RegressionVerdict
from .candidate import INCONCLUSIVE, SAFETY_REJECTED, RegressionRunner, RegressionVerdict, select_candidates
from .safety import UnsafeSnippetError, check_snippet_safety
__all__ = [
@@ -10,4 +10,5 @@ __all__ = [
"RegressionVerdict",
"UnsafeSnippetError",
"check_snippet_safety",
"select_candidates",
]
+57 -1
View File
@@ -1,9 +1,13 @@
"""Safety-gated regression execution (task 4.3)."""
"""Candidate selection and safety-gated regression execution."""
from __future__ import annotations
from collections.abc import Mapping, Sequence
from dataclasses import dataclass
from ..complexity.ledger import hotspot_key, select_forced_candidates
from ..complexity.map import Hotspot
from ..findings import StaticFinding
from ..sandbox import SandboxJob, SandboxResult, SandboxRunner
from .safety import UnsafeSnippetError, check_snippet_safety
@@ -13,6 +17,58 @@ TRIGGERABLE = "triggerable"
NOT_TRIGGERABLE = "not_triggerable"
def select_candidates(
hotspots: Sequence[Hotspot],
findings: Sequence[StaticFinding],
*,
max_candidates: int,
policy_severity_by_id: Mapping[str, object] | None = None,
rule_cwe: Mapping[str, str] | None = None,
) -> tuple[Hotspot, ...]:
"""Select min(max_candidates, ranked hotspots) ∪ sev-5 reachable inventory.
The cap applies to the ranked hotspot slice. Forced policy-severity-5
reachable (or inferred-file-surface) inventory stays in the set even when a
ledger overlay demoted its hotspot out of that slice.
"""
ranked = tuple(sorted(hotspots, key=lambda item: (-item.score, item.path, item.function_name or "")))
selected = list(ranked[: max(max_candidates, 0)])
seen = {hotspot_key(item.path, item.function_name) for item in selected}
extras: list[Hotspot] = []
for finding in select_forced_candidates(findings, policy_severity_by_id or {}, rule_cwe=rule_cwe):
hotspot = _hotspot_for_finding(finding, ranked) or _hotspot_from_forced_finding(finding)
key = hotspot_key(hotspot.path, hotspot.function_name)
if key in seen:
continue
seen.add(key)
extras.append(hotspot)
return tuple(selected + extras)
def _hotspot_for_finding(finding: StaticFinding, hotspots: Sequence[Hotspot]) -> Hotspot | None:
for hotspot in hotspots:
if finding.finding_id in hotspot.inventory_finding_ids:
return hotspot
key = hotspot_key(finding.path, finding.function_name)
for hotspot in hotspots:
if hotspot_key(hotspot.path, hotspot.function_name) == key:
return hotspot
return None
def _hotspot_from_forced_finding(finding: StaticFinding) -> Hotspot:
return Hotspot(
path=finding.path,
function_name=finding.function_name,
score=0.0,
band="low",
signals={},
rationale="forced reachable severity-5 inventory",
test_hint=None,
inventory_finding_ids=(finding.finding_id,),
)
@dataclass(frozen=True)
class RegressionVerdict:
verdict: str