The page hotlinked ~100 AniList CDN covers per load and some failed at random.
The reader now downloads each catalog cover once (sequential, ~1/s, stops on
401/403/429, images up to 2 MB) into data/greatest-covers/ and serves it from
/api/greatest-cover with a year-long browser cache; until a copy exists the
route redirects to the catalog URL. The page also accepts the server's
relative cover URLs, so owned titles show their library cover again.
GREATEST_COVER_WARM=0 turns the downloads off (tests, offline installs).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Cache prune counts directory entries first and only reads files when over
the cap; tests for cross-kind prune, schema-mismatch and corrupt entries.
- Scoring tolerates malformed manga.json and cached records (non-list tags,
object or null relations, non-object items); a tag without a rank no longer
passes the top-tag filter; authors without an integer AniList id are dropped.
- discovery.json publishes only candidates some feed shows; examined/clipped
still describe the pool. Tests that asserted the published count equals the
pool size now check the pool via candidatePool() and the published set
against the feeds.
- The post-harvest rescore failure test now breaks discovery.json right before
the publish (via a scraper stand-in) instead of relying on tags: 5, and a
following successful harvest clears the stale lastError.
- Consent text names everything sent to AniList; paused label mentions admin
harvests; the UI test asserts the XSS seed instead of skipping it.
- Slot-mix test proves the fresh/outside reservations matter.
- Docs: privacy note, fresh fallback reason, per-period cap, dry-run wording,
published-candidate rule; plan/spec hygiene and spec status.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>