- requeue_dead_jobs: when a chapter has multiple dead jobs, revive only the
newest (DISTINCT ON the chapter key) so a single UPDATE can't flip two
dead rows for one chapter to pending and violate the partial unique dedup
index (was a 500 that requeued nothing). Non-chapter jobs fall back to row
id. Regression test added. (critical)
- coordinated_restart: a caller that coalesces into an in-progress restart
now reports that restart's real outcome instead of a blind success, so the
session-update "valid" / restart "ok" signal can't be falsely positive.
- SessionController::update: reject control chars / ';' / ',' in PHPSESSID
before it reaches the cookie string + CDP cookie. Test added.
- Add non-admin 403 test on a mutating crawler endpoint; fix stale
stream-to-storage doc comment.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GET /admin/crawler live status (phase, workers,
last pass, session, browser, queue)
POST /admin/crawler/run trigger an out-of-cycle metadata pass
POST /admin/crawler/browser/restart coordinated Chromium restart
POST /admin/crawler/session refresh PHPSESSID + re-probe
POST /admin/crawler/session/clear-expired clear the sticky expired flag
GET /admin/crawler/dead-jobs paginated dead-letter list
POST /admin/crawler/dead-jobs/requeue requeue all / per-manga / single
All cookie-only via RequireAdmin; control endpoints 503 when the daemon is
disabled; mutations are audit-logged. Reads compose the live status with
DB-derived queue counts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>