{# Console 2.0 speakers overview (#159) — full-page include and the htmx post-mutation refresh target (#roster). Numbers come from effective resolution (the canonical-run fold), never raw machine proposals. Every mutating form's action carries the current ?sort/?view so its re-render preserves both. Operator refusals (RosterError) arrive as roster_error. #} {% set qs = "sort=" ~ sort ~ "&view=" ~ view %} {% if roster_error %}{% endif %} {# Action reminders (#159): the review work waiting on this roster. Capped lists with honest "and N more" totals; the duplicates card is deferred to a follow-up issue. #} {% if overview.name_suggestions or overview.unverified_active %}
{% if overview.name_suggestions %}

{{ overview.name_suggestion_total }} speaker-name suggestion{{ "s" if overview.name_suggestion_total != 1 }} waiting for review: {% for reminder in overview.name_suggestions %} {% if reminder_runs.get(reminder.run_id) %}{{ run_source_title(reminder_runs[reminder.run_id]) }}{% else %}a recording{% endif %} ({{ reminder.count }}){{ ", " if not loop.last }} {% endfor %} {%- if overview.name_suggestion_total > overview.name_suggestions|sum(attribute="count") %} and more on other recordings {%- endif %}

{% endif %} {% if overview.unverified_active %}

{{ overview.unverified_active_total }} frequently heard voice{{ "s" if overview.unverified_active_total != 1 }} you haven't confirmed yet: {% for row in overview.unverified_active %} {{ row.entry.speaker.display_name }} ({{ format_duration(row.aggregate.seconds) }}){{ ", " if not loop.last }} {% endfor %} {%- if overview.unverified_active_total > overview.unverified_active|length %} and {{ overview.unverified_active_total - overview.unverified_active|length }} more {%- endif %}

{% endif %}
{% endif %} {% if overview.rows %}

{{ overview.rows|length }} speaker{{ "s" if overview.rows|length != 1 }} · {{ overview.verified_count }} verified · {{ format_duration(overview.total_seconds) }} attributed across {{ overview.runs_scanned }} processed recording{{ "s" if overview.runs_scanned != 1 }}

{% macro tier_chip(row) %} {%- if row.tier.tier -%} {{ row.tier.tier }} voice match {%- elif row.tier.has_voice_evidence -%} match details unavailable {%- else -%} no voice evidence {%- endif -%} {% endmacro %} {% macro verified_badge(row) %} {%- if row.aggregate.verified -%}Verified{%- endif -%} {% endmacro %} {% macro actions(row) %}
{% set targets = overview.rows | rejectattr("entry.speaker.id", "equalto", row.entry.speaker.id) | list %} {% if targets %}
{% endif %}
{% endmacro %} {% if view == "table" %}
{% for row in overview.rows %} {% endfor %}
NameFiles MinutesLast heard Voice matchActions
{{ row.entry.speaker.display_name }} {{ verified_badge(row) }} {{ row.aggregate.files }} {{ format_duration(row.aggregate.seconds) }} {% if row.aggregate.last_seen %}{{ format_age(row.aggregate.last_seen, now=now) }}{% else %}never{% endif %} {{ tier_chip(row) }}
{{ actions(row) }}
{% else %} {% endif %} {% else %}

No speakers yet. Voices join the roster when you name them while reviewing a recording.

{% endif %} {% if overview.inactive %}
Former speakers ({{ overview.inactive|length }}) {% for entry in overview.inactive %}

{{ entry.speaker.display_name }} — {% if entry.merged_into_name %} merged into {{ entry.merged_into_name }} {% else %} archived

{% endif %}

{% endfor %}
{% endif %}