Version cover URLs, and document firmware-update failure modes #27
Loading…
Reference in a new issue
No description provided.
Delete branch "cover-cache-busting"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to #26, prompted by a cover that still looked unchanged after
that shipped.
Versioned cover URLs
no-cacheprevents future staleness but cannot cure a cover alreadycached under the old
max-age=86400: a copy that is fresh by contractis served without a request, so the client never learns the policy
changed. The entry stays poisoned for the rest of its 24 hours — and the
cover being tested was exactly that one, which made a working fix look
broken.
The book and edit pages now emit
/cover/{uuid}?v=<cover mtime>, so areplaced cover is a different URL that no cached entry can shadow. A
versioned URL is served
immutablefor a year; an unversioned one — abookmark, or a cover that cannot be stat'd — keeps revalidating. A book
with no cover emits no
?v=at all.This is the option-2 fix from the original diagnosis, and it is the one
that does not depend on client revalidation behaviour. Worth noting the
cover markup is a CSS
background: url(...), which browsers arenoticeably more willing to serve from cache than an
<img>.Firmware-update failure modes
docs/kobo-api.mddocumented all 20 endpoints and five failure modes,but not the one hazard certain to arrive eventually. Two sections added:
key,
api_endpoint. An update or factory reset can restore it tostoreapi.kobo.com, after which the device syncs against the realKobo store and nothing fails — no error, no log line, the shelf just
stops changing.
devices.last_seen_atis the canary: frozen across async means the device is no longer talking to this server. Re-applying
the device URL is the whole fix; the token is unchanged.
Colour. The catch-all is what keeps drift from becoming a hard "sync
failed", so expect a degraded feature and silence rather than errors.
Also recorded that pointing
api_endpointat a self-hosted server doesnot stop the device updating its own firmware — observed in
practice, including an update being required before sync would proceed.
Deliberately not included
internal/kobo/cover.go:21still sendspublic, max-age=86400on anequally stable URL, so a replaced cover can lag on the device by up to a
day. The device URL carries no version, and changing device-facing cache
behaviour deserves its own decision rather than riding along here.
Testing
go vetclean, full suite green. Added: the book page references theexact versioned URL for an uploaded cover, a coverless book emits no
?v=, andCoverGet's policy isimmutablewith a version andno-cachewithout.🤖 Generated with Claude Code
no-cache fixed future staleness but could not cure a cover already cached under the old max-age=86400: a fresh-by-contract copy is used without a request, so the client never learns the policy changed. The cover being tested at the time was exactly the poisoned one, which made a working fix look broken. Emit /cover/{uuid}?v=<cover mtime> from the book and edit pages, so a replaced cover is a new URL no cached entry can shadow. A versioned URL is then served immutable for a year; an unversioned one — a bookmark, or a cover that cannot be stat'd — keeps revalidating. The Kobo cover handler keeps its own public, max-age=86400 on an equally stable URL, so a replaced cover can lag on the device by a day. Left alone: the device URL carries no version and that is device-facing behaviour worth changing deliberately. Also document two firmware failure modes in docs/kobo-api.md, which covered every endpoint and five failure modes but not the one hazard guaranteed to arrive eventually: an update or factory reset restoring api_endpoint to storeapi.kobo.com, which fails completely silently because the device then syncs against the real store, with devices.last_seen_at as the canary; and protocol drift, where the catch-all turns a would-be "sync failed" into a degraded feature. Pointing api_endpoint at a self-hosted server does not stop the device updating its own firmware. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>