{% if render_mode != 'fragment' %} {% if domain %}{% endif %} Scan Quality Report - Finite State Report {# ECharts library — replaces Chart.js v4.4.1 + the legacy datalabels plugin from the pre-migration template. ECharts has native series.label.formatter for the percentage labels the datalabels plugin used to provide. #} {% include "_design_system.html" %} {% include "_console_shell.html" %} {% include "_echarts_ready.html" %} {% endif %} {# Recipe-local styles — render in BOTH standalone and fragment modes so fragment_extractor (_STYLE_RE) collects them, scopes under .fs-section-scan-quality, and re-emits at the top of the fragment. #} {% if render_mode != 'fragment' %} {% endif %} {% import "_console_macros.html" as fs with context %} {# Defensive defaults — keeps the template renderable when the upstream transform short-circuited (e.g. empty data). Mirrors license_report.html. #} {% set summary = summary | default({}) %} {% if not summary is mapping %}{% set summary = {} %}{% endif %} {% set charts = charts | default({}) %} {% if not charts is mapping %}{% set charts = {} %}{% endif %} {% set summary_table = summary_table | default([]) %} {% set detail_table = detail_table | default([]) %} {% set thresholds = thresholds | default({'fresh': 30, 'aging': 90, 'stale': 365}) %} {# Reachability-coverage convenience locals. #} {% set rc = summary.get('reachability_coverage', {'with_reachability': 0, 'binary_projects': 0, 'source_only_projects': 0}) %} {% set rc_total = (rc.get('with_reachability', 0) | int) + (rc.get('binary_projects', 0) | int) %} {# Count "Fair" / "Poor" unpack ratings for the Unpack Issues KPI cell — only relevant when unpack data is available. #} {% set unpack_issue_count = namespace(val=0) %} {% if summary_table %} {% for row in summary_table %} {% if row.unpack_rating is defined and row.unpack_rating in ('Fair', 'Poor') %} {% set unpack_issue_count.val = unpack_issue_count.val + 1 %} {% endif %} {% endfor %} {% endif %} {# `has_unpack_data` = the KPI cell gate (matches pre-migration template's `charts.unpack_rating_distribution is defined` — shows the cell even when the chart payload has empty labels; round-1 M1-8). #} {% set has_unpack_data = (charts.unpack_rating_distribution is defined) %} {# `has_unpack_chart` = the chart-render gate (only render the chart when actual labels exist, to avoid empty-canvas / empty-SVG output). #} {% set has_unpack_chart = has_unpack_data and (charts.unpack_rating_distribution.labels | default([]) | length > 0) %} {# Per-section-scoped table IDs so two console recipes in a compound bundle don't collide on `getElementById(summary_table_id)` — round-1 M1-4 / A.3 compound-bundle namespacing pattern. #} {% set summary_table_id = fragment_scope_class ~ '-summaryTable' %} {% set detail_table_id = fragment_scope_class ~ '-detailTable' %} {% if render_mode != 'fragment' %} {{ fs.topbar( crumbs=["Finite State", "Scan Quality"], meta=[ {"label": "Domain", "value": domain or "—"}, {"label": "Scope", "value": project_label or scope_label or "All Projects"}, {"label": "Projects", "value": (summary.get('total_projects', 0)) | string}, {"label": "Generated", "value": generated_at or "—"}, ], controls=[], ) }} {% endif %}

Scan Quality Report

{{ project_label or scope_label | default('All Projects') }} — Scan Coverage & Quality Analysis

{# KPI bar — 4 or 5 cells (Unpack Issues conditional). Sub-caption text (e.g. "out of 4") flows through the macro's `delta=` slot per _console_macros.html:134. #}
{{ fs.kpi_cell("Projects Scanned", summary.get('total_projects', 0)) }} {{ fs.kpi_cell( "Avg Coverage Score", "%.1f"|format(summary.get('avg_coverage_score', 0) | float), delta="out of 4", dot=("critical" if summary.get('avg_coverage_score', 0) < 2 else ("medium" if summary.get('avg_coverage_score', 0) < 3 else "low")), ) }} {{ fs.kpi_cell( "Reachability Coverage", (rc.get('with_reachability', 0) | string) ~ " of " ~ (rc_total | string), delta="binary projects with reachability", ) }} {{ fs.kpi_cell( "Stale Projects", summary.get('stale_project_count', 0), delta="no scan in " ~ (thresholds.aging | string) ~ "+ days", dot=("critical" if summary.get('stale_project_count', 0) > 0 else None), ) }} {% if has_unpack_data %} {{ fs.kpi_cell( "Unpack Issues", unpack_issue_count.val, delta="Fair or Poor rating", dot=("critical" if unpack_issue_count.val > 0 else None), ) }} {% endif %}
{# Staleness legend strip. #} {% if thresholds %}
Staleness Legend: FRESH = scanned within {{ thresholds.fresh }} days | AGING = {{ thresholds.fresh + 1 }}–{{ thresholds.aging }} days | STALE = {{ thresholds.aging + 1 }}–{{ thresholds.stale }} days | DORMANT = over {{ thresholds.stale }} days
{% endif %} {# Charts — 2-column row (staleness + scan_type_coverage) then unpack rating full-width below (if present). The outer panel only renders when at least one of the two charts has non-empty labels — prevents an empty bordered chart region in standalone HTML (round-1 B.1 PR review M1-4). #} {# Chart-render gates require at least one positive value, not just non-empty labels — prevents the server-side doughnut from falling back to a `chart-unavailable` placeholder when every bucket is zero (round-2 B.1 PR review M2-1). Use subscript syntax (`['values']`) because Jinja's dot access resolves `.values` to the dict's `.values()` METHOD, not the dict's `"values"` key. #} {% set has_staleness_chart = charts.staleness_distribution and (charts.staleness_distribution['values'] | default([]) | sum > 0) %} {% set has_scan_type_chart = charts.scan_type_coverage and (charts.scan_type_coverage['values'] | default([]) | sum > 0) %} {% if has_staleness_chart or has_scan_type_chart %}
{# Per-slot gates use the same values | sum > 0 derived locals as the outer panel — prevents an all-zero staleness slot from rendering when scan_type_coverage opens the panel (round-3 B.1 PR review M1-1). #} {% if has_staleness_chart %}
{{ fs.panel_head("Staleness distribution", meta="project recency") }} {% if render_mode == 'fragment' and not fragment_scripts_enabled %}
{{ server_svgs.get('staleness_distribution', '') | safe }}
{% else %}
{% endif %}
{% endif %} {% if has_scan_type_chart %}
{{ fs.panel_head("Scan type coverage", meta="projects per scan type") }} {% if render_mode == 'fragment' and not fragment_scripts_enabled %}
{{ server_svgs.get('scan_type_coverage', '') | safe }}
{% else %}
{% endif %}
{% endif %}
{% endif %} {# Unpack chart panel — INTENTIONALLY outside the `has_staleness_chart or has_scan_type_chart` gate above so an unpack-only payload (rare but possible if the transform's per-chart data is partial) still renders. Round-2 B.1 PR review M1-1 caught the prior nesting bug. #} {% if has_unpack_chart %}
{{ fs.panel_head("Unpack rating distribution", meta="binary scan unpack quality") }} {% if render_mode == 'fragment' and not fragment_scripts_enabled %}
{{ server_svgs.get('unpack_rating_distribution', '') | safe }}
{% else %}
{% endif %}
{% endif %} {# Summary Table (per-project, latest-version snapshot). #}
{{ fs.panel_head("Project summary", meta="latest version per project") }}
{% if summary_table and summary_table | length > 0 %} {% set ns = namespace(has_unpack=false) %} {% for row in summary_table %} {% if row.unpack_rating is defined and row.unpack_rating %} {% set ns.has_unpack = true %} {% endif %} {% endfor %} Project Folder Versions Latest Version Last Scan {% if ns.has_unpack %} Unpack Rating {% endif %} Staleness Coverage Reachability Critical High Total {% for row in summary_table %} {% set staleness_lc = (row.staleness | default('') | lower) %} {% if ns.has_unpack %} {% endif %} {% endfor %}
{{ row.project_name | default('') }} {{ row.folder_name | default('') }} {{ row.version_count | default(0) }} {{ row.latest_version | default('') }} {{ row.last_scan_date | default('') }} {% set ur = row.unpack_rating | default('') %} {% if ur == 'Excellent' %}Excellent {% elif ur == 'Good' %}Good {% elif ur == 'Fair' %}Fair {% elif ur == 'Poor' %}Poor {% elif ur == 'Not Applicable' %}N/A {% else %}{% endif %} {% if row.unpack_short_summary is defined and row.unpack_short_summary %}
{{ row.unpack_short_summary }}
{% endif %}
{% if staleness_lc %} {{ row.staleness }} {% else %}—{% endif %} {% set cs = row.coverage_score | default(0) %} {{ cs }} {% set reach = row.has_reachability | default('') %} {% if reach == 'Yes' %}Yes {% elif reach == 'No' %}No {% else %}N/A{% endif %} {{ row.critical_findings | default(0) }} {{ row.high_findings | default(0) }} {{ row.total_findings | default(0) }}
{% else %}
No project data available.
{% endif %}
{# Detail Table (per project-version). #}
{{ fs.panel_head("Version detail", meta="one row per project-version") }}
{% if detail_table and detail_table | length > 0 %} {% set dns = namespace(has_unpack=false) %} {% for row in detail_table %} {% if row.unpack_rating is defined and row.unpack_rating %} {% set dns.has_unpack = true %} {% endif %} {% endfor %} Project Folder Version Scans Last Scan {% if dns.has_unpack %} Unpack Rating {% endif %} Staleness Coverage Reachability Critical High Total {% for row in detail_table %} {% set staleness_lc = (row.staleness | default('') | lower) %} {% if dns.has_unpack %} {% endif %} {% endfor %}
{{ row.project_name | default('') }} {{ row.folder_name | default('') }} {{ row.version_name | default('') }} {{ row.scan_count | default(0) }} {{ row.last_scan_date | default('') }} {% set ur = row.unpack_rating | default('') %} {% if ur == 'Excellent' %}Excellent {% elif ur == 'Good' %}Good {% elif ur == 'Fair' %}Fair {% elif ur == 'Poor' %}Poor {% elif ur == 'Not Applicable' %}N/A {% else %}{% endif %} {% if row.unpack_short_summary is defined and row.unpack_short_summary %}
{{ row.unpack_short_summary }}
{% endif %}
{% if staleness_lc %} {{ row.staleness }} {% else %}—{% endif %} {% set cs = row.coverage_score | default(0) %} {{ cs }} {% set reach = row.has_reachability | default('') %} {% if reach == 'Yes' %}Yes {% elif reach == 'No' %}No {% else %}N/A{% endif %} {{ row.critical_findings | default(0) }} {{ row.high_findings | default(0) }} {{ row.total_findings | default(0) }}
{% else %}
No version detail data available.
{% endif %}
{% if render_mode != 'fragment' %} {{ fs.status_bar(items=[ "Recipe: Scan Quality", "Projects: " ~ ((summary.get('total_projects', 0)) | string), generated_at | default(''), ], version='fs-report ' ~ (fs_report_version | default('dev'))) }} {% endif %} {% if render_mode != 'fragment' or fragment_scripts_enabled %} {% include '_action_buttons.html' %} {% endif %}