{% extends "base.html" %} {% block title %}Voxint — run {{ run.id.hex[:8] }}{% endblock %} {% block body %}

← runs

Run {{ run.id.hex[:8] }}

{{ run.media_item.source_path }}

{% if provenance %} {# URL runs only: the acquisition source, shown as a bare host — never the raw source_url, whose query could carry a signed token. #}

Source: {{ provenance }}

{% endif %} {# Gate on the live status too: a bookmarked/refreshed ?enqueue=deferred URL must not keep asserting "is queued" after the sweep already republished it. #} {% if enqueue_deferred and run.status == "queued" %}

The initial enqueue was deferred because the task broker was unavailable. This run is queued and will start automatically once the broker recovers — no action needed.

{% endif %}
Status
{{ run.status }}
Current stage
{{ run.current_stage or "—" }}
Revision
{{ run.revision }}
Created
{{ run.created_at.strftime("%Y-%m-%d %H:%M:%S") }}
Updated
{{ run.updated_at.strftime("%Y-%m-%d %H:%M:%S") }}
{% if run.error %}

{{ run.error }}

{% endif %} {% if run.status == "failed" %}
{# Carry the revision we rendered so a stale tab's requeue 409s (exact-revision CAS). #} Retries the failed stage ({{ run.current_stage or "—" }}).
{% if run.current_stage in ("transcribe", "diarize_embed") %} {# Static guidance only — no live probe on this page (a health check here would add model-service latency to every failed-run view and flap with service health; the setup wizard's SERVICES step owns live reachability). #}

This stage needs the model services (ASR / diarizer / embedder). If they aren't running, start a compute tier — docker compose -f compose.yaml -f compose.gpu.yaml up -d (NVIDIA GPU) or docker compose -f compose.yaml -f compose.cpu.yaml up -d (no GPU; needs HF_TOKEN in .env either way) — wait for them to come up, then requeue.

{% endif %} {% endif %}

{% if audio_available %}Audio{% endif %} {% if transcript_available %}Transcript{% endif %} {% if run.status == "completed" %}Review{% endif %} Export (JSON) {% if not audio_available and not transcript_available %} No audio or transcript yet. {% endif %}

{% if source_metadata %} {# Scraped acquisition context (issue #36) — write-once, shown apart from the operator's own notes so human and scraped input are never conflated. The URLs here are sanitized allowlist values (absolute http(s), no userinfo), unlike the raw source_url, which never reaches a template. #}

Source metadata

{% if source_metadata.title %}
Title
{{ source_metadata.title }}
{% endif %} {% if source_metadata.uploader or source_metadata.channel %}
Uploader
{{ source_metadata.uploader or source_metadata.channel }} {% if source_metadata.channel and source_metadata.uploader and source_metadata.channel != source_metadata.uploader %} · {{ source_metadata.channel }} {% endif %} {% if source_metadata.channel_url %} · channel {% endif %}
{% endif %} {% if source_metadata.upload_date %}
Uploaded
{{ source_metadata.upload_date.isoformat() }}
{% endif %} {% if source_metadata.duration_seconds %}
Claimed duration
{{ "%d:%02d" | format(source_metadata.duration_seconds // 60, source_metadata.duration_seconds % 60) }} (source-reported, not measured)
{% endif %} {% if source_metadata.tags %}
Tags
{{ source_metadata.tags | join(", ") }}
{% endif %} {% if source_metadata.canonical_url %}
Page
{{ source_metadata.canonical_url }}
{% endif %} {% if source_metadata.extractor %}
Extractor
{{ source_metadata.extractor }}{% if source_metadata.extractor_version %} (yt-dlp {{ source_metadata.extractor_version }}){% endif %}
{% endif %}
{% if source_metadata.description %}
Description

{{ source_metadata.description }}

{% endif %} {% endif %}

Operator notes

Stage ledger

{% if not stage_runs %}

No stage attempts recorded yet.

{% else %} {% for s in stage_runs %} {% endfor %}
StageAttemptStatusWorker StartedFinishedLease expiresError
{{ s.stage }} {{ s.attempt }} {{ s.status }} {{ s.worker_id or "—" }} {{ s.started_at.strftime("%Y-%m-%d %H:%M:%S") if s.started_at else "—" }} {{ s.finished_at.strftime("%Y-%m-%d %H:%M:%S") if s.finished_at else "—" }} {{ s.lease_expires_at.strftime("%Y-%m-%d %H:%M:%S") if s.lease_expires_at else "—" }} {% if s.error %}{{ s.error }}{% else %}—{% endif %}
{% endif %} {% endblock %}