Skip to content

v2.6.0 — Phase 2B: Analyst Copilot + DAG Parallel + Calibration

Choose a tag to compare

@R00T-Kim R00T-Kim released this 13 Apr 10:12

Phase 2B Release

SCOUT v2.6.0 delivers three axes of change that position it as a single-firmware analyst copilot: performance (DAG parallelization PoC), analyst UX (reasoning trail + MCP override loop), and honest confidence calibration (detection vs priority separation).

Merged via PR #6 (rebase) as 6 atomic commits — any one could ship independently.

1. DAG Parallelization PoC (PR #10)

  • New stage_dag.py with manual STAGE_DEPS (42 entries) + Kahn topo_levels() (15 levels, max-width 7)
  • run_stages_parallel() — ThreadPoolExecutor level-wise submit, skip-on-failed-dep, fail_fast=True/False modes. Sequential run_stages() unchanged
  • New CLI flag: --experimental-parallel [N] (default 4 workers) on both analyze and stages subcommands
  • ProgressTracker(out_of_order=True) for completion-order rendering in parallel mode
# Opt-in parallel execution
./scout analyze firmware.bin --experimental-parallel 4

2. Reasoning Trail Persistence (PR #11 + PR #13)

New reasoning_trail.py module captures structured ReasoningEntry records for LLM-driven finding adjustments. The adversarial_triage debate loop now records advocate / critic / decision entries with llm_model and 200-char raw_response_excerpt. The fp_verification pattern matcher records sanitizer / non-propagating / sysfile hits with per-pattern delta.

All three analyst surfaces expose the trail:

  • Web viewer — collapsible <details> section with CSS styling
  • Analyst markdown report — numbered "Reasoning Trail (N steps)" subsection per finding
  • TUI finding detailrender_finding_detail_with_trail() (AIEDGE_TUI_ASCII-compatible)

SARIF properties bag gains scout_reasoning_trail.

3. MCP Analyst Tools (PR #12)

4 new MCP tools for analyst-driven feedback:

Tool Purpose
scout_get_finding_reasoning Fetch full reasoning trail for a finding
scout_inject_hint Push an analyst hint into the feedback registry
scout_override_verdict Force-set a finding verdict (confirmed / false_positive / wont_fix / needs_info)
scout_filter_by_category Filter findings by vulnerability / misconfiguration / pipeline_artifact

terminator_feedback.py extended with add_analyst_hint / get_analyst_hints / set_verdict_override (fcntl.flock-safe, assert_under_dir enforced). The adversarial_triage advocate prompt now reads analyst hints from AIEDGE_FEEDBACK_DIR and prefixes them priority-sorted — opt-in; byte-identical behavior when env var unset.

4. Detection vs Priority Calibration (PR #15)

Closes external reviewer critique that EPSS-additive confidence made SCOUT's confidence field look like a ranking heuristic instead of a true-positive probability.

New scoring.py with:

@dataclass(frozen=True)
class PriorityInputs:
    detection_confidence: float
    epss_score: float | None
    epss_percentile: float | None
    reachability: str | None
    backport_present: bool
    cvss_base: float | None

def compute_priority_score(inputs: PriorityInputs) -> float:
    # Weights: detection 50% / EPSS 25% / reach 15% / CVSS 10%
    # Backport: -0.20 penalty

cve_scan.py:1140-1170 refactored: confidence now strictly capped at STATIC_CODE_VERIFIED_CAP=0.55 (static evidence only). EPSS / reachability / backport / CVSS now feed priority_score instead.

New doc: docs/scoring_calibration.md with a before/after worked example.

5. Extraction Failure Analyst Guidance (PR #14)

When extraction fails, SCOUT now emits a structured guidance block pointing the analyst at concrete next steps:

Detected encryption (entropy 7.95/8.0). Possible vendor decryption needed.
Suggested actions:
  1. Check vendor_decrypt.py for known vendor formats and add a handler for this firmware.
  2. Provide a pre-extracted rootfs: ./scout analyze firmware.bin --rootfs /path/to/extracted
  3. Try binwalk v3 entropy mode / alternative extractor: binwalk --entropy firmware.bin
  4. File an issue with the first 4 KB hex dump: xxd firmware.bin | head -64
Hint: docs/runbook.md#extraction-failure

New docs/runbook.md#extraction-failure section with symptoms/causes/remediation table.

Verification

Metric v2.5.0 v2.6.0
pytest 865 1027 passed, 1 skipped (+162)
pyright 0 errors 0 errors, 0 warnings (baseline preserved)
ruff clean clean
CI 5/5 green 5/5 green

New test distribution: reasoning_trail 20 · extraction_guidance 18 · mcp_analyst_tools 33 · stage_dag 14 · run_stages_parallel 14 · scoring 19 · reasoning_trail_viewer 44

R7000 smoke test (PR #15): 3 findings, all carrying priority_score + priority_inputs. cve_confidence_above_0.55_cap = 0 (detection cap enforced). priority_bucket_counts = {critical: 0, high: 0, medium: 3, low: 0}.

Design Invariants Preserved

  • Additive-only on findings.py (PR #7a pattern continues for category, now reasoning_trail, priority_score, priority_inputs). No report schema version bump. All 7 downstream consumers untouched.
  • Sequential run_stages() bit-identical to pre-PR state.
  • StageContext frozen invariant preserved (thread-safe sharing without locks).
  • All file writes continue through assert_under_dir().
  • v2.5.0 LLM driver contracts (system_prompt, temperature, 5-stage parser) unchanged.
  • 200-char raw_response_excerpt cap enforced at ReasoningEntry.__post_init__ (cannot be bypassed by call sites).

Deferred to Phase 2C

  • Wall-clock comparison sequential vs --experimental-parallel 4 on R7000 (PoC merged, real firmware measurement pending)
  • Analyst hint injection loop smoke with real LLM driver + AIEDGE_FEEDBACK_DIR
  • Benchmark freeze rule enforcement (check_baseline_metadata wiring requires fresh corpus baseline)

Upgrade Notes

Breaking: confidence field semantics changed for CVE findings — it is now strictly detection evidence (≤0.55). Consumers previously ranking by confidence should migrate to priority_score. See docs/scoring_calibration.md for the full contract.

Everything else is additive; existing consumers that ignore the new fields continue to work unchanged.


Full diff: v2.5.0...v2.6.0
PR #6: #6

🤖 Generated with Claude Code