The Poll fills blank Covers for every Site and both Libraries #61

Closed
opened 2026-08-09 23:12:12 +07:00 by sulthan · 2 comments
Owner

#61 The Poll fills blank Covers for every Site and both Libraries (open)

@sulthan created 2026-08-09 23:12

Parent

Spec: #55. Originating bug: #47. Architecture and rejected alternatives:
docs/adr/0007-backend-hosts-cover-bytes.md. Domain vocabulary: CONTEXT.md.

Do not close #47 or #55 from this ticket.

What to build

Every Series that is blank today gets its Cover without anyone doing
anything — including the Series that have been permanently blank since they
were created, which is the half of #47 that a fix at creation time cannot
reach on its own.

The Poll's cover prefetch is currently guarded to a single Site. That guard
goes away: the prefetch applies to every Site and both Libraries. Nothing
about Covers is conditioned on a Bookmark's kind — the shared card template
already renders both Libraries identically — so this is a guard to remove,
not a branch to add. The lightnovelworld Series that are silently blank
today are repaired by exactly this.

A Poll fills a blank Cover and never replaces one that exists. Two
reasons, both deliberate: a Cover changing under the Reader for no visible
reason is noise, and refetching on every cycle would add a request per
Series per cycle against Sites that already bot-score the deployment's
single IP. This rule is also why no migration or backfill script is needed
anywhere in this effort — the Poll already walks every Series, so the
existing blanks heal themselves.

A failed cover fetch must never fail the chapter poll, never block it, and
never consume anything it depends on. It is retried the next time that
Series is polled; there is no separate retry queue. Failures are logged with
the Series they belong to, so a broken extractor can be told apart from an
unreachable Site.

Extend the existing poller tests rather than starting a parallel harness —
they already run a real store with a fake fetcher and assert prefetch
behaviour, including that a second poll does not refetch.

Acceptance criteria

[x] The cover prefetch runs for every Site, not one
[x] The cover prefetch runs for both Libraries
[x] A Poll fills a blank Cover
[x] A Poll never replaces a Cover that already exists
[x] A failed cover fetch does not fail or block the chapter poll for that
Series
[x] A failed cover fetch is retried on the next poll of that Series, with no
separate retry queue
[x] Failures are logged with the Series they belong to
[x] Existing poller tests are extended rather than duplicated by a new
harness
[x] Manually verified: a Series that was blank before the deploy has a Cover
after a poll cycle
[x] go test ./... is green

Blocked by

• #59 — it fills blanks using that ticket's acquisition path

# #61 The Poll fills blank Covers for every Site and both Libraries (open) @sulthan created 2026-08-09 23:12 ## Parent Spec: #55. Originating bug: #47. Architecture and rejected alternatives: docs/adr/0007-backend-hosts-cover-bytes.md. Domain vocabulary: CONTEXT.md. Do not close #47 or #55 from this ticket. ## What to build Every Series that is blank today gets its Cover without anyone doing anything — including the Series that have been permanently blank since they were created, which is the half of #47 that a fix at creation time cannot reach on its own. The Poll's cover prefetch is currently guarded to a single Site. That guard goes away: the prefetch applies to every Site and both Libraries. Nothing about Covers is conditioned on a Bookmark's kind — the shared card template already renders both Libraries identically — so this is a guard to remove, not a branch to add. The lightnovelworld Series that are silently blank today are repaired by exactly this. A Poll **fills a blank Cover and never replaces one that exists**. Two reasons, both deliberate: a Cover changing under the Reader for no visible reason is noise, and refetching on every cycle would add a request per Series per cycle against Sites that already bot-score the deployment's single IP. This rule is also why no migration or backfill script is needed anywhere in this effort — the Poll already walks every Series, so the existing blanks heal themselves. A failed cover fetch must never fail the chapter poll, never block it, and never consume anything it depends on. It is retried the next time that Series is polled; there is no separate retry queue. Failures are logged with the Series they belong to, so a broken extractor can be told apart from an unreachable Site. Extend the existing poller tests rather than starting a parallel harness — they already run a real store with a fake fetcher and assert prefetch behaviour, including that a second poll does not refetch. ## Acceptance criteria [x] The cover prefetch runs for every Site, not one [x] The cover prefetch runs for both Libraries [x] A Poll fills a blank Cover [x] A Poll never replaces a Cover that already exists [x] A failed cover fetch does not fail or block the chapter poll for that Series [x] A failed cover fetch is retried on the next poll of that Series, with no separate retry queue [x] Failures are logged with the Series they belong to [x] Existing poller tests are extended rather than duplicated by a new harness \[x\] Manually verified: a Series that was blank before the deploy has a Cover after a poll cycle [x] go test ./... is green ## Blocked by • #59 — it fills blanks using that ticket's acquisition path
sulthan added the ready-for-agent label 2026-08-09 23:12:12 +07:00
Author
Owner

Implemented on feat/61-poll-fill-blank-covers. PR: #70

Acceptance criteria ticked except the manual verify (yours). go test ./... green.

Does not close #47 or #55.

Implemented on `feat/61-poll-fill-blank-covers`. PR: https://gitea.violetcrown.my.id/sulthan/mangaBookmark/pulls/70 Acceptance criteria ticked except the manual verify (yours). `go test ./...` green. Does not close #47 or #55.
sulthan removed the ready-for-agent label 2026-08-10 09:26:25 +07:00
Author
Owner

Manually verified (2026-08-10, local mock): seeded three Series with blank Covers into a local stack running this branch (asura/demonic/comix), bypassing the creation-time hook to simulate pre-deploy rows. One poll cycle later the asura Series absolute-regression carried a Cover end-to-end: series.cover_address=414b18b8..., public route GET /covers/414b18b8... serves 200 image/webp 614994B, API wire cover is the absolute content-addressed URL, and the web UI (logged in via a mocked Discord OAuth flow, driven with Playwright) renders the cover image on the card. A second due cycle left cover_address untouched (never-replace holds live). The demonic and comix rows could not be fetched from the local container (ISP DNS filter answers with the internetpositif.id block page), which exercised the graceful-degrade path: failures logged per-Series, chapter poll unaffected, retried next cycle. go test ./... was already green on the branch.

Manually verified (2026-08-10, local mock): seeded three Series with blank Covers into a local stack running this branch (asura/demonic/comix), bypassing the creation-time hook to simulate pre-deploy rows. One poll cycle later the asura Series `absolute-regression` carried a Cover end-to-end: `series.cover_address`=414b18b8..., public route GET /covers/414b18b8... serves 200 image/webp 614994B, API wire `cover` is the absolute content-addressed URL, and the web UI (logged in via a mocked Discord OAuth flow, driven with Playwright) renders the cover image on the card. A second due cycle left cover_address untouched (never-replace holds live). The demonic and comix rows could not be fetched from the local container (ISP DNS filter answers with the internetpositif.id block page), which exercised the graceful-degrade path: failures logged per-Series, chapter poll unaffected, retried next cycle. go test ./... was already green on the branch.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sulthan/mangaBookmark#61