Skip to content

feat(chart): plot the summary p95 over time, not the trace window - #79

Merged
htcom-code merged 1 commit into
mainfrom
feat/latency-time-axis
Oct 12, 2026
Merged

htcom-code merged 1 commit into
mainfrom
feat/latency-time-axis

Conversation

@htcom-code

Copy link
Copy Markdown
Owner

Closes #78

Why

The latency chart bucketed the in-memory trace window (500 rows) per minute, so the time it covered shrank with load. At 67 req/s that was 7.5 seconds, one bucket, and during a 4,000-request burst the chart was a single dot. On a fresh connect its first points were the platform's ring-buffer dump, seconds of traffic from before the page connected, drawn under "over time". The p95 tile showed the worst per-module p95 from metrics, a third source that agreed with neither.

What

  • Source. The chart plots summary.p95LatencyMs, one point per summary frame received on this page. Each point is stamped with the tick the ready ack stated, or 1 s when no ack arrives. Traces no longer reach the chart: traffic cannot shrink it, and the connect dump does not appear on it.
  • Time axis. The x axis spans the selected range and ends now, not at the newest point. When the stream goes quiet the line slides left, so a frozen chart no longer looks live. Before the range fills, the left side stays empty, so the axis shows how much has been collected. The ends are labelled −15m and now.
  • Gaps. The line breaks where two neighbouring points are more than 2 × tickMs apart, the same slack the silence watchdog uses. A point alone between two gaps is drawn as a dot, not a ramp.
  • Buffer. The series is page-scoped and holds up to six hours whatever range is selected, so widening the range shows what already arrived. It survives a rebuilt stream or a pause; a reload clears it.
  • Setting. New pc:chartRange (5m · 15m · 1h · 6h, default 15m). It is in the settings dialog and syncs across tabs through fix(settings): pick up changes made in another tab #76. It uses the TimeRange type, which had no users before.
  • Header. It names what a point is: ms · p95 of 60s · ≤200 traces, taken from summary.windowMs and ready.capacity. Anything the platform did not state is left out.
  • p95 tile. It reads summary.p95LatencyMs, so it equals the chart's newest point. It shows a dash until the first summary arrives instead of falling back to a different measurement.
  • Status mix. The header says last N req: it counts the newest rows in memory, not all traffic. summary has no per-status split, so this stays count-based.
  • Sample data. The curve is still labelled sample data. It now carries timestamps (every 15 s over 6 h), so it fills every range, and it is anchored to its own last point rather than the clock.
  • Removed. deriveP95 is gone. The dead REST snapshot path now returns an empty series because it has no summary.
  • Stale marking. The chart is now dimmed by the summary channel, which feeds it, instead of trace.

Verification

  • 20 net new tests (237 total). They drive the real hook with all three captured connect sequences and check the rendered geometry.

  • Revert checks: each old behaviour was put back one at a time, and the matching tests failed.

    Put back Tests that fail
    Right edge pinned to the last point 2
    Line never breaks 4
    Traces feed the series 5 (including the burst and connect-dump scenarios)
    Series reset on each connection 1
    Tile reads metrics 2
  • Browser, sample mode on vite: the chart draws on the time axis, the range setting reaches it (−6h, 1,441 points across the full width), and Status mix and the tile read as intended.

  • Not checked live: the backend was down, so a live run with gaps, silence and a burst against a real platform is still owed.

  • Gates: lint is clean (the same 7 warnings as main), and the build passes.

  • Full suite run serially: 237/237 here and 217/217 on main. In a parallel run on a heavily loaded machine (load average ~10), the IndexedDB timing scenarios (retention-limit, trace-window, quota-pressure) fail 2–3 at a time on main as well. This is existing flakiness and not from this change.

The latency chart bucketed the in-memory trace window (500 rows) per
minute, so the time it covered shrank with load. At 67 req/s that was
7.5 seconds, one bucket, and during a 4,000-request burst the chart was
a single dot. Its first points on connect were the ring-buffer dump,
seconds of traffic from before the page connected, drawn as "over time".

- The chart plots summary.p95LatencyMs, one point per summary frame
  received on this page, stamped with the tick the ready ack stated
  (1 s when none). Traces no longer reach it, so traffic cannot shrink
  it and the connect dump does not appear on it
- The x axis is time: it spans the selected range and ends now, not at
  the newest point. Silence slides the line left. Before the range
  fills, the left side stays empty. The line breaks where two points are
  more than two ticks apart, so an outage is not joined up
- The series is page-scoped and holds six hours whatever range is
  chosen. It survives a rebuilt stream and is cleared by a reload
- New setting pc:chartRange (5m, 15m, 1h, 6h; default 15m), using the
  TimeRange type that had no users
- The header names what each point is: "p95 of 60s" and the platform's
  capacity cap. Sample data stays labelled, fills every range and is
  anchored to its own last point
- The p95 tile reads summary.p95LatencyMs, so it equals the chart's
  newest point; it showed the worst per-module p95 from metrics before.
  It shows a dash until a summary arrives
- Status mix says "last N req": it counts the newest rows, not traffic
- deriveP95 is gone. The REST snapshot path returns no series, since it
  has no summary
- The chart is dimmed by the summary channel, which now feeds it

Closes #78

Tags: #chart #latency #honesty
Co-Authored-By: htjulia <htjulia1@gmail.com>
@htcom-code
htcom-code merged commit 7f4baba into main Oct 12, 2026
4 checks passed
@htcom-code
htcom-code deleted the feat/latency-time-axis branch October 12, 2026 05:36
htcom-code added a commit that referenced this pull request Oct 12, 2026
In sample mode the p95 tile printed 88 ms beside a curve ending in the
40s. Both are generated, but on a real platform the two are one number
since #79, and a demo that shows them disagreeing teaches the wrong
thing about the screen.

- mockSummary takes the sample series and reports its newest point as
  the p95, and the change from the point one window back as the trend
- A scenario pins it: the cold-start demo's tile equals the chart's
  newest point. Put the fixed 88 back and it fails

Tags: #sample #honesty
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.

Latency chart: plot the summary p95 over time, not the trace window

1 participant