56afb9f237
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.
107 lines
5.7 KiB
Markdown
107 lines
5.7 KiB
Markdown
# ADR-0011: Sightings — a Reader report defers a Poll where being wrong hurts only them
|
|
|
|
Date: 2026-08-16
|
|
Status: accepted
|
|
|
|
## Decision
|
|
|
|
A **Sighting** is what a userscript PUT already carries: the Latest Chapter the
|
|
Reader's own browser read off the Series page. It is now allowed to stand in for
|
|
a Poll, under one restriction and one ceiling:
|
|
|
|
- **Solitary Series only.** A Sighting defers the Poll of a Series exactly one
|
|
Bookmark points at. A Series two Readers share is Polled on schedule no matter
|
|
how recently it was sighted.
|
|
- **One rest of standing.** A Sighting postpones Polls for one Rest
|
|
(`defaultRest`, an hour), not forever: a Series nobody visits again returns to
|
|
the normal schedule by itself.
|
|
- **Six-hour ceiling.** `sightingCeiling = 6 * defaultRest`. However many
|
|
Sightings arrive, a Series unpolled for six hours is Polled.
|
|
|
|
Both live in the due query's HAVING clause (`store.DueForLatestCheck`), beside
|
|
the Rest cutoff — the same place the schedule has always been decided, so no
|
|
timer and no second code path can disagree with it.
|
|
|
|
Attribution and judgement:
|
|
|
|
- `Store.RecordSighting` runs *before* the Upsert that stores the reported
|
|
value, because the raise test needs the row as it stands. A report that raises
|
|
the stored Latest Chapter names its Reader in `series.latest_raised_by`.
|
|
- The Poll is the oracle. `Poller.checkOne` already compares what the Site
|
|
publishes against what is stored, so judgement costs no extra request: a lower
|
|
number contradicts the Sighting (`sighting_disagreements + 1`, both numbers and
|
|
the Reader logged), the same number confirms it (`sighting_agreements + 1`), a
|
|
**higher** number is the Site publishing and means nothing either way.
|
|
- At `SightingDisagreementLimit` (3) that Reader's Sightings stop deferring
|
|
anything. They still write the Latest Chapter — the penalty removes a
|
|
privilege, it does not silence anyone.
|
|
- `SightingAgreementsToClear` (20) consecutive confirmations forgive the
|
|
disagreements. A disagreement resets the run to zero.
|
|
- The owner clears marks from the administration page (issue #102, shipped
|
|
first precisely so a false mark has a remedy the day the mechanism lands).
|
|
|
|
## Why
|
|
|
|
Most of the backend's work was redundant. The userscript reads the Latest
|
|
Chapter on every Series page visit and PUTs it; minutes later the Poll Lane
|
|
fetches the same page for the same number. Deferring on a report converts a
|
|
visit into a Poll saved, which is Lane capacity handed back to Series nobody is
|
|
reading.
|
|
|
|
The restriction is the whole safety argument, and it is about **blast radius**,
|
|
not about trust arithmetic:
|
|
|
|
- On a solitary Series, a wrong report can only mislead the Reader who made it.
|
|
There is nobody else's ember to falsify.
|
|
- On a shared Series it could mislead someone else, so a report never postpones
|
|
anything there.
|
|
|
|
The ceiling bounds the damage in time: a false value dies within six hours
|
|
whatever happens, because the Poll that finds it is guaranteed. That is also
|
|
what makes lying pointless — the six-hour audit is certain, not sampled, so a
|
|
determined attacker buys at most three ceilings' worth of a wrong number on
|
|
their own Series and then loses deferral entirely.
|
|
|
|
The cost of recovery is deliberate. An agreement is only recorded when a later
|
|
Poll confirms a Sighting, so twenty agreements are twenty Polls of Series that
|
|
Reader bookmarks — hours to days of real time, not twenty page views. Waiting is
|
|
therefore not a strategy, and credit cannot be banked in advance.
|
|
|
|
## Tradeoffs and rejections
|
|
|
|
- **Trusting a Sighting on a shared Series** rejected: it is the only case where
|
|
one Reader's mistake reaches another Reader's list, and no amount of
|
|
reputation makes that recoverable within the six-hour window.
|
|
- **Cross-Reader agreement, voting, weighting, consensus scoring** rejected: a
|
|
single-source report cannot have its confidence evaluated by comparison, and
|
|
with the typical two Readers a disagreement identifies nothing. The Poll is
|
|
the only oracle in the system, so it is the only judge.
|
|
- **A randomised audit** (Poll a fraction of deferred Series) rejected in favour
|
|
of the fixed ceiling: a sampled audit makes the attacker's expected cost a
|
|
probability, while a ceiling makes it a certainty, and a certainty is what
|
|
makes the solitary-Series rule defensible in one sentence.
|
|
- **Blocking a marked Reader's writes** rejected: the Latest Chapter they report
|
|
is still the best available value, and their Sightings must keep being judged
|
|
or they could never earn the privilege back.
|
|
- **Per-Series flagging** rejected in favour of per-Reader marks: a Series is
|
|
not the thing that can be wrong. Naming the Reader and logging both numbers is
|
|
also what distinguishes a broken Site adapter (every Reader of that Site
|
|
contradicted at once) from one bad actor.
|
|
- **Timers or a background reputation job** rejected: deferral is decided from
|
|
live facts every round — Bookmark count, sighting timestamp, the Reader's
|
|
marks — so a Series that gains a second Bookmark stops deferring at once, with
|
|
nothing to invalidate.
|
|
|
|
## Constraints preserved
|
|
|
|
- A Sighting is not Progress: it may move the Latest Chapter and nothing else.
|
|
`updated_at` never moves, so a report cannot reorder the list (ADR-0004).
|
|
- The Latest Chapter is a Series-level fact (ADR-0003): a Sighting writes the
|
|
shared row, so every Reader of a shared Series sees it immediately — deferral
|
|
is the only thing the solitary rule withholds.
|
|
- Ember means new chapter only (`docs/design-system.md`): a marked Reader
|
|
renders no differently in their own list, and nothing about the trust model
|
|
reaches the Series list's colour.
|
|
- The Poll remains authoritative. Where a Sighting and a Poll disagree, the
|
|
Poll's value is what gets stored.
|