The stall watchdog now runs inside the scraper (ScraperService.checkStalls, every 30 s from the work loop): same rule as before, one checkpoint-safe restart, quarantine on the second stall, missing checkpoint is no evidence, and paused time no longer counts. Stalls are recorded as scraper incidents (failure.kind 'stall'). The private /api/recovery endpoint is gone. Dropped with the service: reader/scraper-unreachable incidents (supervisor and Docker handle crashes; the health page shows "Scraper: unreachable"), duplicate job-failure incidents and the unused /metrics endpoint. The stack is now reader + scraper (+ optional peer-gateway). The supervisor test moved to runtime/test (npm run test:runtime stays). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
35 lines
7.4 KiB
Markdown
35 lines
7.4 KiB
Markdown
# Shijō Saikō no Manga — Greatest of All Time
|
||
|
||
`greatest.html` is a second, single-page dashboard. The Japanese title is **史上最高の漫画**, romanized **Shijō Saikō no Manga** (“greatest manga of all time”). It displays the [research reading map](manga-reading-map-2026-10-09.md) as ranked five-year cohorts from before 1970 through 2025–2026. Each period keeps its own separator and tile grid.
|
||
Each tile shows a four-line **Why it matters** preview from the editorial rationale; opening the tile shows the complete text under the same heading. The note is a reason for inclusion, not a plot synopsis or a machine-generated rating.
|
||
|
||
The inclusion rationale should answer **why this title belongs in this particular survey**: a documented award or record, a demonstrable genre/cultural legacy, exceptional artistic craft, or a clearly labelled editorial fit for this library. A synopsis alone is not sufficient. Do not turn the curator's cohort rank into a claim about an external top-10 poll. The 2025–2026 cohort is deliberately labelled as *future-watch* or *provisional*; a recent reader vote is evidence of early enthusiasm, not proof of all-time importance. Specific “first” and record claims need a primary source before publication.
|
||
|
||
Primary-source checks for selected concrete claims in the seed include [Tezuka's Princess Knight archive](https://tezukaosamu.net/en/manga/559.html), [Guinness on Golgo 13's volume record](https://www.guinnessworldrecords.com/world-records/405899-most-volumes-published-for-a-single-manga-series), [Kodansha's manga-prize history](https://www.kodansha.co.jp/awards/comics/histories), [the 2025 Harvey Award winners](https://www.harveyawards.com/en-us/about/news/harvey-awards-reveal-2025-winners.html), and the official [2026 Next Manga Awards print](https://tsugimanga.jp/winners_announcement/comics) and [web](https://tsugimanga.jp/winners_announcement/web) results. Keep award year/category precise when editing the notes. Statements of artistic merit or personal-library fit are editorial judgments, not measurements.
|
||
|
||
## Separation and data ownership
|
||
|
||
- `greatest/catalog.json` is a versioned, read-only editorial seed in the application image. Entries have stable IDs, debut year, cohort, curator rank, rationale, official source lead, and optional AniList cover/chapter/status metadata. It is **not** part of `library/`, scraper queue, or `data/catalog.json` collections.
|
||
- `greatest/index.js` validates the seed and performs only exact title/alias matching against the existing library index. A match adds the local cover, chapter count, status and **In library** badge; it never moves or downloads a title.
|
||
- `data/db.json` holds `greatestRatings[userName][entryId]`. Each account can select `flame`, `good`, `neutral`, or `skip`, or click its current choice to clear it. Existing chapter-version votes are separate. Deleting a user removes their ratings. Include `data/db.json` in backups as before.
|
||
- The rating write route is authenticated `POST /api/greatest/rating` with `{id,rating}` (`null` clears). Authenticated `GET /api/greatest` returns the catalog, per-user choice, valid-user community counts, score, local-library match, and supported series links from that manga's library metadata. Unknown IDs/ratings are rejected. There is no admin-only gate for voting.
|
||
- The details popup shows MangaDex and WeebCentral **series** links from the matched library manga's `manga.json`. Admin-only `GET /api/greatest/sources?id=…` checks live scraper queue state by source series ID and conservative title/alias match. Queue-only title matches are visibly marked as needing edition verification; no search result is silently treated as a confirmed match. If the scraper is unavailable, library links remain visible while queue actions are disabled.
|
||
- Admins can use `GET /api/greatest/mangadex-search?id=…` for a single on-demand, metadata-only title lookup (10 candidates maximum, two-second minimum between uncached lookups, one-hour result cache). The UI shows candidate title and year so an admin can choose the right edition. The WeebCentral search-page link and a pasted series URL cover sources without a safe automatic title lookup. Neither source is bulk-searched when the dashboard opens.
|
||
- **Add to scraper** uses the existing admin `enqueue` command with `inspect:true`, `scope:{mode:"missing"}`, `existingPolicy:"skip-any"`, and the owned library ID when available. It adds an inspection job; an admin must confirm any download later in Admin → Scraper. Existing jobs are marked with their queue status and cannot be added again from a known link. The daemon remains responsible for URL validation, duplicate prevention, and source protections. Ordinary users can view known links but cannot inspect queue state or add jobs.
|
||
|
||
Within each cohort, **Rank by my vote** sorts flame → good → neutral → skull → unrated; **Rank by everyone** uses `3×flames + thumbs-up − 2×skulls`, with curator rank as the tie-breaker. These are preference scores, not independent critical ratings. The quick chips filter by *your* ratings (or in-library status), even when community sorting is active. The popup shows the full rationale, metadata, official source link, community counts, and a library link where available.
|
||
|
||
## Covers and metadata
|
||
|
||
The one-time seed is curated from the research document. All 106 catalog entries now have a cover URL. Most were matched to public AniList manga metadata; the five initial gaps were checked individually. Phoenix (1954) and Nausicaä use matching AniList records; Kitarō uses Drawn & Quarterly's Kitaro edition, Someone Hertz uses Shonen Jump's first-volume cover, and Hitoner uses Shueisha's 2026 first-volume cover. Hitoner's AniList 2024 entry represents an earlier work, so it was **not** used for the 2026 series. The five added URLs returned image content on 2026-10-09, but remote hosts can change them; the UI still shows a title-letter fallback if an image fails.
|
||
|
||
`node tools/enrich-greatest-catalog.js` is an **optional manual** public-AniList metadata refresh, paced at one request every 1.5 seconds. It only accepts matching manga title and **original serialization year**, leaving uncertain results untouched rather than using a sequel or remake cover. The dashboard makes **no metadata calls when loading**; only an admin pressing **Search MangaDex** triggers a bounded lookup. Browser covers are lazy-loaded from their listed source; local library covers take precedence.
|
||
|
||
Public catalog chapter counts are often absent; the UI says “Chapters unknown” rather than inventing one. For owned titles, the local library count wins. Status comes from AniList's releasing/finished flag or local library metadata, and may be unknown. Official source links may be publisher editions, chapter services, or an award/info lead; they do not imply all chapters are available in every country. No unverified hoster coverage is claimed.
|
||
|
||
## Deployment and QA
|
||
|
||
The Docker image now copies `greatest/` as app code; no new Compose service, volume, port, secret, or migration is needed. Rebuild/recreate **reader only** to pick up catalog/UI changes. The scraper does not need restarting. Existing `data/db.json` accepts the new `greatestRatings` object without migration.
|
||
|
||
Run `npm run test:reader` for catalog/API tests and `node tools/test-greatest-ui.js` for disposable headless-browser QA. The UI fixture blocks remote covers and never contacts the scraper. Manual catalog edits should preserve stable IDs once anyone has voted; changing a title's ID strands its votes.
|