{# P2-T02 / P2-T03 / P2-T04 / P2-T06 / P2-T16 — per-step LLM Explorer. Renders one ``llm`` step from a scan's trace. The chrome (eyebrow, breadcrumb, card frames, palette) reuses the T55 admin tokens; this page only adds its own local rhythm (data grid, prompt/response side-by-side pre blocks, comparisons table styling). No Tailwind. No emojis. Vanilla JS only — used twice: once to lazy-fetch the S3 dump (P2-T03), once to wire the copy-curl button (P2-T04). Both helpers run < 80 LOC. Inputs (assembled by ``routes.debug._llm_step_view``): * ``view.scan_id`` / ``view.scan_id_short`` * ``view.step_index`` / ``view.step_index_padded`` / ``view.total_step_count`` * ``view.step_name`` / ``view.status_label`` / ``view.status_pill_class`` * ``view.duration`` / ``view.cost`` / ``view.model`` * ``view.llm_call_id`` / ``view.dump_url`` (lazy fetch target) * ``view.metadata_rows`` — list of ``{key, value}`` rendered as a data grid * ``view.comparisons`` — list of pre-formatted row dicts; empty list when the operator has never re-run this step * ``view.copy_curl_payload`` — JSON-safe dict spliced client-side into the clipboard-ready curl string * ``view.back_to_trace_url`` Re-run / mutation flows (P2-T07-T09) intentionally land later; this page renders a placeholder card for that section. #} {% extends "admin_layout.html" %} {% from 'partials/help_tooltip.html' import tip, tip_styles %} {% from 'partials/notifications.html' import notify_styles %} {% block page_title %}admin :: step :: {{ view.scan_id_short }} / {{ view.step_index_padded }}{% endblock %} {% block breadcrumb %} admin/ scans/ {{ view.scan_id_short }}/ step {{ view.step_index_padded }} {% endblock %} {% block head_extra %} {{ tip_styles() }} {{ notify_styles() }} {% if view.is_in_progress %}{% endif %} {% endblock %} {% block content %} {# ============== Sticky breadcrumb strip ============== #}
{{ view.owner_email }}
{% endif %}
{{ fx.id_short }}
{{ fx.outcome_label }}
{{ tip("The experiment pointed at by ?focus_experiment. Shows the full result -- including the error message when it failed -- so a failed re-run is diagnosable.") }}
{% if fx.system %}{{ fx.system }}{% else %}// (empty){% endif %}
{% if fx.user %}{{ fx.user }}{% else %}// (empty){% endif %}
{{ fx.response }}
{% elif fx.errored %}
// errored before a response was produced
{% else %}
// (no response body)
{% endif %}
| when {{ tip("Relative time since the experiment fired.") }} | model {{ tip("Model the experiment ran against.") }} | edits {{ tip("Whether the prompts were edited vs the source call (today this is a coarse 'none / edited' signal; P5 ships a semantic diff).") }} | cost {{ tip("Cost the experiment billed to the admin's daily cap.") }} | latency {{ tip("Wall-clock SDK call duration on the experiment.") }} | outcome {{ tip("Aligned: parseable, no error. Errored: ran but the response was missing or unparseable.") }} | fired by {{ tip("Admin who fired the experiment; the truncated handle is the local-part of their email.") }} | {{ tip("Diff view: opens this step page with the experiment focused (?focus_experiment={exp_id}). The cross-scan index lives at /admin/experiments.") }} |
|---|---|---|---|---|---|---|---|
| {{ row.when_rel }} | {{ row.model }} | {{ row.edits_flag }} | {{ row.cost }} | {{ row.latency }} | {{ row.outcome_label }} | {{ row.fired_by }} | {# P5-T03: step-focused diff link (?focus_experiment={exp_id}). #}diff → |