When a manager-researcher-writer scaffold spends $24 a week instead of $17, the question isn't 'which arm' — it's 'which agent'. Winnow's B7 agent rollup turns per-span agent_id tags into one cross-trace cost table and one per-trace span tree, both colored by the same agent palette.
Multi-Agent Cost: Make the Dominant Agent Visible
A cost alert fires on agent-pricing-rollout-v2: $24.18 this week, $17.04 last. The arm-level chart doesn't help — every arm is up. The model-level breakdown doesn't help either — same model across the board. The actual answer is researcher is dumping every web_search result verbatim into context, but that fact lives buried in the span trees of 1,247 traces.
The fix is one cross-trace rollup table and one per-trace span tree, both colored by the same agent palette.
Where it lives
Winnow's B7 agent rollup ships as two surfaces that share one data source:
- Scorecards → Agents tab (cross-trace). A table reading
GET /api/v1/experiments/{id}/agents. One row per agent, sorted by total cost descending. The dominant agent (≥50% of cost share) gets a red row tint and aDOMINANTchip so the eye lands on it without scanning. - Traces → Group by Agent (per-trace). The existing span tree on
/traces/{id}already had a Nesting / Agent toggle from the P4 trace-detail page; this slice makes the Agent mode read real numbers fromGET /api/v1/traces/{id}/agents— each agent bucket header shows span count, total cost, sum latency, and mean score for that agent on this trace.
Both surfaces use the same color hash on agent_id, so an agent's red badge on the cross-trace table is the same red badge on every span it emitted in any trace.
What it answers
Three questions, each in one click:
- Which agent dominates cost? Cross-trace table, sorted desc. Top row.
- Why is that agent expensive on this trace? Click into a trace, switch to Group by Agent, read the per-agent bucket header for span count + total cost. Inside the bucket, the individual spans show their own cost / model / latency.
- Is this an outlier or a pattern? Compare per-trace cost (bucket header) vs cross-trace mean (Agents tab). If a trace's agent cost is 3× the cross-trace mean, it's a single-trace outlier; if it tracks the mean, the agent's prompt itself needs a rewrite.
Honesty about what isn't built yet
This first slice ships the rollup tables and the per-span colored badges. Four follow-ups are explicitly tracked in docs/UNBUILT-FEATURES.md P2:
- A typed
pass_count/fail_count/error_counton the rollup row so the Agents tab can render a real pass-rate column (today it shows mean score with sample count — honest, but missing from the mockup's four-column shape). - An additive
agent_rollupsfield onScorecardData.metricsso the existingBreakdownToggleon the Overview tab can grow a fourthagentpill alongside Arm / Model / Harness. - An
?agent_id=filter on the experiment-scoped trace list so each agent row on the Scorecard tab is a one-click jump into a filtered trace list, not a tab-switch + manual scan. - A
cost_by_agent_threshold_crossedPR-comment renderer so cost concentration becomes visible to reviewers in the same place they review code.
The per-span agent_id tagging is the SDK contract the rollup reads — record_observation(..., agent_id=...) was shipped 2026-05-19 in the storage migration that added the indexed observations.agent_id column. The cross-trace rollup endpoint shipped 2026-05-21. This slice is the UI consumer for both.