Repository navigation
Closed
Labels
ready-for-agentFully specified, ready for an AFK agentFully specified, ready for an AFK agent
Description
Parent
What to build
Build #995's design.
- The span tree grows out of the Waterfall for any Command with Session traces: its Runs, stages, sessions, model calls and tool calls.
- Span details: selecting a span shows its details in the Peek panel.
- A CLI command with
--jsongives the same data, as every Console view has one (ADR 0016).
Acceptance criteria
- Route and browser tests show the tree for a Command with child Runs, and a selected span's details.
- It fits a 390 px phone.
- The same data comes from the CLI with
--json.
Design (settled in #995)
Settled with Jacob in #995's prototype: layout E, a tree with a timeline and the slowest calls, and Peek layout 3, a summary card. The prototype is the primary source: src/console/span-tree-prototype/ on the issue-995-prototype branch. Run it with real Session traces as its README says, and open ?variant=E&details=3. It is throwaway code: rebuild it properly, don't copy it.
The span tree
- One tree below the Waterfall's Command chips: Command › Runs › stages › sessions › model calls, tool calls and sub-agents. A child Run nests under the stage it started in. A sub-agent's calls nest under it. A session that several stages name (the "pull request" stage reuses the implement session's Session trace) sits under the first stage that names it.
- Each row has a disclosure triangle, a kind tag (
cmd,run,stage,sess,model,turn,tool,agent), the name truncated with an ellipsis, a status mark, a duration column, and a bar on one shared time axis. The status mark is ✕ for an error, with its message as the tooltip, or ● for running. The duration gets a*when the time is estimated. The axis ticks are relative:+0 ms,+40m 48s, … - Bars distinguish tool calls from model calls, errors, running calls and estimated times. A running call is hatched and extends to now. An estimated time is dotted.
- Folding: the Command, Runs and stages start open, and sessions start folded. A row of buttons expands to Runs, stages, sessions or every call. A folded parent shows its error count and the ranks of any slowest calls inside it, such as
▸ #1 #2 #3. - Keyboard: the ARIA tree pattern. ↑ ↓ (and j k) move; → expands or goes to the first child; ← folds or goes to the parent; Enter or Space opens the Peek.
Slowest calls
- A foldable list above the tree, open by default: the ten slowest tool and model calls in the timeline's current scope. Codex
turnspans span their own tool calls, so they would crowd them out; they are left out, as are sub-agent spans. - Each entry has a rank badge, the kind tag, the name, its start → end clock times (
→ nowwhile running), the duration, and "N% of its · # · session". - The tree marks the same calls: the rank badge on the row and a highlighted bar.
- Clicking an entry unfolds the tree to the call, selects it, opens its Peek, and brings its row into view.
Zooming the timeline
- The Peek's button: on a call it reads "Zoom timeline around this call" and shows a window around the call. On a span with children it reads "Zoom timeline to this " and fits the axis to that span.
// Around a call: show what ran just before and after it. const pad = Math.max(call.duration, 1000) * 1.5; axis = { start: Math.max(parent.start, call.start - pad), end: Math.min(parent.end ?? now, call.end + pad) };
- The zoom notice is pinned in the sticky axis header: "Timeline zoomed around : → ()", plus a Zoom out to whole Command button. The name stays on one line. The Peek's button also becomes "Zoom out to whole Command".
- While zoomed, rows outside the window are dimmed and the slowest list re-ranks within the window.
- A row brought into view (after zooming or from the slowest list) stays below the sticky header and, on a phone, above the Peek's bottom sheet. Centre it in what's left visible.
Span details in the Peek (summary card)
- The path of ancestors, as links that reveal and select that span.
- Then: the kind tag and the name as the heading, the status, the start → end clock times, and an "estimated" marker.
- Tiles, only those that apply: duration, % of its parent, tokens in / out, cost, model / tool call counts, errors.
- Two small bars: where the span sits within its parent, and within the Command.
- Actions: the zoom button, Open in conversation (the conversation view at this record), and Copy CLI.
- Input, open: a tool call's arguments as pretty JSON, a session's Session prompt, or a sub-agent's description. Output, All attributes and an Overview table (kind, status, times, model, Harness, tokens with the cache split, cost, span ID) are folded below. A model call's span carries no text, so its Peek says the text is in the conversation view.
Phone (390 px) and laptop
- Laptop: the Peek sits beside the tree, as
body.peek-opendoes today. Tree rows are a grid: label · duration (7ch) · bar. - Phone: the label takes a full-width line, with the bar and duration on a line under it. The indent is 8 px per level, and there are three axis ticks. The Peek is today's bottom sheet. A slowest-calls entry wraps to name, then times and duration, then where it ran.
CLI
The tree and one span's details come from the CLI with --json. The prototype showed thirdshift logs <command> --spans --json and --span <id> as a placeholder; name it as ADR 0016 and the existing commands suggest.
What the real data showed
- Converted Session logs carry estimated times that can overlap. A converted session can start at the Command's start: Find what still makes the macOS test shards slow after #857 #894's Security review session claims 3h 24m in a 40 s stage. A converted model call is estimated to last until the next event, so it absorbs the wait of the tool call it made. The tree tolerates both; mark estimated times with
*. A flame chart could not, which is one reason layout C lost. - Sub-agent spans that never ended (status "call did not end") stretch to the session's end.
- Codex sessions have no model-call spans: one
turnspan carries the usage, and the tool calls sit flat under the session, hundreds of them in Spec: Session traces, OTLP JSON Lines in place of Session logs #700's Runs. - Session spans repeat their calls' token totals, so don't add a session's tokens to its children's.
- Upper levels: use the span IDs computed from the Command record, as Spec: Session traces, OTLP JSON Lines in place of Session logs #700 says. The prototype used stand-in hashes.
What the static prototype didn't show
The prototype was a static page over one snapshot. The build also needs these.
- The tree replaces today's Waterfall body (each Run's section with its stage and tool bars), as layout E did. It shows the same Runs, stages and calls, and more. The Command chips and the page's CLI line stay.
- Command details stay reachable. Today a Run's heading opens the Command's Peek, with Stop, the logs and the pull request. The prototype gave Command and Run rows the summary card instead. Keep both: the card for the span, and a link to the Command details.
- Live updates: the Waterfall refreshes while a Command runs. Folding, zoom, selection and the open Peek survive each refresh, running calls grow to now, and the slowest list may re-rank.
- Scale: a Run's session can hold hundreds of tool calls (Spec: Session traces, OTLP JSON Lines in place of Session logs #700's Runs total about 2,200). Render a session's calls only once it is unfolded.
- Commands without Session traces still show their Runs and stages from the Command record, with no sessions under them.
- Open in conversation links to the conversation view at that span's record. If the view can't anchor a record, link to the session's conversation.
Metadata
Metadata
Assignees
Labels
ready-for-agentFully specified, ready for an AFK agentFully specified, ready for an AFK agent
Activity
JacobStephens2 commentedon Oct 22, 2026
Closed by #1107, merged into issue-700-branch-2 by a thirdshift Merge run.