Repository navigation
Latency chart: plot the summary p95 over time, not the trace window #78
Description
Problem
Latency p95 over time collapses as traffic rises. The chart is derived from the in-memory trace window (TRACE_WINDOW = 500 rows) bucketed per minute (deriveP95), so the time it covers shrinks with load:
| traffic | 500 rows cover | 1-minute buckets |
|---|---|---|
| 1 req/s | ~8 min | 8 (a line) |
| 10 req/s | 50 s | 1–2 |
| 67 req/s | 7.5 s | 1 (a single dot) |
Measured during a 4,000-request burst: no polyline, one circle. The chart dies exactly when an operator needs it.
On a fresh connect it is worse: the first points come from the platform's ring-buffer dump, a few seconds of traffic from well before the connection, drawn under "over time".
The p95 card and the chart also disagree: the card shows the max of per-module metrics p95, the chart shows a value derived from the trace window, and neither is the platform's windowed summary.
Decision
The chart, the p95 card and the status mix are live widgets: they show what arrived after this connection, and a reload clears them. History is the trace table's job.
- Source. Plot
summary.p95LatencyMs, one point persummaryframe received after connecting. Sample spacing comes fromready.tickMs, which the platform declares, so no 1 Hz assumption. Each point is the p95 over the platform'swindowMs(60 s), sampled from at mostcapacityrows. The chart says both. - Time axis. The x axis spans the selected range and ends at now, not at the last point. When the stream goes quiet, the line slides left and the silence is visible. A chart pinned to its last point would look live while frozen.
- Draw what exists. Before the range fills, the left side stays empty. Axis end labels show the times. With no samples, the existing empty frame is kept.
- Gaps. The line breaks where two neighbouring points are more than
2 × tickMsapart (the same reasoning as the silence watchdog). Joining them would draw a measurement that was never taken. - Range option.
TimeRange(5m·15m·1h·6h) becomes a setting. The default is15m, and the value is shared across tabs like the other settings. - Buffer. Up to 6 h of points are always kept (21,600 at 1 s), whatever range is selected. Widening the range shows what has already arrived.
- p95 card. It reads
summary.p95LatencyMs, so the card equals the chart's last point. - Status mix. It stays count-based and says so ("last N requests").
summarycarries no per-status split. - Sample data. The generated curve is kept, already labelled
sample data(fix(chart): label the sample latency curve as sample data #74). It gets timestamps that fill the selected range. - Hover. The crosshair picks the point nearest in time.
TRACE_WINDOWstays unexposed. The setting the user gets is a time, not a row count.
Done when
- The chart no longer depends on the trace window: a burst of any size leaves it a line, not a dot.
- The connect dump does not reach the chart.
- A gap in the stream shows as a break in the line, and silence shows as empty space at the right edge.
- Scenario tests drive real connect sequences through the stream fixtures. Reverting the change makes them fail.
Activity
feat(chart): plot the summary p95 over time, not the trace window (#79)