{# Defensive defaults — placed BEFORE the render-mode gate. Console-shell pattern from C.1 round-2 M1-2 / C.2 round-2 M1-2 / D round-1 M1-2 (3/3 critical). #} {% set summary = summary | default({}) %} {% if summary is string or summary is not mapping %}{% set summary = {} %}{% endif %} {% set candidates = candidates | default([]) %} {% if candidates is mapping or candidates is string or candidates is not iterable %}{% set candidates = [] %}{% endif %} {% set identity_assertions = identity_assertions | default([]) %} {% if identity_assertions is mapping or identity_assertions is string or identity_assertions is not iterable %}{% set identity_assertions = [] %}{% endif %} {% set ai_component_prompts = ai_component_prompts | default([]) %} {% if ai_component_prompts is mapping or ai_component_prompts is string or ai_component_prompts is not iterable %}{% set ai_component_prompts = [] %}{% endif %} {% import "_console_macros.html" as fs with context %} {% if render_mode != 'fragment' %} {% if domain %}{% endif %} False Positive Analysis — {{ project_label or folder_name or recipe_name }} {# Recipe is chart-free (server-side chart specs via output.charts; no inline emission). #} {% include "_design_system.html" %} {% include "_console_shell.html" %} {% endif %} {# Recipe-local styles — render in BOTH standalone and fragment modes so fragment_extractor (_STYLE_RE) auto-scopes under .fs-section-false-positive-analysis. All hex literals migrated to design tokens. #} {% if render_mode != 'fragment' %} {% endif %} {# Build topbar meta items. #} {% set fp_meta = [{"label": "Domain", "value": domain or "—"}] %} {% if project_label %}{% set _ = fp_meta.append({"label": "Project", "value": project_label}) %}{% endif %} {% if folder_name %}{% set _ = fp_meta.append({"label": "Folder", "value": folder_name}) %}{% endif %} {% set _ = fp_meta.append({"label": "Generated", "value": generated_at or "—"}) %} {% if render_mode != 'fragment' %} {{ fs.topbar( crumbs=["Finite State", "False Positive Analysis"], meta=fp_meta, controls=[], ) }} {% endif %}

False Positive Analysis

Component identity + finding-level FP detection

{# 4 KPI cells via fs.kpi_cell. #}
{{ fs.kpi_cell("Open Findings", summary.get('total_open_findings', 0) if summary is mapping else 0) }} {{ fs.kpi_cell( "FP Candidates", summary.get('fp_candidates_found', 0) if summary is mapping else 0, dot=("low" if (summary is mapping and summary.get('fp_candidates_found', 0) > 0) else None), ) }} {{ fs.kpi_cell( "Mechanical Detections", summary.get('mechanical_detections', 0) if summary is mapping else 0, dot=("high" if (summary is mapping and summary.get('mechanical_detections', 0) > 0) else None), ) }} {{ fs.kpi_cell( "AI Detections", summary.get('ai_detections', 0) if summary is mapping else 0, dot=("info" if (summary is mapping and summary.get('ai_detections', 0) > 0) else None), ) }}
{# Component Identity Assertions section. Field names come from the transform return at false_positive_analysis.py:806-816 — likely_product, nvd_product, evidence, confidence (NOT verdict/rationale). #} {% if identity_assertions and identity_assertions | length > 0 %}

Component Identity Assertions

{{ identity_assertions | length }} component(s) detected as misidentified relative to NVD. Each block summarises the scanned vs. expected product and lists the per-CVE verdicts.

{% for a in identity_assertions %} {% if a is mapping %}
{{ a.component_name }} {{ a.component_version }} — scanned as {{ a.likely_product or '?' }}, NVD expected {{ a.nvd_product or '?' }} MISMATCHED confidence: {{ a.confidence or 'medium' }}

Evidence: {{ a.evidence or '—' }}

{% if a.cve_verdicts and a.cve_verdicts | length > 0 %} {% for cv in a.cve_verdicts %} {% if cv is mapping %} {% endif %} {% endfor %}
CVE Verdict Rationale Recommended VEX
{{ cv.cve_id }} {% if cv.verdict == 'does_not_apply' %} does_not_apply {% else %} might_still_apply {% endif %} {{ cv.rationale or '—' }} {% if cv.verdict == 'does_not_apply' %} NOT_AFFECTED / CODE_NOT_PRESENT {% else %} Review individually {% endif %}
{% endif %}
{% endif %} {% endfor %}
{% endif %} {# Residual FP Candidates section. #}

Residual FP Candidates

Findings on components whose identity was confirmed or ambiguous, flagged as likely FP by finding-level applicability analysis.

{% if candidates and candidates | length > 0 %} {% for row in candidates %} {% if row is mapping %} {% endif %} {% endfor %}
CVE Component Severity Confidence Signals Reason / AI Rationale Action
{{ row.cve_id or row.finding_id or '—' }} {{ row.component_name or '—' }} {{ row.component_version or '' }} {{ row.severity or 'UNKNOWN' }} {{ row.fp_confidence or '—' }} {# fp_signals can be string (transform's default — comma-joined at false_positive_analysis.py:895) OR list (defensive — the pre-migration template handles both). Preserve both branches. #} {% if row.fp_signals %} {% if row.fp_signals is string %} {% for sig in row.fp_signals.split(',') %} {{ sig | trim }} {% endfor %} {% else %} {% for sig in row.fp_signals %} {{ sig }} {% endfor %} {% endif %} {% else %} — {% endif %} {# primary_reason visible by default; AI verdict + rationale collapsible via
(pre-migration two-tier pattern). #} {{ row.primary_reason or '—' }} {% if row.ai_rationale %}
AI details
Verdict: {{ row.ai_verdict or '—' }}
{{ row.ai_rationale }}
{% endif %}
{{ row.recommended_action or 'Review' }}
{% else %}

No residual FP candidates.

{% endif %}
{# Component Identity Prompts section (air-gapped --ai-prompts workflow). Iterates `ai_component_prompts` (NOT ai_triage_prompts) — false_positive_analysis.py builds per-component identity prompts as the user-facing copy-paste workflow. Each entry has `component` + `prompt` fields. #} {% if ai_component_prompts and ai_component_prompts | length > 0 %}

Component Identity Prompts

{{ ai_component_prompts | length }} prompt(s) for offline LLM review. Paste each into an external model; if the answer is IDENTITY: mismatched, run the per-CVE applicability fan-out using the LIKELY_PRODUCT and NVD_PRODUCT values. These prompts are also written to False Positive Analysis_prompts.md alongside this report.

{% for p in ai_component_prompts %} {% if p is mapping %}
{{ p.component }}
{{ p.prompt }}
{% if render_mode != 'fragment' %} {% endif %}
{% endif %} {% endfor %}
{% endif %} {# Detection by Signal Type section. #} {% if summary is mapping and summary.get('by_signal_type') is mapping %}

Detection by Signal Type

{% for signal, count in summary.by_signal_type.items() %} {% endfor %}
SignalCount
{{ signal }} {{ count }}
{% endif %}
{% if render_mode != 'fragment' %} {{ fs.status_bar(items=[ "Recipe: False Positive Analysis", "Open: " ~ ((summary.get('total_open_findings', 0) if summary is mapping else 0) | string), "FP Candidates: " ~ ((summary.get('fp_candidates_found', 0) if summary is mapping else 0) | string), generated_at | default(''), ], version='fs-report ' ~ (fs_report_version | default('dev'))) }} {% endif %} {% if render_mode != 'fragment' %} {% include '_action_buttons.html' %} {% endif %}