The Lanes page now projects store.LatestLanePasses and the owner-window outcomes (store.LanePassOutcomes) into per-Site rows instead of reading an in-memory Poller snapshot, so a deploy answers the instant the store is up. Browser configuration is a config fact and reachability is derived from recent browser-Site passes inside latest.RefuseBackoff. This atomically deletes the in-memory path in the same commit that makes the page read the DB: latest/status.go (LaneState, Status, LaneStatus, recordLaneState) and the web.LaneReporter seam plus fakeLanes are gone, and latest.refuseBackoff is renamed latest.RefuseBackoff at every callsite. ownerWindow (#142) is referenced, never declared (contract C2)
2.0 KiB
ADR-0012: Persisted lane state
Date: 2026-08-21 Status: accepted
Supersedes the in-memory lane snapshot carried by latest's LaneState/Status
and the web.LaneReporter seam (ADR-0010 wrote the durable rows this page now
reads).
Decision
The admin Lanes page stops reading the poller's in-memory Lane state and
becomes a read of poll_passes/poll_lanes in Postgres. There is no
LaneReporter interface: web/admin_lanes.go walks store.LatestLanePasses()
into one row per Site and adds the window's outcome sums from
store.LanePassOutcomes(). The latest package's LaneState/Status snapshot
and its web.LaneReporter seam are deleted.
The browser is a deployment configuration fact plus a reachability derived
from the pass log: BROWSER_WS_URL set means "configured", and the browser is
"reachable" unless a recent browser-Site pass inside latest.RefuseBackoff is
a sidecar loss, a missing fetcher, or an interrupted read. A skip reason is
the whole difference between a Lane resting and a Lane stuck: a skipped pass
prints its sentence, and only an empty skip with Series due and none read
draws the true-stall fault. Sleep skips never count toward Attention.
Why
The old page lived on a poller snapshot. Because that state was in memory, a deploy erased it: the page read zeroes until a fresh pass ran, and browser reachability came through a reporter interface only a live poller could serve. Making the page answer from the database means a restart is complete the instant the store is up, the browser fact survives a poller restart, and a Lane that has not yet gathered figures shows a placeholder rather than a confident zero.
Constraints
The poller still owns the writes: each pass exit records one row (ADR-0010),
and a pass that returns before gathering figures carries the previous pass's
numbers forward instead of recording zeroes. A skip is a stable wire string;
asleep never counts toward Attention. When polling is switched off the
page must say so, and the browser statusline appears only when a poller
actually answers.