{% if runs %}
{% for run in runs %}
{% set progress = run.progress %}
{% set is_multi = progress and progress.total > 1 %}
{% set pct = (progress.completed / progress.total * 100) | round(1) if is_multi else 0 %}
{% set is_err = run.status != 'running' and run.result == 'error' %}
{% set is_cancelled = run.status != 'running' and run.result == 'cancelled' %}
{% set is_success = run.status != 'running' and run.result == 'success' %}
{% set is_finished_unknown = run.status != 'running' and run.result != 'success' and run.result != 'error' and run.result != 'cancelled' %}
{% set report_url = run.report_url %}
{# A workflow run renders as ONE first-class row: named by the workflow, a
segment sparkline (done / pulsing-now / pending) in place of the bar, and a
click that opens the run (/run/{id}) — NOT the last report. The is_wf
branch is evaluated FIRST so a successful workflow links to /run/{id}, not
report_url.
A COMPOUND row links to the SAME canvas (/run/{id}): the fan-in canvas is
reopened and its deliverable node opens the combined report (spec §9). So
the LINK uses is_canvas (workflow OR compound); the NAME still uses is_wf
(a compound row shows recipes[0] = the compound/bundle name, not a
workflow_name) — only the link target changes.
ALL terminal states (success / cancelled / error / unknown) for a canvas
row reopen the canvas (/run/{id}) — including ERROR (fix ④): the canvas now
renders the terminal error state + the deliverable's error message, and a
persistent "Run log" link in the canvas toolbar keeps the raw log one click
away. Only ad-hoc (non-canvas) report errors still route straight to
/run/{id}/log. #}
{% set is_wf = run.kind == 'workflow' %}
{% set is_canvas = run.kind in ('workflow', 'compound') %}
{% set wf_total = (progress.total if progress else (run.recipes | length)) or (run.recipes | length) %}
{% set wf_completed = (progress.completed if progress else 0) %}
{% set wf_tint = 'success' if is_success else ('error' if is_err else ('cancelled' if is_cancelled else 'neutral')) %}
{% if is_wf %}{{ run.workflow_name or 'Workflow' }}{% else %}{{ run.recipes[0] }}{% if run.recipes | length > 1 %} +{{ run.recipes | length - 1 }}{% endif %}{% endif %}· {{ run.scope }}
{% if is_err %}
✕ failed
{% elif is_cancelled %}
— cancelled
{% elif is_success %}
✓ done
{% elif is_finished_unknown %}
{# Defensive: completed run with null/unexpected result — show neutral state #}
— finished
{% else %}
{% if run.elapsed >= 60 %}{{ (run.elapsed // 60) }}m{% else %}{{ run.elapsed }}s{% endif %}
{# B2 #21: per-row Stop — wired to POST /api/run/{id}/cancel by the
delegated handler in command-center.js (stops row-navigation
propagation on canvas rows). The poller settles the row to "cancelled"
on its next tick. #}
{% endif %}
{% if is_wf %}
{# ── Workflow segment sparkline (one .seg per step) ──────────────
Running: done (< completed) / now (== completed, pulsing) / pending.
Finished: all done, result-tinted (+ a one-time shimmer added by the
poller on the in-place transition). The template owns this markup; the
poller only toggles .seg classes + the label (no rebuild → no drift). #}
{% for i in range(wf_total) %}{% endfor %}
{% if run.status == 'running' %}step {{ wf_completed }} of {{ wf_total }}{% else %}{{ wf_total }} steps{% endif %}
{% elif run.status == 'running' %}
{% if is_multi %}
{# Determinate bar: multiple recipes, show progress width #}