Rebuild: completeness as indexed, file totals from any counter, pausable tails, progress by articles
Test and deploy / test (push) Successful in 21s
Test and deploy / deploy (push) Skipped

- releases.complete is computed with every batch (files >= the
  counter's total) instead of only when a release settles after 6 quiet
  hours: the 'complete' filter matched nothing in a fresh catalog.
- A release's file total comes from any counter form (counterTotal:
  '(01/10)', 'File 27 of 132', …), not only [i/M]; the post rule's key
  keeps the [i/M] total, so keys are unchanged. Both implementations.
- groups.tail: a group's live tail can be paused (its history and owner
  priority stay), e.g. to let other groups' history go first.
- Stats: history by articles, and the current pass (history ranges
  before those deferred 2000 priorities behind) as its own figure; the
  header showed 0.1% of ranges counting 145k deferred ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daan MeijerandClaude Opus 5.5 committed 2026-10-09 13:06:03 +02:00
1 parent 7b7175c229
commit d0f3497ec9
8 files changed
+57 -17

No files matched your search

+15 -6
View File
@@ -222,12 +222,18 @@ class SearchService {
const sampled = Number(s[0].sampled)
const releases = sample ? Math.max(estimate, 0) : sampled
const scale = (n: unknown) => (sampled > 0 ? Math.round((Number(n) / sampled) * releases) : 0)
// History by articles; the pass: the history ranges before those deferred behind them (priority
// 2000 apart; e.g. groups added later that go first).
const { rows: ranges } = await db.rawQuery(
`SELECT count(*) FILTER (WHERE status = 'done') AS done, count(*) AS total,
count(*) FILTER (WHERE status = 'done' AND priority >= 0) AS history_done, count(*) FILTER (WHERE priority >= 0) AS history,
max(done_at) AS last_done_at,
max(done_at) FILTER (WHERE priority < 0) AS tail_done_at
FROM ranges`
`WITH h AS (SELECT status, priority, end_id - start_id + 1 AS n FROM ranges WHERE priority >= 0),
pass AS (SELECT (floor(coalesce(min(priority) FILTER (WHERE status <> 'done'), 0) / 2000) + 1) * 2000 AS below FROM h)
SELECT (SELECT count(*) FILTER (WHERE status = 'done') FROM ranges) AS done, (SELECT count(*) FROM ranges) AS total,
coalesce(sum(n) FILTER (WHERE status = 'done'), 0) AS history_done, coalesce(sum(n), 0) AS history,
coalesce(sum(n) FILTER (WHERE status = 'done' AND priority < (SELECT below FROM pass)), 0) AS pass_done,
coalesce(sum(n) FILTER (WHERE priority < (SELECT below FROM pass)), 0) AS pass,
(SELECT max(done_at) FROM ranges) AS last_done_at,
(SELECT max(done_at) FROM ranges WHERE priority < 0) AS tail_done_at
FROM h`
)
const g = ranges[0]
return {
@@ -236,7 +242,10 @@ class SearchService {
readableReleases: scale(s[0].readable),
files: scale(s[0].files),
size: scale(s[0].bytes),
ranges: { done: Number(g.done), total: Number(g.total), historyDone: Number(g.history_done), history: Number(g.history) },
ranges: { done: Number(g.done), total: Number(g.total) },
/** History and the current pass, in articles. */
history: { done: Number(g.history_done), total: Number(g.history) },
pass: { done: Number(g.pass_done), total: Number(g.pass) },
lastIndexedAt: g.last_done_at,
tailIndexedAt: g.tail_done_at,
}