{% extends "base.html" %} {% from "fragments/review_journey.html" import review_journey %} {% block title %}Voxint — check the words: {{ run_source_title(run) }}{% endblock %} {% block body %} {# Backward nav only (issue #117 Phase B): "the people" is Step 1, the workbench. The sequence never promotes a sideways jump; a step's own Continue moves it forward. #}

← Back to the people

{# Shared identity + two-step sequence (issue #117 Phase B); this is Step 2 ("check the words"), matching the workbench header so the two screens read as one journey. The fragment is static; the claim-state line below OWNS the claim state. #}
{{ review_journey(run, 2) }} {# This server-rendered line OWNS the claim state, JS on or off — the island deliberately renders no unclaimed notice of its own (review finding: the two copies used to double up after hydration). The inner span keeps the text one flex item so it wraps normally beside the status dot. #} {% if token %}

Claimed by you — verify and edit are enabled.

{% else %}

Not claimed by this tab — verifying and editing are disabled. Claim this run in the workbench to review.

{% endif %}

Read the full transcript (you can switch between versions there).

{% if not lines %}

No transcript segments for this run.

{% else %} {# Island mount (issue #53): the review-stepper hydrates the verify-and-advance loop + inline edit over this fallback. JS-off, the list below is fully usable: each unverified segment carries a plain verify form that POSTs and redirects back here (the write route content-negotiates). Inline TEXT editing needs the island — stated honestly, never faked. The progress track (issue #92) keeps the count as visible text; the bar is aria-hidden decoration. #}
{# Same card the hydrated island renders, so JS-off/island-failure does not drop the flagship surface (hydration replaces this innerHTML wholesale). #} {% set all_checked = progress.total > 0 and progress.verified >= progress.total %}

{{ progress.verified }} of {{ progress.total }} segments verified.{% if all_checked %} You have checked every line.{% endif %}

{% if progress.total > 0 %} {% endif %}
{# Step 2 terminal action (issue #117 Phase B). Checking the words is recommended navigation, never a durable whole-run completion flag (Phase 0 contract), so this offers plain next actions and sets no state. It stays neutral: checking the words does not prove speaker labels are resolved, so it never calls the run "finished". The island renders the live equivalent once JS is on. #} {% if all_checked %} {% endif %}
{% for ln in lines %} {% set idx = palette.get(ln.diarization_label) %} {% set uncertain = ln.confidence is not none and ln.confidence < low_confidence_threshold %}

[{{ "%.2f"|format(ln.start_seconds) }}–{{ "%.2f"|format(ln.end_seconds) }}] {% if uncertain %}uncertain{% endif %} {% if ln.verified %}verified{% endif %} {% if ln.corrected %}edited{% endif %} {% if ln.diarization_label %}{{ ln.diarization_label }}{% endif %} {% if ln.speaker != ln.diarization_label %}{{ ln.speaker }}:{% endif %} {{ ln.text }} {% if token and ln.segment_id and not ln.verified %}

{% endif %}

{% endfor %} {# Highlights fallback (issue #86): a read-only list of the run's annotations for JS-off / pre-hydration. Sits INSIDE the island wrapper, so hydration replaces it with the interactive Highlights panel. Creating and editing highlights needs the island — stated honestly, never faked. #} {% if island_props.annotations %}

Highlights ({{ island_props.annotations|length }})

Read-only list. Creating and editing highlights needs JavaScript.

{% endif %}
{% endif %} {% endblock %}