{# One speaker's web-research block (issue #40): latest job + start/cancel + reviewable profile drafts. Included per roster card AND served standalone by GET /speakers/{id}/research — the div re-polls itself only while a job is active, so a terminal render stops the polling. #}
Web research {%- if research.proposed %} ({{ research.proposed|length }} draft{{ "s" if research.proposed|length != 1 }} to review){% endif %} {% if research.error %}{% endif %} {% if research.job %}

Job {{ research.job.status }} · {{ research.job.searches_used }}/{{ research.job.budget.max_searches }} searches · {{ research.job.reads_used }}/{{ research.job.budget.max_reads }} reads · {{ research.job.rounds_used }}/{{ research.job.budget.max_rounds }} rounds {% if research.job.started_at %} · started {{ research.job.started_at.strftime("%Y-%m-%d %H:%M") }} {% else %} · queued {{ research.job.created_at.strftime("%Y-%m-%d %H:%M") }} {% endif %} {% if research.job.error %}
{{ research.job.error }}{% endif %}

{% if research.job_active %}

Cancel stops the job before its next round — an in-flight fetch finishes first.

{% endif %} {% endif %} {% if not research.gates_open %}

Web research is off. It needs the web-research feature enabled, a configured search provider, and LLM transcript enhancement — set these up in Settings.

{% elif not research.job_active %}

Budget: at most {{ research.budget.max_searches }} searches, {{ research.budget.max_reads }} page reads, {{ research.budget.max_rounds }} tool rounds, {{ research.budget.deadline_seconds|int }}s wall clock. Findings appear below as drafts with their sources — nothing is applied until you accept it.

{% endif %} {% for view in research.proposed %}

{{ view.candidate.field }}: {{ view.candidate.value }}

{# Review-priority ordering (issue #42): raw facts, not a probability. #} {% set t = research.triage.get(view.candidate.id) %} {% if t %}

review priority {{ "%.2f"|format(t.priority) }} — {{ t.components.distinct_domains_count|int }} distinct evidence domain{{ "s" if t.components.distinct_domains_count|int != 1 }}{% if t.components.source_authority %}, {{ "%.0f"|format(t.components.source_authority * 100) }}% authority-listed{% endif %}{% if t.components.corroborated %} · corroborated{% endif %}

{% endif %} {% for e in view.evidence %}{% if e.url %}

source: {# Defense-in-depth: only http(s) values ever become an active link. #} {% if e.url.startswith("https://") or e.url.startswith("http://") %} {{ e.url }} {% else %}{{ e.url }}{% endif %} {% if e.retrieved_at %}(fetched {{ e.retrieved_at.strftime("%Y-%m-%d %H:%M") }}){% endif %}

{% if e.snippet %}
{{ e.snippet }}
{% endif %} {% endif %}{% endfor %}
{% endfor %} {% if research.decided_count %}

{{ research.decided_count }} decided draft{{ "s" if research.decided_count != 1 }} in history.

{% endif %}