fix(correctness): pagination tiebreakers, dedup race, duration gating (0.87.6)

Three medium correctness fixes:

1. **Pagination ORDER BY missing tiebreakers** — four admin list queries
   sorted by a timestamp or `chapters.number` with no stable secondary
   sort. Add `id` tiebreakers across `repo::admin_view`,
   `repo::admin_audit`, `repo::bookmark`.

2. **`enqueue_pages` NOT EXISTS read-then-insert race** — concurrent
   admin clicks could land duplicate analyze_page jobs. Migration 0031
   adds a partial unique index mirroring 0014; query relies on
   `ON CONFLICT DO NOTHING`.

3. **`record_duration` overwrote a prior done row's duration on a
   non-terminal failed retry of a force-re-analyze.** Gate the call
   on "did this attempt actually write a row?".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-22 21:34:39 +02:00
parent 80f4819fad
commit b9dd75684e
9 changed files with 64 additions and 16 deletions

View File

@@ -239,7 +239,11 @@ pub async fn list_mangas_with_sync_state(
)
SELECT * FROM classified
WHERE ($2::text IS NULL OR sync_state = $2)
ORDER BY updated_at DESC
-- `id` tiebreaker stabilises pagination across mangas that share an
-- `updated_at` (multi-row crawl-tick bulk updates land within the
-- same statement_timestamp() and tie on Postgres' default ts
-- resolution). Without it, page boundaries can skip or repeat rows.
ORDER BY updated_at DESC, id DESC
LIMIT $3 OFFSET $4
"#,
case = MANGA_SYNC_STATE_CASE
@@ -332,7 +336,12 @@ pub async fn list_chapters_with_sync_state(
WHERE cs.chapter_id = c.id AND cs.dropped_at IS NULL) AS latest_seen_at
FROM chapters c
WHERE c.manga_id = $1
ORDER BY c.number ASC
-- `id` tiebreaker: migration 0013 dropped the (manga_id, number)
-- UNIQUE constraint to allow variants ("Ch.14: PH" / "Ch.14:
-- Official") and non-numeric entries (all parse to 0). Without a
-- tiebreaker, pagination over those tied rows can skip or repeat
-- depending on Postgres' chosen sort order.
ORDER BY c.number ASC, c.id ASC
LIMIT $2 OFFSET $3
"#,
)