From 5e77a141f3ff6e5726ff339bb031554a849eda69 Mon Sep 17 00:00:00 2001 From: htjulia Date: Mon, 12 Oct 2026 11:09:27 +0900 Subject: [PATCH] fix(chart): label the sample latency curve as sample data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With no platform reachable the console fills every card with generated data and the top bar says SAMPLE DATA. The latency chart was the one card that made a claim of its own on top of that: its header read "ms · rolling window", which a generated curve is not. - LatencyChart takes a sample flag; App sets it from conn.status. The header then reads "ms · sample data" and the aria-label says the values are generated - The curve stays: every other card shows sample values as well, so an empty chart would single this one out without making the screen more honest, and the demo would lose the card people explore first - Three tests cover the label, the curve, and the label going away once real samples arrive. With the component change reverted, the label test fails - Checked in the browser against a dev server with no platform: badge SAMPLE DATA, header "ms · sample data", polyline drawn - Gates: lint clean (same 7 warnings as main), 202 tests pass Tags: #chart #honesty Co-Authored-By: htjulia --- src/App.tsx | 2 +- src/components/latency-chart.test.tsx | 30 +++++++++++++++++++++++++++ src/components/latency-chart.tsx | 15 ++++++++++---- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index a11503f..739ced5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -89,7 +89,7 @@ export default function App() {
- + diff --git a/src/components/latency-chart.test.tsx b/src/components/latency-chart.test.tsx index 6f1bd7a..bbbcf68 100644 --- a/src/components/latency-chart.test.tsx +++ b/src/components/latency-chart.test.tsx @@ -141,6 +141,36 @@ describe('latency chart with no samples', () => { }) }) +describe('latency chart on sample data', () => { + afterEach(cleanup) + + /** + * With no platform the console draws a generated curve. The top bar says SAMPLE + * DATA, but this header said "rolling window" — a claim about where the numbers + * came from that a generated curve cannot make. The header has to say it instead. + */ + it('says the curve is sample data, not a window', () => { + const { getByText, queryByText, getByRole } = render() + expect(getByText(/sample data/)).toBeTruthy() + expect(queryByText(/rolling window/), 'a generated curve claimed to be a window').toBeNull() + expect(getByRole('img').getAttribute('aria-label')).toMatch(/sample data/) + }) + + it('still draws the curve, so the demo stays explorable', () => { + // Every other card shows sample values too; an empty chart beside them would + // single this one out without making the screen any more honest. + const { container } = render() + expect(container.querySelector('polyline')).not.toBeNull() + }) + + it('drops the label once real samples replace it', () => { + const { getByText, queryByText, rerender } = render() + rerender() + expect(getByText(/rolling window/)).toBeTruthy() + expect(queryByText(/sample data/)).toBeNull() + }) +}) + describe('status mix', () => { afterEach(cleanup) diff --git a/src/components/latency-chart.tsx b/src/components/latency-chart.tsx index 976ffa7..7020808 100644 --- a/src/components/latency-chart.tsx +++ b/src/components/latency-chart.tsx @@ -33,8 +33,15 @@ function niceTicks(max: number, count = 4): number[] { */ const EMPTY_SCALE_MAX = 100 -/** Single-series p95 latency area with a crosshair+tooltip. One hue (telemetry), no legend needed. */ -export function LatencyChart({ series }: { series: number[] }) { +/** + * Single-series p95 latency area with a crosshair+tooltip. One hue (telemetry), no legend needed. + * + * `sample` marks a series this console generated because no platform answered. The + * top bar already says SAMPLE DATA, but the chart is the one card whose header made + * a claim of its own — "rolling window" — and a generated curve is not a window onto + * anything. The header names what it is instead. + */ +export function LatencyChart({ series, sample = false }: { series: number[]; sample?: boolean }) { const gradId = useId() const svgRef = useRef(null) const [hover, setHover] = useState(null) @@ -67,7 +74,7 @@ export function LatencyChart({ series }: { series: number[] }) { Latency p95 over time - {empty ? 'ms · default scale' : 'ms · rolling window'} + {sample ? 'ms · sample data' : empty ? 'ms · default scale' : 'ms · rolling window'}
@@ -77,7 +84,7 @@ export function LatencyChart({ series }: { series: number[] }) { className="block h-[190px] w-full touch-none" preserveAspectRatio="none" role="img" - aria-label="p95 latency over the rolling window" + aria-label={sample ? 'p95 latency, generated sample data' : 'p95 latency over the rolling window'} onPointerMove={onMove} onPointerLeave={() => setHover(null)} >