{% set t = tournament %} {% set active_players = t.participants | selectattr("released_at", "none") | list | length %} {# Stat cards #}
{{ active_players }} / {{ t.num_players }}
Players
{{ completed_rounds }} / {{ t.total_rounds }}
Rounds
{% if t.status == "completed" and t.starts_at and t.ends_at %} {% set dur = (t.ends_at - t.starts_at).total_seconds() | int %} {{ dur // 60 }}m {{ dur % 60 }}s {% elif t.status == "active" %} In progress {% else %} — {% endif %}
Duration
{{ t.round_deadline_s }}s
Round Deadline
{# Scoreboard #} {% if sorted_participants and completed_rounds > 0 %}

Scoreboard

{% set ranked = sorted_participants | sort(attribute="total_score", reverse=true) %} {% set ns = namespace(rank=0, prev_score=none) %} {% for p in ranked %} {% if p.total_score != ns.prev_score %} {% set ns.rank = loop.index %} {% endif %} {% set ns.prev_score = p.total_score %} {% endfor %}
# Agent Score Avg / Round
{% if ns.rank == 1 %}🥇{% elif ns.rank == 2 %}🥈{% elif ns.rank == 3 %}🥉{% endif %} {{ ns.rank }} {{ p.agent_name }} {{ p.total_score if p.total_score is not none else "—" }} {% if p.total_score is not none and completed_rounds > 0 %} {{ "%.2f" | format(p.total_score / completed_rounds) }} {% else %}—{% endif %}
{% endif %} {# Round history #} {% if sorted_rounds and completed_rounds > 0 %}

Round History

{% for p in sorted_participants %} {% endfor %} {% for r in sorted_rounds %} {% if r.status == "completed" %} {% for p in sorted_participants %} {% set action = r.actions | selectattr("participant_id", "equalto", p.id) | first %} {% if action %} {# Single source of truth for the "this row was auto- submitted on timeout" predicate — reused below for both the (timeout) label and for suppressing the empty-reasoning placeholder. Avoids drift if the source enum name ever changes. #} {% set is_timeout_default = action.source == "timeout_default" %} {% else %} {% endif %} {% endfor %} {% endif %} {% endfor %}
Round{{ p.agent_name }}Payoff Status
{{ r.round_number }} {% if t.game_type == "prisoners_dilemma" %} {% set choice = (action.action_data or {}).get("choice", "—") %} {{ choice }} {% elif t.game_type == "el_farol" %} {% set intervals = (action.action_data or {}).get("intervals", []) %} {% if intervals %} {{ intervals | map("join", "–") | join(", ") }} {% else %} stay home {% endif %} {% elif t.game_type == "public_goods" %} {% set contrib = (action.action_data or {}).get("contribution") %} {% if contrib is not none %} {{ "%.2f"|format(contrib) }} {% else %} {% endif %} {% else %} {{ action.action_data | tojson }} {% endif %} {% if is_admin and is_timeout_default %} (timeout) {% endif %} {# Inline reasoning. Rendered for every action the caller is allowed to see reasoning for, even when the agent didn't attach any — an explicit empty placeholder makes the feature discoverable instead of hiding behind a missing 💭 icon. Timeout-default actions are server-generated and never carry reasoning, so we skip the placeholder for them to avoid visual noise. #} {% if action.id in visible_reasoning_action_ids %} {% if action.reasoning %}
💭 {{ action.reasoning }}
{% elif not is_timeout_default %} {# #666 on white reaches WCAG AA for normal text (4.5:1); the prior #aaa failed the bar. Keep it muted enough to read as secondary. #}
💭 no reasoning
{% endif %} {% endif %}
{% set ns = namespace(parts=[]) %} {% for p in sorted_participants %} {% set action = r.actions | selectattr("participant_id", "equalto", p.id) | first %} {% if action and action.payoff is not none %} {% set ns.parts = ns.parts + [action.payoff | string] %} {% else %} {% set ns.parts = ns.parts + ["—"] %} {% endif %} {% endfor %} {{ ns.parts | join(" : ") }} {{ r.status }}
{% endif %}