Skip to content

Fix scout traces show rendering span durations ~1000x too small - #31

Open
quinnmil wants to merge 3 commits into
mainfrom
26-traces-show-duration-units
Open

quinnmil wants to merge 3 commits into
mainfrom
26-traces-show-duration-units

Conversation

@quinnmil

Copy link
Copy Markdown
Contributor

Closes #26

Summary

scout traces show rendered every span's duration ~1000x too small, which silenced the whole visualization: bars always collapsed to the 1-block minimum, the yellow/red color thresholds could never trigger, and the ⚠ slow warning was unreachable.

Root cause: the API reports a span's duration_ms / exclusive_duration_ms in seconds, despite the key name. renderSpan formatted the raw value as milliseconds, so an 8-second span printed "8ms," and the bar-fill ratio against the trace total was always ≈0.001.

Fix

Renamed TraceSpan.DurationMs/ExclusiveDurationMs to DurationSeconds/ExclusiveDurationSeconds so the real unit is explicit in the Go types (JSON tags keep the API's wire names, so --json output is unchanged), and scale to milliseconds once at the point of use in renderSpan for both the printed label and the bar-fill ratio.

Verified live

Checked against real trace data on an authenticated account: before the fix, a span's printed duration and the trace header's total duration disagreed by ~1000x; after, they agree, and a trace's duration_in_seconds matches the sum of its root-span durations to six decimal places across several traces. With the fix, a root span filling the whole trace renders fully red with the slow warning, a span at roughly half the trace's duration renders mostly-filled in yellow with the warning, and a small span renders a single filled block in green with no warning — all three color thresholds and the warning are reachable again.

Tests

  • Updated the existing memory-footer test to use internally consistent (seconds) values.
  • Added two new tests: one asserting a span's rendered duration matches the trace header when the span spans the whole trace, and one asserting the bar-fill block counts and the slow warning for a 60%-of-trace span versus a 5%-of-trace span.

Test plan

  • gofmt -l cmd internal (clean, aside from a pre-existing unrelated file)
  • go vet ./...
  • go build
  • go test -race ./...
  • golangci-lint run ./... (0 issues)
  • Live verification against real trace data (described above, no account-specific details included)

🤖 Generated with Claude Code

https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS

quinnmil and others added 3 commits September 11, 2026 10:23
Every open PR editing CHANGELOG.md's `## Pending` section directly meant
any two concurrent PRs collided on the same lines, and each merge forced
the next PR to redo the conflict resolution. Add changelog.d/, where each
PR drops a new file instead of editing the shared section, so concurrent
PRs can never conflict on this axis. scripts/assemble_changelog.py folds
the fragments into a versioned CHANGELOG.md section at release time.

See changelog.d/README.md for the fragment format and
.claude/commands/release.md for the updated release process (not
committed here — .claude/ isn't tracked in this repo yet).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS
The API populates a span's duration_ms and exclusive_duration_ms keys with
values in seconds, not milliseconds. renderSpan formatted the raw value with
FormatMs, so an 8-second span printed as "8ms", and the bar-fill ratio against
the trace total was always ~0.001. Every bar collapsed to the 1-block minimum,
the yellow/red color thresholds never fired, and the "slow" warning was
unreachable.

Rename the fields to DurationSeconds/ExclusiveDurationSeconds so the real unit
is explicit, keeping the JSON tags on the API's wire names, and scale to
milliseconds at the point of use. TOON output now shows the accurate field
names; --json keys are unchanged.

Closes #26

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS
Drop changelog.d/ and the assembly script — decided the fragment-file
system was more process than this repo's PR concurrency warrants.
Move this PR's changelog entry into CHANGELOG.md's Pending section
directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BK3fzED9ksTWsvoPfsEwpS
@quinnmil
quinnmil force-pushed the 26-traces-show-duration-units branch from f7f50f1 to d5e75ae Compare September 11, 2026 17:26

@mitchh456 mitchh456 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified against the API serializer — duration_ms is seconds, so the scaling direction is right; the bar-fill and slow-threshold paths now have direct test coverage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

scout traces show: span durations render ~1000x too small (bars, colors, slow-warning all dead)

2 participants