Files
usenet-indexer/database/migrations/1770000003900_final_completeness.ts
T
Daan MeijerandClaude Opus 5.5 ce43099188
Test and deploy / test (push) Successful in 58s
Test and deploy / edge (push) Successful in 2m4s
Test and deploy / deploy (push) Successful in 8m5s
Final completeness by time window: ranges keep their posting span, release_final() over blocks of done ranges
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:19:03 +02:00

46 lines
2.4 KiB
TypeScript

import { BaseSchema } from '@adonisjs/lucid/schema'
/**
* Final completeness by time window (LOG.md 2026-10-16 (67)). A release settles once quiet, but history is read
* newest first and in islands: one next to an unread range was "incomplete" twice as often (52.5% against 25.7%),
* its missing files only not read yet. An upload is posted within hours, so a release is final (its complete verdict
* definite) once done ranges cover its posting times and FINAL_MARGIN either side.
* - ranges.posted_low/high: the posting time span the workers report per batch (postedSpan: without the earliest and
* latest 1%), the min and max over the range's batches.
* - range_blocks: runs of consecutive done ranges per group with their span (RangeBlocks rebuilds it); at_group_start
* when the run starts at the group's first range (nothing older to wait for).
* - release_final(): whether one block holds the release's articles and reaches FINAL_MARGIN past its posting times.
* Computed when asked, so no release row is written (50M updates would double the table on the NVMe).
*/
export default class extends BaseSchema {
async up() {
this.schema.raw(`ALTER TABLE ranges ADD COLUMN IF NOT EXISTS posted_low timestamptz, ADD COLUMN IF NOT EXISTS posted_high timestamptz`)
this.schema.raw(`
CREATE TABLE range_blocks (
group_id integer NOT NULL,
start_id bigint NOT NULL,
end_id bigint NOT NULL,
posted_low timestamptz,
posted_high timestamptz,
at_group_start boolean NOT NULL,
PRIMARY KEY (group_id, start_id)
)`)
// FINAL_MARGIN: 6 hours.
this.schema.raw(`
CREATE FUNCTION release_final(g integer, first_article bigint, last_article bigint, posted timestamptz, last_posted timestamptz)
RETURNS boolean LANGUAGE sql STABLE AS $$
SELECT EXISTS (
SELECT 1 FROM range_blocks b
WHERE b.group_id = g AND b.start_id <= first_article AND b.end_id >= last_article
AND (b.at_group_start OR b.posted_low <= posted - interval '6 hours')
AND b.posted_high >= coalesce(last_posted, posted) + interval '6 hours')
$$`)
}
async down() {
this.schema.raw(`DROP FUNCTION IF EXISTS release_final(integer, bigint, bigint, timestamptz, timestamptz)`)
this.schema.raw(`DROP TABLE IF EXISTS range_blocks`)
this.schema.raw(`ALTER TABLE ranges DROP COLUMN IF EXISTS posted_low, DROP COLUMN IF EXISTS posted_high`)
}
}