Overview page: a verdict line, and a stats block where every figure is a door #143

Closed
opened 2026-08-21 16:39:21 +07:00 by sulthan · 1 comment
Owner

Parent

Spec #134.

What to build

The owner opens the landing page and decides in one glance whether to keep reading or start investigating. One line leads: a verdict, how many Series are waiting, how many have not been checked in twelve hours -- fully database-computed. The waiting figure sums due over the latest pass per Site; the stale figure counts Series with a series URL whose check stamp is older than the window. The verdict says all lanes healthy when nothing needs attention, otherwise how many lanes need attention rather than just "unhealthy", so the owner knows the size of the problem before clicking. With no pass rows at all it says no Lane has reported yet rather than drawing confident zeroes -- "nothing has happened" must never render as "everything is fine". That state does not disappear; it narrows from after every deploy to a virgin database.

One window constant, twelve hours, in the web package, feeding both the staleness cutoff and the outcome window. Twelve hours because the owner looks once by day and once by night and each look should cover the interval since the last. It is a human threshold, deliberately not a multiple of the Lane's rest, and the page reads the database rather than the poller so it could not follow the Lane's pace anyway. Two differently-named twelve-hour constants on one page is how they drift apart.

Then a stats block: library size and the manga/novel split, the roster count, and the eight hygiene counts both library-wide and per Site. Every figure is an entry point, not only the hygiene ones -- the total to the unfiltered list, the Library split to a Library-narrowed list, a per-Site row label to a Site-narrowed list, the roster count to the Readers page, each hygiene count to its filter, each per-Site hygiene count to both. A zero renders as the digit and is not a link: the figure stays, because a measured zero is a real fact, but no anchor, because following it lands on an empty list.

The per-Site table here carries library shape only. The five Poll outcome sums live on the Lanes page; on the landing page they were nine columns of zeros burying the four columns that move. No aggregate problem count: the classes overlap -- one orphaned Series with no URL and no cover is three counts and one row -- so a sum over-reports while a distinct count is a number nothing can be done about. The stats block is the whole hygiene surface and every figure on it is individually actionable.

The verdict line is set in the mono data face at 15px, not the display face: it is three counts, not a page title. The stats block is an auto-fit grid with one rule on the block, zeros in the muted colour and unlinked. No timer on this page -- the Lane rest is an hour, so a 30s timer would re-run a cross-Series join roughly 120 times an hour to redraw the same rows.

Acceptance criteria

  • The verdict line renders all three states: healthy, N lanes need attention, and no-Lane-has-reported on a database with no pass rows
  • The waiting count sums due over the latest pass per Site; the stale count uses the single twelve-hour window constant
  • Exactly one twelve-hour constant exists in the web package and both the staleness cutoff and the outcome window read it
  • Every non-zero figure in the stats block links to the list it counts, including the Library split, the per-Site labels and the roster count
  • A zero figure renders as an unlinked digit in the muted colour
  • A hygiene count on the landing page and the heading count on the list it links to agree
  • The per-Site table shows library shape only, with no outcome columns
  • No aggregate problem count is rendered anywhere
  • The page carries no refresh timer
  • go test ./... green

Blocked by

  • #138 — Split the admin surface into four bookmarkable pages with a nav row
  • #139 — Durable Lane state: poll_passes and poll_lanes, plus their store surface
  • #140 — Cross-Series admin read model, with the privacy boundary in the projection
## Parent Spec #134. ## What to build The owner opens the landing page and decides in one glance whether to keep reading or start investigating. One line leads: a verdict, how many Series are waiting, how many have not been checked in twelve hours -- fully database-computed. The waiting figure sums due over the latest pass per Site; the stale figure counts Series with a series URL whose check stamp is older than the window. The verdict says all lanes healthy when nothing needs attention, otherwise **how many lanes need attention rather than just "unhealthy"**, so the owner knows the size of the problem before clicking. With no pass rows at all it says **no Lane has reported yet** rather than drawing confident zeroes -- "nothing has happened" must never render as "everything is fine". That state does not disappear; it narrows from *after every deploy* to *a virgin database*. **One window constant, twelve hours, in the web package, feeding both the staleness cutoff and the outcome window.** Twelve hours because the owner looks once by day and once by night and each look should cover the interval since the last. It is a human threshold, deliberately not a multiple of the Lane's rest, and the page reads the database rather than the poller so it could not follow the Lane's pace anyway. Two differently-named twelve-hour constants on one page is how they drift apart. Then a stats block: library size and the manga/novel split, the roster count, and the eight hygiene counts both library-wide and per Site. **Every figure is an entry point**, not only the hygiene ones -- the total to the unfiltered list, the Library split to a Library-narrowed list, a per-Site row label to a Site-narrowed list, the roster count to the Readers page, each hygiene count to its filter, each per-Site hygiene count to both. **A zero renders as the digit and is not a link**: the figure stays, because a measured zero is a real fact, but no anchor, because following it lands on an empty list. The per-Site table here carries **library shape only**. The five Poll outcome sums live on the Lanes page; on the landing page they were nine columns of zeros burying the four columns that move. **No aggregate problem count**: the classes overlap -- one orphaned Series with no URL and no cover is three counts and one row -- so a sum over-reports while a distinct count is a number nothing can be done about. The stats block is the whole hygiene surface and every figure on it is individually actionable. The verdict line is set in the mono data face at 15px, not the display face: it is three counts, not a page title. The stats block is an auto-fit grid with one rule on the block, zeros in the muted colour and unlinked. No timer on this page -- the Lane rest is an hour, so a 30s timer would re-run a cross-Series join roughly 120 times an hour to redraw the same rows. ## Acceptance criteria - [ ] The verdict line renders all three states: healthy, N lanes need attention, and no-Lane-has-reported on a database with no pass rows - [ ] The waiting count sums due over the latest pass per Site; the stale count uses the single twelve-hour window constant - [ ] Exactly one twelve-hour constant exists in the web package and both the staleness cutoff and the outcome window read it - [ ] Every non-zero figure in the stats block links to the list it counts, including the Library split, the per-Site labels and the roster count - [ ] A zero figure renders as an unlinked digit in the muted colour - [ ] A hygiene count on the landing page and the heading count on the list it links to agree - [ ] The per-Site table shows library shape only, with no outcome columns - [ ] No aggregate problem count is rendered anywhere - [ ] The page carries no refresh timer - [ ] `go test ./...` green ## Blocked by - #138 — Split the admin surface into four bookmarkable pages with a nav row - #139 — Durable Lane state: poll_passes and poll_lanes, plus their store surface - #140 — Cross-Series admin read model, with the privacy boundary in the projection
sulthan added the ready-for-agent label 2026-08-21 16:39:21 +07:00
sulthan self-assigned this 2026-08-22 00:36:49 +07:00
Author
Owner

Merged into spec-134 (branch ticket/143-overview, commits c432a3b, 00fa237).

Overview ships the three-state verdict line, the eight library-wide hygiene counts, the Library block and the per-Site table, with every non-zero figure a link into the list that counts it and every zero an unlinked muted digit. One twelve-hour constant (ownerWindow, from #142) feeds both the staleness cutoff and the outcome window. No aggregate problem count, no refresh timer.

Two judgement calls the implementer declined, both documented in the report and worth a second opinion later rather than now:

  • the verdict ignores never-reported Lanes when other Lanes have reported (the no-Lane-has-reported state is reserved for an empty pass log, as the ticket words it);
  • the per-Site table lists Sites that have Series, not the whole registry.

Also recorded: the per-Site table carries three hygiene columns plus State, not eight. The ticket prose says eight per Site; the design mock and the landed .tbl.sites grid (170px repeat(4, 106px) minmax(180px, 1fr)) both say six columns, and the acceptance criteria only require per-Site figures to link to both filter and Site. Flagging in case the prose was the intent.

Review: spec axis one Minor fixed, standards axis one Minor fixed.

go test ./... green on the merged base.

Merged into `spec-134` (branch `ticket/143-overview`, commits c432a3b, 00fa237). Overview ships the three-state verdict line, the eight library-wide hygiene counts, the Library block and the per-Site table, with every non-zero figure a link into the list that counts it and every zero an unlinked muted digit. One twelve-hour constant (`ownerWindow`, from #142) feeds both the staleness cutoff and the outcome window. No aggregate problem count, no refresh timer. Two judgement calls the implementer declined, both documented in the report and worth a second opinion later rather than now: - the verdict ignores never-reported Lanes when other Lanes have reported (the no-Lane-has-reported state is reserved for an empty pass log, as the ticket words it); - the per-Site table lists Sites that have Series, not the whole registry. Also recorded: the per-Site table carries three hygiene columns plus State, not eight. The ticket prose says eight per Site; the design mock and the landed `.tbl.sites` grid (`170px repeat(4, 106px) minmax(180px, 1fr)`) both say six columns, and the acceptance criteria only require per-Site figures to link to both filter and Site. Flagging in case the prose was the intent. Review: spec axis one Minor fixed, standards axis one Minor fixed. `go test ./...` green on the merged base.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sulthan/mangaBookmark#143