poll_failures: the row is the failure state #165

Closed
opened 2026-08-22 17:39:57 +07:00 by sulthan · 1 comment
Owner

Parent

Part of #137.

What to build

A Series that used to work and has stopped becomes a durable fact instead of a log line nobody reads. A new per-Series table holds one row per failing Series; the row's existence is the failure state. A correct read deletes it. No success sentinel, no counter, no history — and nothing is added to the Series row.

Two outcomes deliberately write nothing at all, and the silence is load-bearing in both directions: a Site refusing us and our own browser being unreachable are not evidence about any particular Series. Writing a row would mark a whole library as failing when one Site had a bad day; deleting one would claim recovery when nothing was read, resetting the age that makes a three-month failure findable.

Acceptance criteria

  • A migration creates the table keyed by the composite the rest of the system uses, carrying the outcome word and a failing-since stamp, with a cascade so deleting a Series takes its failure row and orphan removal stays a single statement.
  • A failing Poll upserts: the word is updated on a change, and the failing-since is never touched — the age is the age of the run of failures, not of the current word.
  • A repeated identical failure writes nothing, so a broken Series costs the same as a healthy one every hour.
  • A successful read deletes the row.
  • refused and unreachable issue no statement at all — asserted against a pre-seeded row so both directions are covered.
  • A hand correction clears nothing; a Forced Poll request clears nothing; a forced Poll that reads the page clears the row with no special case in the code.
  • The due query does not join the table: a failing Series is polled at the same pace as any other.
  • An ADR records the design — a table whose row is the state, plus the two outcomes that deliberately write nothing.
  • Rollout note in the ticket's PR: the table starts empty, so nothing is findable for the first twelve hours after deploy and a pre-existing breakage reads as new. Accepted; the alternative is inventing history.

Blocked by

  • #164 — A sixth outcome word: not_found splits out of errors
## Parent Part of #137. ## What to build A Series that used to work and has stopped becomes a durable fact instead of a log line nobody reads. A new per-Series table holds one row per failing Series; the row's existence *is* the failure state. A correct read deletes it. No success sentinel, no counter, no history — and nothing is added to the Series row. Two outcomes deliberately write nothing at all, and the silence is load-bearing in both directions: a Site refusing us and our own browser being unreachable are not evidence about any particular Series. Writing a row would mark a whole library as failing when one Site had a bad day; deleting one would claim recovery when nothing was read, resetting the age that makes a three-month failure findable. ## Acceptance criteria - [ ] A migration creates the table keyed by the composite the rest of the system uses, carrying the outcome word and a failing-since stamp, with a cascade so deleting a Series takes its failure row and orphan removal stays a single statement. - [ ] A failing Poll upserts: the word is updated on a change, and the failing-since is **never** touched — the age is the age of the run of failures, not of the current word. - [ ] A repeated identical failure writes nothing, so a broken Series costs the same as a healthy one every hour. - [ ] A successful read deletes the row. - [ ] `refused` and `unreachable` issue **no statement at all** — asserted against a pre-seeded row so both directions are covered. - [ ] A hand correction clears nothing; a Forced Poll *request* clears nothing; a forced Poll that reads the page clears the row with no special case in the code. - [ ] The due query does not join the table: a failing Series is polled at the same pace as any other. - [ ] An ADR records the design — a table whose row is the state, plus the two outcomes that deliberately write nothing. - [ ] Rollout note in the ticket's PR: the table starts empty, so nothing is findable for the first twelve hours after deploy and a pre-existing breakage reads as new. Accepted; the alternative is inventing history. ## Blocked by - #164 — A sixth outcome word: not_found splits out of errors
sulthan added the ready-for-agent label 2026-08-22 17:39:57 +07:00
sulthan self-assigned this 2026-08-22 18:30:47 +07:00
Author
Owner

Landed on spec-137 (merge 4d67736, then 5a32943 after #169). poll_failures table: upsert on failure (word updates, failing_since sticky), delete on success, refused/unreachable write nothing (both directions proven), due query untouched, ADR-0016 recorded. Two-axis review: spec pass, standards pass (1 style nit fixed, 1 duplication call declined w/ reason). Full backend suite green post-merge. Commits: 417f809, caabdff.

Landed on spec-137 (merge 4d67736, then 5a32943 after #169). poll_failures table: upsert on failure (word updates, failing_since sticky), delete on success, refused/unreachable write nothing (both directions proven), due query untouched, ADR-0016 recorded. Two-axis review: spec pass, standards pass (1 style nit fixed, 1 duplication call declined w/ reason). Full backend suite green post-merge. Commits: 417f809, caabdff.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sulthan/mangaBookmark#165