{% if logo_path %}
{% else %}
{% endif %}

Version Comparison

{% if transform_result and transform_result.is_pair_comparison and transform_result.projects %} {% set _p0 = transform_result.projects[0] %} {% set _bpn = _p0.latest_delta.baseline_project_name | default('') %} {% set _cpn = _p0.latest_delta.current_project_name | default('') %} {% if _bpn and _cpn and _bpn != _cpn %}

{{ _bpn }} ↔ {{ _cpn }}

{% elif _bpn %}

{{ _bpn }}

{% else %}

Two-version comparison

{% endif %} {% elif transform_result and transform_result.project_count %}

Version-over-version progression across {{ transform_result.project_count }} project{{ 's' if transform_result.project_count != 1 else '' }}

{% else %}

Version-over-version progression

{% endif %}
Report Generated: {{ metadata.start_date | default('N/A') }} | {% if transform_result and transform_result.is_pair_comparison and transform_result.projects %} {% set _md_p0 = transform_result.projects[0] %} {% set _md_bpn = _md_p0.latest_delta.baseline_project_name | default('') %} {% set _md_cpn = _md_p0.latest_delta.current_project_name | default('') %} {% if _md_bpn and _md_cpn and _md_bpn != _md_cpn %} Project A: {{ _md_bpn }} | Project B: {{ _md_cpn }} | {% elif _md_bpn %} Project: {{ _md_bpn }} | {% endif %} {% elif metadata.project_filter %} Project: {{ metadata.project_filter }} | {% endif %} {% if metadata.folder_filter %} Folder: {{ metadata.folder_filter }} | {% endif %} Generated by: Finite State Reporting Kit
{% if transform_result and transform_result.projects and transform_result.projects|length > 0 %} {% set result = transform_result %} {% set kpi = result.kpi %} {% if partial_report %}
⚠ Partial report: {{ failed_version_names|length }} version{{ 's' if failed_version_names|length != 1 else '' }} could not be fetched ({{ failed_version_names|join(", ") }}). These appear as placeholders below.
{% endif %}
Total Findings
{{ kpi.total_findings.baseline }} {{ kpi.total_findings.current }}
{% set tf = kpi.total_findings %} {% if tf.delta > 0 %}+{% endif %}{{ tf.delta }} ({% if tf.delta > 0 %}+{% endif %}{{ tf.pct }}%)
Critical
{{ kpi.critical_findings.baseline }} {{ kpi.critical_findings.current }}
{% set cf = kpi.critical_findings %} {% if cf.delta > 0 %}+{% endif %}{{ cf.delta }}
High
{{ kpi.high_findings.baseline }} {{ kpi.high_findings.current }}
{% set hf = kpi.high_findings %} {% if hf.delta > 0 %}+{% endif %}{{ hf.delta }}
Components
{{ kpi.components.baseline }} {{ kpi.components.current }}
{% set cp = kpi.components %} {% if cp.delta > 0 %}+{% endif %}{{ cp.delta }}
Fixed (latest)
{{ kpi.fixed_count }}
New (latest)
{{ kpi.new_count }}
{% for proj in result.projects %}
{% set is_pair = proj.is_pair_comparison | default(false) %}

{{ proj.project_name }}

{% if is_pair %} {{ proj.latest_delta.baseline_label }} → {{ proj.latest_delta.current_label }} {% else %} {{ proj.progression|length }} versions | {{ proj.progression[0].version }} → {{ proj.progression[-1].version }} {% endif %}
{% set proj_idx = loop.index %}
{% if is_pair %}Baseline{% else %}First Version{% endif %}
{% if proj.progression[0].total is none %}—{% else %}{{ proj.progression[0].total }}{% endif %}
findings
{% if is_pair %}Current{% else %}Latest Version{% endif %}
{% if proj.progression[-1].total is none %}—{% else %}{{ proj.progression[-1].total }}{% endif %}
findings
Net Change
{% if proj.progression[-1].total is none or proj.progression[0].total is none %}
{% else %} {% set net = proj.progression[-1].total - proj.progression[0].total %}
{% if net > 0 %}+{% endif %}{{ net }}
{% endif %}
Latest Fixed
{% if proj.latest_delta.fixed_count is defined %}{{ proj.latest_delta.fixed_count }}{% else %}—{% endif %}
Latest New
{% if proj.latest_delta.new_count is defined %}{{ proj.latest_delta.new_count }}{% else %}—{% endif %}

{% if is_pair %}Version Comparison{% else %}Version Progression{% endif %}

{% for step in proj.progression %} {% endfor %}
Project Version Date Total Critical High Medium Low Fixed New Components
{{ step.version_project_name or proj.project_name }} {{ step.version }} {% if step.fetch_failed %}⚠ fetch failed{% endif %} {{ step.created }} {% if step.total is none %}—{% else %}{{ step.total }}{% endif %} {% if step.critical is none %}—{% else %}{{ step.critical }}{% endif %} {% if step.high is none %}—{% else %}{{ step.high }}{% endif %} {% if step.medium is none %}—{% else %}{{ step.medium }}{% endif %} {% if step.low is none %}—{% else %}{{ step.low }}{% endif %} {% if step.fixed is none %}—{% elif step.fixed > 0 %}-{{ step.fixed }}{% elif loop.index0 == 0 %}—{% else %}0{% endif %} {% if step.new is none %}—{% elif step.new > 0 %}+{{ step.new }}{% elif loop.index0 == 0 %}—{% else %}0{% endif %} {% if step.components is none %}—{% else %}{{ step.components }}{% endif %}

Changes ({{ proj.latest_delta.baseline_label | default(proj.latest_delta.baseline_version) }} → {{ proj.latest_delta.current_label | default(proj.latest_delta.current_version) }})

{{ proj.latest_delta.fixed_count|default('—') }} fixed {{ proj.latest_delta.new_count|default('—') }} new {% if proj.latest_delta.externally_changed_count | default(0) > 0 %} {{ proj.latest_delta.externally_changed_count }} external {% endif %}
Fixed: {{ proj.latest_delta.fixed_severity_summary }} New: {{ proj.latest_delta.new_severity_summary }}

Fixed in {{ proj.latest_delta.current_label | default(proj.latest_delta.current_version) }}

{% if proj.latest_delta.fixed_findings and proj.latest_delta.fixed_findings|length > 0 %} {% for row in proj.latest_delta.fixed_findings %} {% endfor %} {% if proj.latest_delta.fixed_findings|length > 10 %} {% endif %}
ID Severity Component Score Title
{{ row.display_id if row.display_id else '—' }} {{ row.severity }} {{ row.component_name }}{% if row.component_version %} {{ row.component_version }}{% endif %} {{ "%.1f"|format(row.risk / 10.0) if row.risk else '—' }} {{ row.title if row.title else '—' }}
{% else %}

No fixed findings.

{% endif %}

New in {{ proj.latest_delta.current_label | default(proj.latest_delta.current_version) }}

{% if proj.latest_delta.new_findings and proj.latest_delta.new_findings|length > 0 %} {% for row in proj.latest_delta.new_findings %} {% endfor %} {% if proj.latest_delta.new_findings|length > 10 %} {% endif %}
ID Severity Component Score Title Note
{{ row.display_id if row.display_id else '—' }} {{ row.severity }} {{ row.component_name }}{% if row.component_version %} {{ row.component_version }}{% endif %} {{ "%.1f"|format(row.risk / 10.0) if row.risk else '—' }} {{ row.title if row.title else '—' }} {{ row.external_change_note if row.external_change_note else '' }}
{% else %}

No new findings.

{% endif %}
{% if proj.latest_delta.externally_changed and proj.latest_delta.externally_changed|length > 0 %}

Externally Changed Findings ({{ proj.latest_delta.baseline_label | default(proj.latest_delta.baseline_version) }} → {{ proj.latest_delta.current_label | default(proj.latest_delta.current_version) }})

{{ proj.latest_delta.externally_changed_count }} CVEs

CVEs present in both versions whose severity or exploit status changed due to platform intelligence updates — not developer action. These findings remain open and may require re-prioritization.

{% for entry in proj.latest_delta.externally_changed %} {% endfor %}
CVE ID Component Change Type Old Severity New Severity Old Exploit New Exploit
{{ entry.cve_id }} {{ entry.component_name if entry.component_name else '—' }} {{ entry.change_type | replace('_', ' ') | title }} {% if entry.old_severity %}{{ entry.old_severity }}{% else %}—{% endif %} {% if entry.new_severity %}{{ entry.new_severity }}{% else %}—{% endif %} {{ entry.old_exploit if entry.old_exploit else '—' }} {{ entry.new_exploit if entry.new_exploit else '—' }}
{% endif %} {% if proj.latest_delta.component_churn and proj.latest_delta.component_churn|length > 0 %}

Component Changes ({{ proj.latest_delta.baseline_label | default(proj.latest_delta.baseline_version) }} → {{ proj.latest_delta.current_label | default(proj.latest_delta.current_version) }})

{{ proj.latest_delta.component_churn|length }} changes
{% for row in proj.latest_delta.component_churn %} {% endfor %} {% if proj.latest_delta.component_churn|length > 15 %} {% endif %}
Change Component Old Version New Version Findings Impact
{% if row.change_type == 'added' %}+ Added{% elif row.change_type == 'removed' %}- Removed{% else %}↑ Updated{% endif %} {{ row.name }} {{ row.version_baseline | default('-', true) }} {{ row.version_current | default('-', true) }} {{ row.findings_impact | default(0) }}
{% endif %} {% if proj.progression|length > 2 %}

Version changelog

{% for step in proj.progression %} {% if step.from_version %} {% set step_churn_list = step.component_churn | default([]) %}
{{ step.from_version }} → {{ step.version }} {% if step.fixed is none %}—{% else %}{{ step.fixed }}{% endif %} fixed {% if step.new is none %}—{% else %}{{ step.new }}{% endif %} new {{ step_churn_list | length }} component{{ 's' if step_churn_list | length != 1 else '' }}
Fixed: {{ step.fixed_severity_summary }} New: {{ step.new_severity_summary }}

Fixed

{% if step.fixed_findings and step.fixed_findings|length > 0 %} {% for row in step.fixed_findings %} {% endfor %}
IDSeverityComponentScoreTitle
{{ row.display_id if row.display_id else '—' }}{{ row.severity }}{{ row.component_name }}{% if row.component_version %} {{ row.component_version }}{% endif %}{{ "%.1f"|format(row.risk / 10.0) if row.risk else '—' }}{{ row.title if row.title else '—' }}
{% else %}

No fixed findings.

{% endif %}

New

{% if step.new_findings and step.new_findings|length > 0 %} {% for row in step.new_findings %} {% endfor %}
IDSeverityComponentScoreTitle
{{ row.display_id if row.display_id else '—' }}{{ row.severity }}{{ row.component_name }}{% if row.component_version %} {{ row.component_version }}{% endif %}{{ "%.1f"|format(row.risk / 10.0) if row.risk else '—' }}{{ row.title if row.title else '—' }}
{% else %}

No new findings.

{% endif %}

Component changes

{% if step_churn_list and step_churn_list|length > 0 %} {% for row in step_churn_list %} {% endfor %}
Change Component Previous Version Current Version Findings Impact
{% if row.change_type == 'added' %}+ Added{% elif row.change_type == 'removed' %}- Removed{% elif row.change_type == 'updated' %}↑ Updated{% else %}—{% endif %} {{ row.name | default('—') }} {{ row.version_baseline | default('—', true) }} {{ row.version_current | default('—', true) }} {{ row.findings_impact | default(0) }}
{% else %}

No component changes.

{% endif %}
{% endif %} {% endfor %}
{% endif %}
{% endfor %} {% else %}

No comparison data available.

Ensure projects have at least two scanned versions, or scope with --project or --folder.

{% endif %}