diff --git a/docs/plans/2026-04-25-run-detail-improvements-design.md b/docs/plans/2026-04-25-run-detail-improvements-design.md new file mode 100644 index 0000000..78c75de --- /dev/null +++ b/docs/plans/2026-04-25-run-detail-improvements-design.md @@ -0,0 +1,128 @@ +# Run Detail Improvements — Design + +**Date:** 2026-04-25 +**Scope:** `run-detail.js`, `style.css` +**Pages affected:** Run detail (`/runs/:id`) + +## Goal + +Make the run detail page the best possible trace viewer for diagnosing what an agent did and what went wrong. Three focused improvements: surfacing prompt and error context in the header, adding span filter/search, and upgrading the waterfall to an interactive view. + +--- + +## Section 1: Run Header — Prompt Preview & Error Detail + +### Prompt preview strip + +Below the meta-tiles, add a collapsible block showing the first ~200 characters of the run's prompt. The data is already returned by `/v1/runs/:id` via `payload.prompt_preview` or `payload.message_preview` on the `run.start` event — it is just not currently rendered. + +- Styled as a `
` block inside a callout pill
+- Muted background (`var(--surface-2)`), monospace font, left border in `var(--accent)`
+- "Show more" expands to the full text inline; "Show less" collapses it
+- Only rendered when `prompt_preview` is non-empty
+
+### Error detail callout
+
+When `r.status === 'error'`, render a prominent callout box between the meta-tiles and the spans section.
+
+- Pulls error message/stack from the first error-status span's payload, or from the `run.end` event payload
+- Left border in `var(--error)`, background in `var(--error-bg)`, message in monospace
+- Copy button on the error message
+- If no error detail is available in the payload, shows a minimal "Run ended with error" notice
+
+### Files touched
+
+- `cmd/web-ui/static/modules/pages/run-detail.js` — `renderRun()` only
+- `cmd/web-ui/static/style.css` — new callout/prompt-preview rules
+
+No API changes required.
+
+---
+
+## Section 2: Span Filter & Search Bar
+
+Add client-side filtering controls above the spans container. No API calls — filtering operates on the `spans` array captured at render time.
+
+### Controls
+
+**Text search input**
+- Filters span rows in real time by matching against span name (case-insensitive substring)
+- Clears on `✕` button click or `Escape`
+- Filter persists when switching between Table and Waterfall views
+
+**Kind filter pills**
+- One pill per span kind present in the current run (`tool`, `agent`, `unknown`, etc.)
+- Pills are generated dynamically from the spans array — only kinds that exist are shown
+- Multiple kinds can be active simultaneously; all active = show all
+- Clicking a pill toggles it; at least one must remain active
+
+**Errors-only toggle**
+- Binary toggle: `All` / `Errors only`
+- When active, only spans with `status === 'error'` are shown
+
+### Filter state
+
+```js
+let spanFilter = { query: '', kinds: new Set(), errorsOnly: false };
+```
+
+Filter state is module-level, reset on `cleanup()`.
+
+### Integration with views
+
+- **Table view:** Non-matching rows are hidden (`display: none`)
+- **Waterfall view:** Non-matching bars are dimmed (`opacity: 0.2`) rather than hidden — so the timescale and relative positioning remain meaningful
+
+### Files touched
+
+- `cmd/web-ui/static/modules/pages/run-detail.js` — `renderRun()`, `renderRunSpansRows()`, `renderSpanWaterfall()`, new `applySpanFilter()` helper
+- `cmd/web-ui/static/style.css` — filter bar layout, pill styles
+
+---
+
+## Section 3: Waterfall — Hover Detail & Visual Improvements
+
+### Hover tooltip
+
+Replace the plain `title` attribute on waterfall bars with a styled floating tooltip.
+
+**Tooltip contents:**
+- Span name and kind badge
+- Duration and start offset from run start
+- Status
+- One-line payload preview (tool input snippet or token count)
+
+**Implementation:**
+- Single shared tooltip DOM element, positioned via `mousemove` on the waterfall container
+- Hidden on `mouseleave`
+- No per-row DOM overhead
+
+### Clickable bars → inline detail drawer
+
+Clicking a waterfall bar opens an inline detail drawer below that waterfall row, rendering the same `renderSpanPayload()` content used in the table view. A second click collapses it. At most one drawer open at a time.
+
+### Visual polish
+
+- **Minimum bar width:** Raised so short-duration spans remain clickable
+- **Error spans:** Pulsing red left edge (consistent with `tr-error` in table view)
+- **Timescale ticks:** Snap to human-friendly intervals (100ms, 500ms, 1s, 5s, 10s, 30s, 1m) rather than always dividing into 5 equal parts
+
+### Filter integration
+
+Spans dimmed by the Section 2 filter get `opacity: 0.2` on their bars. They remain positioned correctly for timing context.
+
+### Files touched
+
+- `cmd/web-ui/static/modules/pages/run-detail.js` — `renderSpanWaterfall()`, new `bindWaterfallInteractions()` helper
+- `cmd/web-ui/static/style.css` — tooltip, drawer, error pulse rules
+
+---
+
+## Summary of changes
+
+| File | Sections |
+|------|----------|
+| `cmd/web-ui/static/modules/pages/run-detail.js` | 1, 2, 3 |
+| `cmd/web-ui/static/style.css` | 1, 2, 3 |
+
+No backend changes. No new dependencies. All data already returned by existing API endpoints.