Files
usenet-indexer/lib/seed/plan.ts
T
Daan MeijerandClaude Opus 5.5 693e6c3244
Test and deploy / test (push) Successful in 1m27s
Test and deploy / deploy (push) Failing after 33m7s
Seed plans fill every uncovered gap, with priorities; cheaper ingest and file storing
- seed:plan plans every part of a group's history no range covers (it
  started below the lowest known range and left a.b.ath's 13 most recent
  months out); seed_ranges.priority orders leases (seed:plan --priority).
- binaries.part_count, kept by the parts insert in the same statement:
  claimCompleted compares it instead of counting parts every batch.
- file_keys: 64-bit hashes of all file keys; FileStore.insert asks it
  before probing every files partition.
- worker:file stores 100 completed binaries per job with set-based queries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:18:01 +02:00

28 lines
1.1 KiB
TypeScript

/**
* Seed planning arithmetic (CONCEPT.md D38), independent of the database.
*/
/** The parts of `from`..`to` (inclusive) that no range in `covered` (inclusive pairs) overlaps, oldest first. */
export function uncovered(from: number, to: number, covered: [number, number][]): [number, number][] {
const gaps: [number, number][] = []
let next = from
for (const [start, end] of [...covered].sort((a, b) => a[0] - b[0])) {
if (end < next) continue
if (start > to) break
if (start > next) gaps.push([next, Math.min(start - 1, to)])
next = Math.max(next, end + 1)
if (next > to) return gaps
}
if (next <= to) gaps.push([next, to])
return gaps
}
/** `gaps` cut into ranges of at most `size` articles, newest first (from the top of the newest gap down). */
export function cut(gaps: [number, number][], size: number): [number, number][] {
const ranges: [number, number][] = []
for (const [from, to] of [...gaps].sort((a, b) => b[1] - a[1])) {
for (let end = to; end >= from; end -= size) ranges.push([Math.max(from, end - size + 1), end])
}
return ranges
}