Files
mangaBookmark/docs/adr/0012-persisted-lane-state.md
T
sulthan fc8a40cfc6 fix(latest,web): finish the atomic deletion and honest empty states (#145)
Review fixes on top of cb2b104:
- Delete the write-only in-memory refuseUntil map and setRefusalBackoff now
  that status.go is gone: the pass gate reads the durable stamp, so the map
  was half-deleted dead state (spec review C-1).
- An outcome-query failure no longer blanks the Lane table into the false
  'no data yet': rows render with 'none observed' chips instead (I-1).
- due-query and eligible-count skips get their own sentences instead of the
  merged 'check failed' (I-2).
- ADR-0012 constrain wording corrected and trailing newline added (M-1)
2026-08-21 20:31:50 +07:00

2.1 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 (LATEST_CHAPTER_POLL_ENABLED unset) the page must say so, and the browser statusline appears only when polling is switched on.