Only TrailBook was covered; the HA-facing half — subscription callback,
attribute dialects, map-id resolution, run end on docking — had no test
at all. It does now, against a stubbed hass, which is also where the
missing behaviour showed up: recording started at the NEXT state change,
so an HA restart (or finishing calibration) mid-cleanup dropped the
opening seconds of the path. Sampling is factored out and runs once per
source on setup and on every refresh.
The integration now records the path itself (trails.py): it watches the
source entity's state changes, so recording needs no open card, has no
multi-tab write races, and every screen sees the same line — reloads
included, which retires the localStorage snapshot after one day of
life. Stored per marker: the current run plus exactly one previous
(owner call — users want cleaned-vs-uncleaned at a glance). The
previous run renders at 40% opacity; the current one still trims its
live tail so it never outruns the puck. Runs rotate on start or map
switch, points cap at 2000 with decimation, store writes debounce 10 s,
and houseplan_trail_updated pushes live cards. TrailBook is pure under
5 backend tests; the WS command degrades silently on older backends.