Sean 4.6 / 4.7 / 4.9 / 4.10 on the occupancy drill-down, rendered
31 Aug 2026 · branch gera/sean-4-6-chart-behavior · captured against propflow-stage · at 9b69419f0f+local
Data note. Every name and balance below comes from propflow-stage, which is anonymized by construction (ADR-0097/0110 — phones in the impossible +1000 NPA, emails @example.test). The identical capture against prod would carry real tenants' names and balances and is not safe to attach anywhere, which is why the generator refuses to run against one.
The occupancy drill-down on the dashboard, where the roomy surface renders the details open by default. The rail under the plot sits at its full extent, and the stats strip and the drill-down table describe that same full window. Note the AVG cell and the number of rows: they are what the next capture is measured against.
Asserted in the captured DOM — AVG · LATEST · HIGH · LOW · DATE · VALUE. The stats strip and the drill-down table are both mounted, so the next section's readings are a comparison and not an appearance.
The same card, with the range-start handle driven inward. Before this PR the rail scaled the plotted curve and nothing else: TrendView owned the range in its own useState, and its comment said so — “Stats strip + data-points table downstream still receive the unbrushed current from MetricInsight.” Compare the AVG, the LOW and the row count against the capture above: all three moved together, because one range now drives all of it (MetricInsight owns brushRange; metric-insight/viewport-slice.ts restates the chart's own point-placement rule so the table lists exactly what the plot draws).
The floating pill above the handle is 4.9: it was 4×8px of 10.5px type in a saturated chip, and is now the app's floating-surface chrome — card ground, hairline border, the popover radius and shadow, 11.5px tabular type, with a notch pointing at its handle.
Asserted in the captured DOM — AVG · LOW · DATE · VALUE. Same four labels as the capture above — what changed is the numbers beside them, which is the whole claim.
The gesture the other captures could not see. Both of those drive Range start, which keeps the newest bucket in frame — so LATEST is unchanged in both and they cannot rule in or out whether the chart's own headline follows the rail. It did not: the big number read the full series' last bucket while LATEST in the strip followed the rail, so driving the end handle inward left the headline naming a bucket the viewport had clipped off the plot. That is a defect this PR introduced and round 2 caught.
Here the end handle is driven inward. The headline above the plot and LATEST in the strip name the same bucket, and the table's first row is that bucket. Four surfaces, one range.
Asserted in the captured DOM — Latest · · LATEST · AVG · DATE. The headline's own 'Latest ·' caption is asserted alongside the strip's LATEST, so the two are photographed in the same frame and can be read against each other.
The overflow menu, unopened toggle. The hint is not a description — it is the LABEL: 92.4% · 102 mo · Jan '18 – Jun '26. A reader knows what window is being averaged, and how many readings are behind it, before they ever turn the line on. The unit is derived from the record's own median gap rather than assumed, so a daily-backed metric opting into this control could not print “365 mo”.
Where the record is too thin to average (fewer than three readings) the toggle renders disabled and names the count actually on record. There is no back-fill and no average of one — a fabricated baseline on a real occupancy chart is the worst outcome available here.
Asserted in the captured DOM — Historical average · 102 mo · Jan '18. The reading count and the span are asserted in text, not just photographed — that sentence IS the honesty claim.
The overlay on. The dashed neutral rule sits at 92.4%, the unweighted mean of every one of the 102 readings on record — deliberately NOT the visible window, whose mean is the AVG cell in the strip below. On this capture the two happen to coincide because the rail is at full extent; narrow the rail (see the second capture, where AVG moved to 96.3%) and they separate, which is the entire point of the overlay.
The chip repeats the control's sentence verbatim — one helper produces both, so the two surfaces cannot come to describe the same line differently. The rule is --color-text-mid, not a brand hue: it is furniture the data is read against, and a coloured line would read as a second metric.
Asserted in the captured DOM — Historical average · 102 mo · Jan '18. The reading count and the span are asserted in text, not just photographed — that sentence IS the honesty claim.
4.10 is a pointer-lifecycle fix and photographs as nothing: a drag that no longer arms without its capture, a lostpointercapture handler so an OS-level steal cannot strand the rail, focus handed from the mouse to the arrow keys, a ~24px transparent hit band around the 6px painted track, and a press on bare track that centres the window and keeps panning. Those six are covered by ObservabilityChart.brush-drag.test.tsx, which drives the real pointer stream; 7 of its 10 cases fail against the pre-change component.
The end-handle capture exists because the first two could not have caught the headline defect: both drive the START handle, which keeps the newest bucket in frame, so LATEST is unchanged in both. A check that cannot fail on the axis it covers is not evidence. brush-drives-everything.test.tsx now pins the headline mechanically too.
The 4.6 claim above is also pinned mechanically rather than only shown: brush-drives-everything.test.tsx asserts the row count and the AVG move on the same gesture and that the printed average equals the mean of the rows on screen. A table-only assertion would have passed on the bug, which is why both live in one test.