{% extends "base.html" %} {% block title %}Run #{{ run.id }} - {{ project.name }}{% endblock %} {% block content %} {% if run.error %}

Error

{{ run.error }}
{% endif %} {# Trend macro: render a +N / -M badge comparing current vs previous run. `direction` controls semantic color: "up_good" → going up is good (more captures OK) "down_good" → going down is good (fewer discrepancies) #} {% macro trend(current, previous, direction='down_good') %} {% if previous is not none and current != previous %} {% set delta = current - previous %} {% if direction == 'up_good' %} {% set good = delta > 0 %} {% else %} {% set good = delta < 0 %} {% endif %} {{ '+' if delta > 0 else '' }}{{ delta }} {% endif %} {% endmacro %}
{{ stats.captures_ok }}/{{ stats.total_captures }} {% if previous_stats %}{{ trend(stats.captures_ok, previous_stats.captures_ok, 'up_good') }}{% endif %}
Captures OK
{% if stats.captures_failed %}
{{ stats.captures_failed }} {% if previous_stats %}{{ trend(stats.captures_failed, previous_stats.captures_failed, 'down_good') }}{% endif %}
Nav. failures
{% endif %}
{{ stats.total_discrepancies }} {% if previous_stats %}{{ trend(stats.total_discrepancies, previous_stats.total_discrepancies, 'down_good') }}{% endif %}
Active discrepancies
{% if stats.n_dismissed %}
{{ stats.n_dismissed }}
Dismissed
{% endif %}
{{ stats.by_severity.critical or 0 }} {% if previous_stats %}{{ trend(stats.by_severity.critical or 0, previous_stats.by_severity.critical or 0, 'down_good') }}{% endif %}
Critical
{{ stats.by_severity.important or 0 }} {% if previous_stats %}{{ trend(stats.by_severity.important or 0, previous_stats.by_severity.important or 0, 'down_good') }}{% endif %}
Important
{{ stats.by_severity.minor or 0 }} {% if previous_stats %}{{ trend(stats.by_severity.minor or 0, previous_stats.by_severity.minor or 0, 'down_good') }}{% endif %}
Minor
{% if execution and execution.total_cost %}
~${{ "%.2f" | format(execution.total_cost) }}
API Cost
{% endif %}
{% if run.status == 'running' %}

Loading progress...

{% endif %} {% if execution and execution.phases and run.status != 'running' %}

Execution details

{% for phase in execution.phases %} {% endfor %}
Phase Duration Detail Tokens Cost
{% if phase.status == 'completed' %} {% elif phase.status == 'failed' %} {% else %} {% endif %} {{ phase.label }} {% if phase.duration %} {% if phase.duration >= 60 %}{{ (phase.duration // 60) | int }}m{{ "%02d" | format((phase.duration % 60) | int) }}s{% else %}{{ "%.1f" | format(phase.duration) }}s{% endif %} {% else %}-{% endif %} {{ phase.detail or '-' }} {% if phase.tokens %}{{ "{:,}".format(phase.tokens) }}{% else %}-{% endif %} {% if phase.cost %}~${{ "%.3f" | format(phase.cost) }}{% else %}-{% endif %}
Total {% if run.duration %} {% if run.duration >= 60 %}{{ (run.duration // 60) | int }}m{{ "%02d" | format((run.duration % 60) | int) }}s{% else %}{{ "%.1f" | format(run.duration) }}s{% endif %} {% elif execution.elapsed %} {% if execution.elapsed >= 60 %}{{ (execution.elapsed // 60) | int }}m{{ "%02d" | format((execution.elapsed % 60) | int) }}s{% else %}{{ "%.0f" | format(execution.elapsed) }}s{% endif %} {% endif %} {% if execution.total_tokens %}{{ "{:,}".format(execution.total_tokens) }}{% endif %} {% if execution.total_cost %}~${{ "%.3f" | format(execution.total_cost) }}{% endif %}
{% endif %} {% if failed_captures %}

Navigation failures ({{ failed_captures | length }})

These pages could not be captured correctly. The screenshots were identical to those of other pages (silent redirect to login/home/splash) or the navigation raised an error. Phase 5 does not compare them — the associated Figma screens will remain unverified.

{% for fc in failed_captures %} {% endfor %}
Page IDRouteTested URLCause
{{ fc.page_id }} {{ fc.route }} {{ fc.landed_url or '-' }} {% if fc.is_duplicate %} Silent redirect — {{ fc.error }} {% else %} {{ fc.error }} {% endif %}
{% endif %} {% set valid_comparisons = comparisons_list | selectattr('fidelity', '!=', 'mismatch') | list %} {% set mismatch_comparisons = comparisons_list | selectattr('fidelity', '==', 'mismatch') | list %} {% if valid_comparisons %}

Comparisons by screen ({{ valid_comparisons | length }})

{% for comp in valid_comparisons %} {% endfor %}
Figma screenPageDiscrepanciesFidelity
{{ comp.screen_name }} {{ comp.page_id }} {{ comp.count }} {{ comp.fidelity }} {% if comp.has_image %} Compare {% else %} No Figma image {% endif %}
{% endif %} {% if mismatch_comparisons %}

Uncompared screens ({{ mismatch_comparisons | length }})

These Figma screens could not be compared — wrong matching, uncaptured state, or page error.

{% for comp in mismatch_comparisons %} {% endfor %}
Figma screenAssociated pageDiagnostic
{{ comp.screen_name }} {{ comp.page_id }} {{ comp.mismatch_reason or 'Different screens' }} View
{% endif %} {% if discrepancies %}

Discrepancies ({{ discrepancies | length }})

{% for d in discrepancies %}
{{ d.category }} - {{ d.page_id }} ({{ d.route }})
{{ d.status }} {{ d.severity }}
{{ d.description }}
{% if d.figma_value or d.app_value %}
{% if d.figma_value %}Figma: {{ d.figma_value }}{% endif %} {% if d.app_value %}App: {{ d.app_value }}{% endif %}
{% endif %} {% if d.status == 'open' %}
{% endif %}
{% endfor %}
{% endif %} {% endblock %}