Commit Graph
140 Commits
Author SHA1 Message Date
Daan MeijerandClaude Fable 5.1 137e931e9e Posting-time windows into the corpus: ranges:dates, ranges:capture
Test and deploy / test (push) Successful in 55s
Test and deploy / edge (push) Successful in 2m2s
Test and deploy / deploy (push) Successful in 2m12s
ranges:dates samples each active group's posting dates from the news
server (group_dates) and estimates every range's date (ranges.est_date).
ranges:capture --from --to marks a window's ranges of every group for the
corpus. The corpus fill takes capture ranges in priority order, done ones
too, and remembers complete ones (ranges.stored_at).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-25 09:47:28 +01:00
Daan MeijerandClaude Opus 5.5 03ca96b255 Fix findCounter infinite loop; corpus filter skips chunks past 256 MB
Test and deploy / test (push) Successful in 47s
Test and deploy / edge (push) Successful in 1m45s
Test and deploy / deploy (push) Successful in 2m5s
lastIndexOf('(', -1) searches from 0 again, so a subject starting with a "("
that isn't a counter, without a quote, looped forever. The corpus filter hit
it at 11:23 on Oct 24: the coordinator (and corpus:filter) spun at 100% CPU
for 10 hours and no range finished. The Rust find_counter stops at 0 already.

A chunk inflating past V8's longest string can't be filtered as text; such a
chunk is now stored unfiltered instead of throwing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:08:22 +02:00
Daan MeijerandClaude Opus 5.5 a66b0980f4 Corpus: store chunks without the lines the worker only counts
Test and deploy / test (push) Successful in 59s
Test and deploy / edge (push) Successful in 2m3s
Test and deploy / deploy (push) Successful in 1m20s
History fetched ahead into the corpus (bulk HDD) is ~60 TB raw for the
1,180B missing articles, and the indexer keeps only ~38% of headers.
With CORPUS_FILTER (default on), Corpus.write leaves out the lines the
edge worker drops on their own, decided per line as RangeIndexer.line
does: a crosspost another indexed group owns, and a subject that names no
file part (~48% of the indexed ranges' headers). Release-level rules
(garbage, per-article, executable, poster) judge files across chunks and
aren't applied. The chunk is compressed again as zlib (the worker takes
it as before); beside it a .drops (gzip JSON) keeps the rule version,
the owners' priorities and per rule the article numbers (as differences,
crossposts by owner), and range.json says filtered. A test shows the
worker makes the same releases, candidates and fragments of a filtered
chunk. corpus:filter filters chunks stored raw (planned capture ranges;
--all for every range).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:34:09 +02:00
Daan MeijerandClaude Opus 5.5 c1946792b2 Corpus prefetch: at most perGroup/perRange capture ranges per group
Test and deploy / test (push) Successful in 1m2s
Test and deploy / edge (push) Successful in 2m10s
Test and deploy / deploy (push) Successful in 1m19s
The prefetcher fetched capture ranges into the corpus 16 at a time in id
order, and ids run group by group: the 16 were one or two groups', the
per-group connection limit (4) let 4-8 loops work and left the rest
idle, ~30k articles/s for the first batch of 19,955 capture ranges. Now
at most perGroup / perRange (2) of a group are taken, so the 16 come
from 8+ groups and every loop gets work (and the pool asks for more).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 15:25:18 +02:00
Daan MeijerandClaude Opus 5.5 fb6b00f230 Name pass: only holders near the newest; merges drop duplicate candidates
Test and deploy / test (push) Successful in 50s
Test and deploy / edge (push) Successful in 1m53s
Test and deploy / deploy (push) Successful in 57s
The name pass put every holder of a set into its merge: a par2 posted
again years later ("Auto Bild Klassik Februar 02-2014", held by a 2014
and a 2026 release) would have joined the repost to the old upload. Now
the newest holder anchors it and only holders in its group within 12
hours take part. Every round, three sets failed on the probe candidates'
unique key: a member held a candidate of an article the target had.
merge() now drops such a candidate (the target's, or a lower member's,
stays), as it already does for par2 sets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 14:59:09 +02:00
Daan MeijerandClaude Opus 5.5 e00e4f3988 Join an upload's releases by its par2 set's file names
Test and deploy / test (push) Successful in 1m5s
Test and deploy / edge (push) Successful in 2m0s
Test and deploy / deploy (push) Successful in 1m19s
The files of one upload often became several releases whose names
differ slightly: scene tracks apart from their album's nfo/sfv/par2,
"Vermaechtnis" beside a garbled "Vermächtnis", an index named
Die.Bergretter.S18E05... beside its video wishtv-diebergretter-s18e05.
The par2 merge joined releases only by first-16-KiB hashes, which
readable files never get. A name pass now looks, for every set the
merger finds, at the set poster's releases in its group posted within
12 hours: those whose files the set all names (without case or
punctuation, Latin-1-read UTF-8 read back; sidecars, par2 and images
aside) join the set's release, within the hash pass's file bound.
Merges are kept in release_merges as via 'name'. releases:merge-names
runs it over the sets found before; on 300 recent sets 22 merges of 147
releases, all one upload each.

Also: volumes split after .wmv, .mov, .mpg and other video extensions
share a stem ("Morning Lovers.wmv.001" to ".058" were 58 releases), in
the Rust edge and the TypeScript identity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 14:02:51 +02:00
Daan MeijerandClaude Opus 5.5 61bdd43b34 Categories from the inner name, spots and groups; fix the name rules
Migration 1200 passed regexes with `?` through knex, which made them
bindings: the live function held blu-$1ray, web-$2dl and h\.$326[45], so
BluRay, WEB-DL and H.264 names without a resolution were Misc. 93% of
recent releases were Misc, as the category came from the name alone.

category becomes a plain column (DROP EXPRESSION, no rewrite) set by a
trigger: the name's category (fixed, no `?` anywhere; adds XXX,
audiobooks, console and PC games, and TV codes like S01e07[ and
S04E01E02), else the prober's inner name's, else one given before (a
spot's), else the groups'. The spot inspector sets a spot's category
(spot_category) on Misc releases it links and on its own releases. The
Newznab and web category lists gain Console, PC Games, Audiobook, Anime,
XXX and Comics. releases:recategorize recomputes existing rows in id
batches, writing only changed rows and waiting under a free-space floor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:07:12 +02:00
Daan MeijerandClaude Opus 5.5 ebe9f8bb36 Decide completeness by par2 set for releases without a counter
59% of settled releases had complete = NULL: without an [i/N] counter
the settler left it unknown, and the "phase 2 reads par2 sets for those"
step was never built. A release is now complete when every file its par2
sets describe is there by name or by its first-16-KiB hash, or, for an
upload renamed after its par2 was made, when it has as many non-par2
files and bytes. Decided when a par2 index is probed, after a par2 merge,
and before the pruner drops a set's file list; the batch store, settler
and merger keep a decided value instead of resetting it to NULL.
releases:par2-complete decides the releases probed before this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:00:19 +02:00
Daan MeijerandClaude Opus 5.5 f75097d7ac Put known passwords in the NZB and show them
release_passwords (from spots: their NZB meta, title or text) was only
read by the judge. The NZB now carries the most trusted one as
<meta type="password">, which SABnzbd and NZBGet use to unpack; a spot's
own NZB gets it added when its meta has none. The release details list
all known passwords with their source, the list marks "Password known",
and the web interface shows them instead of "not in the index".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 11:56:43 +02:00
Daan MeijerandClaude Opus 5.5 d446bb57df Probe 7z listings and ZIP starts
7z keeps its file list at the end of the archive, so the 7z-tail
candidates (the last segment of the highest volume) were queued but
never probed, and the .7z.001 start only gave the type. The prober now
claims 7z-tail candidates after the archives; lib/sevenzip finds the end
header in the article, decodes the LZMA-packed header (a TypeScript port
of the LZMA SDK's reference decoder) and lists the files with their
sizes. An AES-encrypted header means passworded without names. Names
feed the inner name and the judge's fake rule.

An unsplit .7z of several segments now also gets a tail candidate, and
.zip files an archive candidate: their first segment's local headers
give the first entries and whether they are encrypted. Both in the Rust
edge and the TypeScript indexer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 11:55:07 +02:00
Daan MeijerandClaude Opus 5.5 3b61215f6b Keep only the 7z tails of a release's highest volume
Test and deploy / test (push) Successful in 48s
Test and deploy / edge (push) Successful in 1m47s
Test and deploy / deploy (push) Successful in 1m49s
The live tail reads an upload in pieces while it is posted, and each
piece queued a 7z-tail candidate for the last volume it had seen so far
(release 306905984: seven, for .002-.008). Only the last volume's end
holds the 7z listing. When candidates are stored, and when releases are
merged, waiting tails below the release's highest volume are deleted.
All tails of the highest volume stay: a piece that saw only part of it
queued a segment that is not its last. RAR is unaffected: it lists its
files in the first volume's header and gets no tail candidate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 11:16:25 +02:00
Daan MeijerandClaude Opus 5.5 b60d716db0 Close NNTP connections left idle for NNTP_IDLE_CLOSE_SECONDS
Test and deploy / test (push) Successful in 50s
Test and deploy / edge (push) Successful in 1m45s
Test and deploy / deploy (push) Successful in 2m20s
Eweka drops quiet connections, so the next command on one failed
("Spot inspection failed: NNTP connection closed"), and idle connections
held account slots that downloads could use. The coordinator pool now
closes free connections (and the plain one) on its sync once idle for
60 s; dry prober lanes, the spotter between rounds and the spot inspector
with nothing to inspect close theirs too, reconnecting when work comes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 14:31:49 +02:00
Daan MeijerandClaude Opus 5.5 705f9c3897 Release keys numbered after the highest number, not the count
Test and deploy / test (push) Successful in 57s
Test and deploy / edge (push) Successful in 1m58s
Test and deploy / deploy (push) Successful in 2m10s
Merges delete releases, so the count of a key's releases fell behind its
numbers (83 releases up to key:129): the 20 numbers tried were all taken
and the range's batch failed for good. Spot releases (spot:key) are not
numbered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:08:13 +02:00
Daan MeijerandClaude Opus 5.5 8ad5ea162c par2 file lists dropped once their holders are final; late candidates claimable
Test and deploy / test (push) Successful in 47s
Test and deploy / edge (push) Successful in 1m46s
Test and deploy / deploy (push) Successful in 58s
Most par2 sets describe readable uploads whose files are never hashed, so they
were never complete and kept forever (19 GB). Candidates added to a release
after it settled were never marked ready (93,642 since 2026-10-13); the batch
store and merge mark them now, migration 5100 repairs the waiting ones
(LOG.md 2026-10-20 (87)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 13:56:57 +02:00
Daan MeijerandClaude Opus 5.5 4f41303482 Merger: what's new an hour at a time, only the sets two releases share; common files match nothing
Test and deploy / test (push) Successful in 1m3s
Test and deploy / edge (push) Successful in 2m14s
Test and deploy / deploy (push) Successful in 3m9s
A round behind by two days of the probe backlog read 3.5M sets and never ended;
a par2 file shared by up to 190k files loaded every release it matched and the
merger ran out of heap every few minutes (LOG.md 2026-10-20 (85)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:54:50 +02:00
Daan MeijerandClaude Opus 5.5 9725bdbd7b Judge: count a chunk's file hashes once, from a covering index
Test and deploy / test (push) Successful in 1m1s
Test and deploy / edge (push) Successful in 2m6s
Test and deploy / deploy (push) Successful in 8m54s
The incremental judge counted each changed release's files twice, each
index entry a heap fetch: 24-32 s a chunk. file_hashes by (hash16k,
size, release_id) replaces (hash16k); the other releases of a file are
judged only when the chunk brings it to 20.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:32:52 +02:00
Daan MeijerandClaude Opus 5.5 76e52f69ce Judge the releases whose facts changed every 2 minutes, all daily
Test and deploy / test (push) Successful in 51s
Test and deploy / edge (push) Successful in 2m3s
Test and deploy / deploy (push) Successful in 1m5s
A full round took 35-38 min of each hour and grew with every inspection
the prober added. Triggers note changed releases in judge_dirty; the
judge judges those (and releases a file hash of theirs tipped to
repeated) by every rule, and every release in a daily full round for
what time changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:10:49 +02:00
Daan MeijerandClaude Opus 5.5 a983cad509 Judge: write only changed verdicts; scraped and locked by index
Test and deploy / test (push) Successful in 1m2s
Test and deploy / edge (push) Successful in 2m7s
Test and deploy / deploy (push) Successful in 16m15s
A round took 22-29 min an hour: every match went through the insert's
conflict check (60-150 s a rule), scraped and locked each scanned all of
releases. The spot inspector's releases now add their poster to posters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:48:54 +02:00
Daan MeijerandClaude Opus 5.5 d405b658c3 Prober: a flush with a NUL in a name, or one article twice, no longer fails
Test and deploy / test (push) Successful in 57s
Test and deploy / edge (push) Successful in 2m15s
Test and deploy / deploy (push) Successful in 1m51s
jsonb can't hold \u0000, and ON CONFLICT can't take a row twice in one
statement: either failed the whole flush, its outcomes lost and its
candidates taken until a restart. NULs are dropped from strings; the
probe_cache insert takes each message-id once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 17:45:35 +02:00
Daan MeijerandClaude Opus 5.5 9fb36d217c Prober: no claims under PROBE_MIN_FREE_GB free on the NVMe
Test and deploy / test (push) Successful in 52s
Test and deploy / edge (push) Successful in 2m5s
Test and deploy / deploy (push) Successful in 1m1s
At ~200 articles/s what the prober stores (inspections, par2 file lists,
the WAL) took ~0.8-1.1 GB an hour of homelab's root, and nothing stopped it
at the 10 GB floor. Below 12 GB free it claims nothing (resumed 1 GB above):
the lanes go dry and its share shrinks to its minimum.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 17:38:37 +02:00
Daan MeijerandClaude Opus 5.5 39480c486f NNTP shares: the account's connections shared by priority
Test and deploy / test (push) Successful in 49s
Test and deploy / edge (push) Successful in 1m54s
Test and deploy / deploy (push) Successful in 53s
The coordinator (38) and the prober (8) had a fixed split; with history
paused the coordinator's stood idle while the prober's were its limit.
nntp_shares: each process syncs every 15 s (priority, minimum, what it could
use, what it has open) and gets what it may open: minimums first, then by
priority what each wants, growing only into connections the others closed
or gave up. The pool's size and the prober's lanes follow the grant; the
coordinator doubles its want while work waits for a connection, else asks
for its peak in use and a margin; the prober wants its maximum unless the
queue is dry. Claims scale with the lanes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:20:09 +02:00
Daan MeijerandClaude Opus 5.5 7eba53043a Prober: claim range per value of unreadable, from the index ends
Test and deploy / test (push) Successful in 50s
Test and deploy / edge (push) Successful in 1m55s
Test and deploy / deploy (push) Successful in 1m59s
Over unreadable >= false Postgres walked every waiting entry of the kind:
2.5 minutes a claim at 28M archive candidates, the prober idle every other
minute. Per value each min and max is one end of the ready index (56 ms).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:00:11 +02:00
Daan MeijerandClaude Opus 5.5 a5e0399ee6 The par2 prune's cursor is (created_at to the microsecond, set_id): 20k sets of one flush share a created_at
Test and deploy / test (push) Successful in 51s
Test and deploy / edge (push) Successful in 1m57s
Test and deploy / deploy (push) Successful in 1m6s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 22:10:19 +02:00
Daan MeijerandClaude Opus 5.5 f2c5607ec3 Fold only sidecar-only releases (sidecar_only at insert); no queue-wide scan for gone releases
Test and deploy / test (push) Successful in 47s
Test and deploy / edge (push) Successful in 1m56s
Test and deploy / deploy (push) Successful in 54s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 20:57:59 +02:00
Daan MeijerandClaude Opus 5.5 aa20d6b79f The par2 prune gets 2 min per round (it held the merges back for hours); abandoned ranges past their end are finished
Test and deploy / test (push) Successful in 52s
Test and deploy / edge (push) Successful in 1m57s
Test and deploy / deploy (push) Successful in 2m42s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 20:42:14 +02:00
Daan MeijerandClaude Opus 5.5 c55918350e Poster search per poster found (LATERAL on releases_poster_newest_idx), at most 200 posters
Test and deploy / test (push) Successful in 52s
Test and deploy / edge (push) Successful in 2m7s
Test and deploy / deploy (push) Successful in 2m12s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 17:58:26 +02:00
Daan MeijerandClaude Opus 5.5 c0e00f1707 Poster search through a posters table and releases_poster_newest_idx; complete releases are final; the tail before everything (-3)
Test and deploy / test (push) Successful in 56s
Test and deploy / edge (push) Successful in 1m59s
Test and deploy / deploy (push) Successful in 5m20s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 17:25:30 +02:00
Daan MeijerandClaude Opus 5.5 aa3bd82445 At most two leases per group: a group's batches wait for each other, more workers only queue
Test and deploy / test (push) Successful in 54s
Test and deploy / edge (push) Successful in 2m4s
Test and deploy / deploy (push) Successful in 3m19s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:28:42 +02:00
Daan MeijerandClaude Opus 5.5 b73e91219e The judge's unusable waits for final: next to an unread range a release's par2 or files may still come
Test and deploy / test (push) Successful in 53s
Test and deploy / edge (push) Successful in 2m13s
Test and deploy / deploy (push) Successful in 2m20s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:06:13 +02:00
Daan MeijerandClaude Opus 5.5 ec2e5a60be Settle every 5 min in rounds of 200k, not ~3M at once hourly; range blocks in a loop of their own
Test and deploy / test (push) Successful in 1m0s
Test and deploy / edge (push) Successful in 2m1s
Test and deploy / deploy (push) Successful in 3m48s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:56:27 +02:00
Daan MeijerandClaude Opus 5.5 ce43099188 Final completeness by time window: ranges keep their posting span, release_final() over blocks of done ranges
Test and deploy / test (push) Successful in 58s
Test and deploy / edge (push) Successful in 2m4s
Test and deploy / deploy (push) Successful in 8m5s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:19:03 +02:00
Daan MeijerandClaude Opus 5.5 3d24db5565 Rules drop posters at the header pass: the CelebMovie family (rule set version 3)
Test and deploy / test (push) Successful in 50s
Test and deploy / edge (push) Successful in 1m55s
Test and deploy / deploy (push) Successful in 1m47s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:36:46 +02:00
Daan MeijerandClaude Opus 5.5 093d0a71ad The judge hides scraped celebrity pictures; no ? in its patterns (a raw query takes it for a binding)
Test and deploy / test (push) Successful in 52s
Test and deploy / edge (push) Successful in 2m0s
Test and deploy / deploy (push) Successful in 2m11s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:01:07 +02:00
Daan MeijerandClaude Opus 5.5 1a20fcd2c3 Prune par2_files of complete and judged sets (hourly, from the merger)
Test and deploy / test (push) Successful in 53s
Test and deploy / edge (push) Successful in 1m55s
Test and deploy / deploy (push) Successful in 3m35s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 07:59:40 +02:00
Daan MeijerandClaude Opus 5.5 59c93071c7 The sidecar fold every 5 min inside a long par2 pass too
Test and deploy / test (push) Successful in 48s
Test and deploy / edge (push) Successful in 1m50s
Test and deploy / deploy (push) Successful in 2m6s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 15:48:30 +02:00
Daan MeijerandClaude Opus 5.5 2e25b7c56e The sidecar fold first in a merger round: a queue, it needn't wait for the par2 pass
Test and deploy / test (push) Successful in 54s
Test and deploy / edge (push) Successful in 2m3s
Test and deploy / deploy (push) Successful in 2m18s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 15:37:53 +02:00
Daan MeijerandClaude Opus 5.5 e627862a8d The merger keeps its place over a restart (worker_cursors), not from 1970 each deploy
Test and deploy / test (push) Successful in 49s
Test and deploy / edge (push) Successful in 1m57s
Test and deploy / deploy (push) Successful in 2m4s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:45:25 +02:00
Daan MeijerandClaude Opus 5.5 329c7a1373 Fold sidecars (.nfo, .sfv, .nzb) apart from their upload into it
Test and deploy / test (push) Successful in 44s
Test and deploy / edge (push) Successful in 1m57s
Test and deploy / deploy (push) Successful in 2m14s
"Murdoch Mysteries S8D1 [00/80] - \"….nzb\"" beside its "[01/94]" upload
was a release of its own (23k sidecar-only releases on the corpus, 15k with
the poster's bigger release within 10 minutes). The settler queues small
settled releases (fold_candidates); the merger's third pass folds one whose
files are all sidecars into the poster's bigger release in the same group
within 10 minutes: the one sharing a 4+ letter word with its subject, else
the one under the same counter total, else none (via 'sidecar').

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:10:48 +02:00
Daan MeijerandClaude Opus 5.5 5897d595cf The junk judge: releases judged by what their probes showed; verdicts hide them
Test and deploy / test (push) Successful in 51s
Test and deploy / edge (push) Successful in 1m53s
Test and deploy / deploy (push) Successful in 3m29s
Voyager 1's second filter (D42) for voyager 2. Hourly, in order (the first
rule wins): dead (every probed first article gone), fake (a film, episode or
music name whose content is a program: archive entries all executables, or
the file itself by name or sniffed exe), repeated (the same first 16 KiB and
size in 20+ releases), locked (passworded, no password known), unusable
(random names, no inner name, no merge, no spot, a day after settling).
Verdicts in release_verdicts (rule, version) hide releases from search
(judged shows them); a verdict whose rule no longer matches is taken back.
Nothing dropped yet. Service judge; releases:judge --once --dry counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 11:45:08 +02:00
Daan MeijerandClaude Opus 5.5 256fb24c46 A cap on the catalog's NVMe size: above it only the tail and the stored ranges
Test and deploy / test (push) Successful in 54s
Test and deploy / edge (push) Successful in 2m3s
Test and deploy / deploy (push) Successful in 1m20s
After reset 24 the catalog grew ~3.7 GB an hour (77 GB, root 31 GB free, 600k
history ranges to go). CATALOG_MAX_NVME_GB (as voyager 1's
BACKFILL_MAX_NVME_GB): once the default tablespace is over it, leases and the
prefetcher take priority < 0 only (the tail, the stored ranges); measured once
a minute. Off when unset; 90 on homelab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:10:11 +02:00
Daan MeijerandClaude Opus 5.5 3f6bb8b162 Spots: rematch the never-tried and newest spots first
Test and deploy / test (push) Successful in 51s
Test and deploy / edge (push) Successful in 1m59s
Test and deploy / deploy (push) Successful in 1m27s
Oldest inspection first went through the 3-month backfill before today's
spots, whose releases the tail has: 3 h after reset 24, 2 of 16.7k matched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:50:40 +02:00
Daan MeijerandClaude Opus 5.5 0c5946eb06 Spots: 5,000 unmatched spots matched again an hour
Test and deploy / test (push) Successful in 58s
Test and deploy / edge (push) Successful in 2m21s
Test and deploy / deploy (push) Successful in 1m8s
After a reset every spot is unmatched: 16.5k at 500 an hour took 33 h.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:55:17 +02:00
Daan MeijerandClaude Opus 5.5 1b64fed427 Spots: a matched spot's NZB isn't kept
Test and deploy / test (push) Successful in 1m6s
Test and deploy / edge (push) Successful in 2m47s
Test and deploy / deploy (push) Successful in 1m26s
Only a spot that becomes a release of its own needs its NZB (the header
pass's releases have their chunks); spots took 2.7 GB on the NVMe at 9k.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:42:26 +02:00
Daan MeijerandClaude Opus 5.5 550f63cd84 Spots: unmatched ones matched again in turns; a standalone release gives way
Test and deploy / test (push) Successful in 58s
Test and deploy / edge (push) Successful in 2m18s
Test and deploy / deploy (push) Successful in 1m52s
A spot older than what the catalog has indexed (the spotter's first backfill
reaches back ~3 months) matched nothing and would have become a release of
its own, a duplicate once the history pass builds the upload. Unmatched
spots are matched again in turns (rematched_at) for 30 days; the 24 h before
a standalone release count from the inspection; a later match deletes the
spot's own release and links the header pass's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:19:24 +02:00
Daan MeijerandClaude Opus 5.5 7df5a638ca Spots: the spotter and the spot inspector, passwords kept apart
Test and deploy / test (push) Successful in 50s
Test and deploy / edge (push) Successful in 2m1s
Test and deploy / deploy (push) Successful in 1m28s
Two processes, one NNTP connection each (the coordinator 40 -> 38):
- spots:read (service spotter): free.pt's overviews after the last article
  seen, each spot's full header verified (lib/spotnet from voyager 1, as
  Spotweb), its description, website and NZB articles; the password its
  title or text names; delete/dispose messages applied.
- spots:inspect (service spot-inspector): each spot's compressed NZB read,
  its files listed (spot_files), each matched to the header pass's release
  by the same release identity in one of its groups within 48 h
  (release_spots); unmatched spots matched again hourly, after 24 h a
  release of their own (source spot) with the spot's NZB.
- release_passwords: per release and password, its source (nzb, spot-title,
  spot-text) and spot; the catalog keeps only passworded.
XoverClient.head(); PROBE_CONNECTIONS default 10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:10:10 +02:00
Daan MeijerandClaude Opus 5.5 2823d42bfa Merge obfuscated uploads by the random stem of their inner names
Test and deploy / test (push) Successful in 50s
Test and deploy / edge (push) Successful in 1m53s
Test and deploy / deploy (push) Successful in 2m32s
hep, hephaestus and gyges post each file under a subject name of its own
(31,000 one-file releases), but the yEnc name in each file's first article
keeps the upload's random stem ("bX147zx8I0oEgj7nzFCiorCT0ps2jEcb.7z.001"),
one stem per counter total. The merger's second pass joins releases whose
lone inspections share a random stem: one group and poster, the same total,
within 48 h, no more files than the total plus 10. An expression index over
the stem; release_merges records the kind (via) and takes a stem.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:38:31 +02:00
Daan MeijerandClaude Opus 5.5 942c4901fa Par2 merge: a set held by many releases, or a merge far larger than its set, isn't one upload
Test and deploy / test (push) Successful in 48s
Test and deploy / edge (push) Successful in 1m59s
Test and deploy / deploy (push) Successful in 1m34s
Every kantodoNNN.bin test upload carries the same par2 set: 64 releases held
it nearby and became one release of 631 files for a set of 10. A set held by
more than 4 releases nearby isn't merged, nor members with more than 3x the
set's files plus 10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:29:48 +02:00
Daan MeijerandClaude Opus 5.5 c72bf68fd2 Par2 merge: a set held by two merged releases; one failed set doesn't stop a round
Test and deploy / test (push) Successful in 51s
Test and deploy / edge (push) Successful in 1m59s
Test and deploy / deploy (push) Successful in 1m59s
A par2 index and its repost both hold a set: moving both rows to the target
broke par2_sets' primary key, and the round failed on it every minute from
20:28 UTC (no merges at all). Duplicates among the others go first; a set that
fails is logged and the round goes on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:28:50 +02:00
Daan MeijerandClaude Opus 5.5 7b436f3f77 Idle connections fetch capture ranges into the corpus
Test and deploy / test (push) Successful in 42s
Test and deploy / edge (push) Successful in 1m48s
Test and deploy / deploy (push) Successful in 1m6s
The spool only fetches what workers lease soon, in priority order, and the
tail never ends: after a reset the 1,400 capture ranges waited behind it
while 34 of 40 connections idled. Up to CORPUS_AHEAD (8) planned capture
ranges whose chunks aren't all stored are now targets after everything else,
fetched into the corpus only (no spool); a later lease reads them from disk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:11:57 +02:00
Daan MeijerandClaude Opus 5.5 cdc1cdc0cc Prober: claim only candidates of settled releases, without the join
Test and deploy / test (push) Successful in 48s
Test and deploy / edge (push) Successful in 1m59s
Test and deploy / deploy (push) Failing after 4m2s
The settler marks a settled release's candidates ready (and unreadable when
it had no readable name). Claims took the candidates by joining releases
from random points of the queue; in its newer half nothing had settled, so
a slice scanned to the end (0.3 s each, 20 slices and 5 tiers a claim) and
the prober stood still: 2.4M waiting, 0 probed a minute. Now an index over
the claimable rows only, the slices drawn within them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 12:12:59 +02:00