feat: a Reader's Sighting defers a Poll of a solitary Series (#103)
A userscript PUT already carries the Latest Chapter the Reader's own browser read; it now stands in for a Poll where being wrong can hurt nobody else. Deferral lives in the due query beside the rest cutoff: one Bookmark, sighted within one rest, under the six-rest ceiling. checkOne judges the Reader whose report raised the value off the comparison it already makes - three contradictions stop them deferring, twenty confirmations forgive. ADR-0011 records the trust model and the rejected alternatives.
This commit is contained in:
+19
-1
@@ -27,7 +27,8 @@ Guidance for OpenCode (and Claude Code) working under `backend/`. See root `AGEN
|
||||
`series` keyed `(site, series_id)`
|
||||
(`asura`|`demonic`|`comix`|`kagane`|`novelfull`|`lightnovelworld`) owns the
|
||||
shared facts — title, cover, canonical URL, `kind` (`manga`|`novel`),
|
||||
Latest Chapter, `latest_checked_at` — and `bookmarks` holds only what
|
||||
Latest Chapter, `latest_checked_at`, and the Sighting pair
|
||||
`latest_sighted_at`/`latest_raised_by` (issue #103) — and `bookmarks` holds only what
|
||||
differs between readers: progress, favourite, lifecycle bucket,
|
||||
`updated_at`. A bookmark is keyed `(reader_id, site, series_id)` — no
|
||||
surrogate id; the wire `key` is derived as `site:series_id` on read — and
|
||||
@@ -91,6 +92,23 @@ Guidance for OpenCode (and Claude Code) working under `backend/`. See root `AGEN
|
||||
every tick; found chapter written straight to the series row via
|
||||
`Store.SetLatestChapter`, so a bookmark's `updated_at` — and the list
|
||||
order — is never touched.
|
||||
**Sightings** (issue #103, ADR-0011) let a Reader's own page read defer a
|
||||
Poll: `Store.RecordSighting` — called by the PUT handler *before* the Upsert,
|
||||
because the raise test needs the row as it stands — stamps
|
||||
`series.latest_sighted_at` and, when the report raises the stored number,
|
||||
names its Reader in `series.latest_raised_by`. The due query's HAVING clause
|
||||
is where deferral lives: a Series is skipped only while it has exactly one
|
||||
Bookmark, was sighted within one Rest, and is under the `sightingCeiling`
|
||||
(six rests) since its last Poll. So a shared Series is never deferred, and no
|
||||
Series goes six hours unpolled whatever arrives. `checkOne` judges the named
|
||||
Reader off the comparison it already makes: a lower number is a
|
||||
contradiction (logged with the Reader and both numbers), the same number an
|
||||
agreement, a higher number the Site publishing and neither. Three
|
||||
contradictions (`store.SightingDisagreementLimit`) stop that Reader deferring
|
||||
— their reports still write the Latest Chapter — and twenty consecutive
|
||||
agreements (`store.SightingAgreementsToClear`) forgive them, as does the
|
||||
owner's clear-marks control. Deferral is recomputed from live facts every
|
||||
round, so nothing needs invalidating when a Series gains a second Bookmark.
|
||||
Refusals and browser loss are Lane-local: two `errChallengeHeld` in one pass
|
||||
stop that Site for `refuseBackoff` (15m) while other Lanes continue; an
|
||||
`errBrowserInterrupted` (remote Chrome restart) sets a shared Poller flag
|
||||
|
||||
Reference in New Issue
Block a user