Commit Graph
23 Commits
Author SHA1 Message Date
Daan MeijerandClaude Fable 5.1 8f5f83b4ea Deploying voyager 3 without its edge worker: the no-edge marker, history replayed into the catalog
Test and deploy / test (push) Failing after 51s
Test and deploy / edge (push) Successful in 1m52s
Test and deploy / deploy (push) Skipped
deploy.sh and the nightly resume leave the edge stopped while .cache/no-edge
exists (range by range it would split releases at every edge with no merger
left). deploy/replay-window.sh takes DB and OUT and passes
REPLAY_INTO_CATALOG=1, which lets replay:corpus write a database not named
*_replay or *_scratch (never the test one).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-26 16:30:56 +01:00
Daan MeijerandClaude Fable 5.1 f437929181 Homelab: the replay container's app environment; the nightly resume honours the v2 reset
Test and deploy / test (push) Successful in 54s
Test and deploy / edge (push) Successful in 1m50s
Test and deploy / deploy (push) Skipped
deploy/replay-window.sh passes the compose app environment (HOST, PORT, APP_URL,
SPOOL_DIR, CHUNK_TABLESPACE) the ace command validates. The resume script starts
only the coordinator (the corpus fill) while .cache/v2-reset exists: the voyager 2
catalog was reset on 2026-10-26 and its workers would fill it again.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-26 08:09:45 +01:00
Daan MeijerandClaude Fable 5.1 ae735361a0 Replay harness: a --to bound and the homelab window driver
Test and deploy / test (push) Successful in 52s
Test and deploy / edge (push) Successful in 2m7s
Test and deploy / deploy (push) Skipped
edge-bench --group and replay:corpus take --to <article> next to --from, so a
replay covers one window of a group's history while the corpus holds others
(the 2016 ranges next to 2021's and 2025's). deploy/replay-window.sh runs a
window on homelab: every group whose window ranges are all stored is replayed
once into usenet_replay through the voyager-3 app image, 4 groups at a time,
looping while the corpus fill completes the rest.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-26 07:56:39 +01:00
Daan MeijerandClaude Fable 5.1 72e973d006 The replay harness: a group's corpus through one carried window into a scratch catalog
Test and deploy / test (push) Successful in 48s
Test and deploy / edge (push) Successful in 1m43s
Test and deploy / deploy (push) Skipped
replay:corpus runs edge-bench --group over a group's complete corpus ranges
in article order (one window, carried from range to range, finished after
the last range; edge/src/lease.rs holds the lease JSON the worker and the
bench share) and stores every batch through BatchStore as the worker
would, then reports releases finished, provisional, complete and the bytes
per header of the NVMe and HDD tables. Refuses a database not named
*_replay or *_scratch. The app image carries edge-bench; compose gets a
replay profile for homelab.

Design amended (REBUILD.md 1, 2, 5): the window is carried by one worker a
group, no block leases and no block merger; provisional writes stay for
the lease ends.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-26 00:27:09 +01:00
Daan MeijerandClaude Opus 5.5 0469fcd975 Prober stops claiming under 6 GB free (was 12)
Test and deploy / test (push) Successful in 51s
Test and deploy / edge (push) Successful in 1m59s
Test and deploy / deploy (push) Successful in 1m10s
The NVMe floor is 4 GB since Oct 23; at 12 the prober had claimed nothing
since Oct 23 15:30 (7-10 GB free).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:35:35 +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 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 c9a9c0155e Postgres memory for the freed RAM: shared_buffers 8GB, effective_cache_size 32GB, random_page_cost 1.1, work_mem 16MB
Test and deploy / test (push) Successful in 54s
Test and deploy / edge (push) Successful in 2m6s
Test and deploy / deploy (push) Successful in 2m13s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:57:12 +02:00
Daan MeijerandClaude Opus 5.5 dd35b49a3f Nightly pause (23:45) and resume (07:45); a deploy while paused leaves the workers stopped
Test and deploy / test (push) Successful in 55s
Test and deploy / edge (push) Successful in 2m3s
Test and deploy / deploy (push) Successful in 1m12s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 19:13:21 +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 c174b3691e PROBE_CONNECTIONS 8: 2 connections to spare
Test and deploy / test (push) Successful in 48s
Test and deploy / edge (push) Successful in 1m58s
Test and deploy / deploy (push) Successful in 52s
At 50 exactly the coordinator still got 502s now and then: a hedged request
closes its connection and opens another while the old one still counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 19:51:17 +02:00
Daan MeijerandClaude Opus 5.5 9104e9af18 PROBE_CONNECTIONS 9: with 10 the account was at 51
Test and deploy / test (push) Successful in 47s
Test and deploy / edge (push) Successful in 1m54s
Test and deploy / deploy (push) Successful in 1m22s
Coordinator 38 + its plain connection + prober 10 + spotter + spot inspector:
the spot inspector got 502 Too many connections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 19:50:35 +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 652f278474 Postgres WAL on the NVMe; wal_buffers 64 MB
Test and deploy / test (push) Successful in 57s
Test and deploy / edge (push) Successful in 1m58s
Test and deploy / deploy (push) Successful in 1m6s
Every commit waited on the WAL in ./pg on the HDD (WALWrite; the HDD 100%
busy, 56–70 ms a write): prober flushes and claims took most of each minute.
A PG_WAL_DIR volume (default /var/lib/usenet-rebuild-wal) at
/var/lib/postgresql/wal, with data/pg_wal a symlink to it (set up by hand
once, with Postgres stopped).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:17:24 +02:00
Daan MeijerandClaude Opus 5.5 2bbabc08de corpus_sweep capture: budget for the marked ranges still filling
Test and deploy / test (push) Successful in 55s
Test and deploy / edge (push) Successful in 2m12s
Test and deploy / deploy (push) Successful in 2m18s
Only the bytes on disk were checked: at 296.6 GB with 2,300 ranges complete it
marked 100 more (~310 GB). The marked ranges not complete count at the stored
ranges' mean size, and no more are marked than fit under 300 GB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:55:26 +02:00
Daan MeijerandClaude Opus 5.5 8e07478659 Counters: a total padded wider than its index is none; report diff on shared ranges
Test and deploy / test (push) Successful in 49s
Test and deploy / edge (push) Successful in 2m1s
Test and deploy / deploy (push) Successful in 1m25s
- "Very Best Of The Who [01/010]", "[02/020]", "[07/070]": a posting tool's
  total of index×10, so every track had a total of its own and was a
  release of its own. A total zero-padded wider than its index is no
  counter ("[001/010]" still is).
- corpus_sweep.py report compares builds over the ranges both replayed (the
  corpus grows between builds).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 10:12:28 +02:00
Daan MeijerandClaude Opus 5.5 3d0dc6ca1f The par2 merge: releases whose files one par2 set describes become one
Test and deploy / test (push) Successful in 44s
Test and deploy / edge (push) Successful in 1m51s
Test and deploy / deploy (push) Successful in 1m27s
The prober stores, per probed article that starts a file, the MD5 of its
first 16 KiB (file_hashes), and per par2 body the set's whole file list
(par2_files, par2_sets): FileDesc holds the same hash per file, whatever
the file was renamed to. releases:merge (the merger service, no NNTP)
merges every minute the releases of one group, posted within 48 hours of
a release holding the set's par2, whose files the set describes, into the
one with the most files: chunks, probe candidates, inspections, hashes and
counts move; the par2's shared name when none was readable; release_merges
keeps what went where. Obfuscated uploads whose files were each a release
of their own ("[9/20] - "14f5999a…"", hep: 13,232) become one.

Also: corpus_sweep.py counts the marked ranges without psql's command tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:37:35 +02:00
Daan MeijerandClaude Opus 5.5 9ea2669b2a Corpus: stored XOVER chunks for the grouping sweeps
Test and deploy / test (push) Successful in 43s
Test and deploy / edge (push) Successful in 1m48s
Test and deploy / deploy (push) Successful in 1m23s
Ranges marked `capture` keep their XOVER chunks in CORPUS_DIR
(corpus/<group>/<start>-<end>/, edge-bench's layout, range.json once
complete; only chunks that inflate). The prefetcher reads a stored chunk
instead of fetching it, so a reset re-indexes them without the news
server; a chunk a worker reports corrupt goes from the corpus too.

edge-bench gets --releases (release chunks without payload, with their
first subjects) and ships in the edge image; deploy/corpus_sweep.py marks
more ranges (capture), replays the corpus with the deployed build (replay)
and reports suspects and the change since the previous build (report).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:28:22 +02:00
Daan MeijerandClaude Opus 5.5 48f4e982f9 Rebuild: the edge workers' API in its own service
Test and deploy / test (push) Successful in 49s
Test and deploy / deploy (push) Successful in 1m16s
The node API (leases, hour-long streams, batches of up to 256 MB JSON
parsed in-process) shared the web process with the catalog API, Newznab
and the web interface; voyager 1 had to make the same split on
2026-10-06. HTTP_ROUTES picks a process's routes (node, public, all by
default): compose service node-api (same image, port 3335 on the compose
network) serves the workers, web the rest. The workers' COORDINATOR_URL
points at node-api; deploy.sh stops edge before recreating node-api.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:49:56 +02:00
Daan MeijerandClaude Opus 5.5 8bd6d6aa5f Rebuild: phase 2's prober reads the probe queue
Test and deploy / test (push) Successful in 50s
Test and deploy / deploy (push) Successful in 1m46s
probe:run (compose service prober, PROBE_CONNECTIONS, default 6) claims
waiting candidates of settled releases (lone, then par2, then archive),
fetches each article with BODY over connections of its own (no
compression) and inspects it: the yEnc name and size, the content type
from the first bytes, a par2 set's files, a RAR volume's entries and
whether they're encrypted. Results per release and kind in
release_inspections (CHUNK_TABLESPACE, the HDD); on the release
passworded, inner_name (the largest content name) and inspected_at.
430 = missing, not yEnc = error, both final; connection trouble puts
the candidate back.

Fetch and parse in one process: an article takes ~0.1 s per connection,
parsing a few ms (no queue in between). Parsers from voyager 1 (lib/yenc,
lib/rar, lib/par2, lib/content sniff) with their tests; XoverClient.body;
yencode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:32:49 +02:00
Daan MeijerandClaude Opus 5.5 fd06b16bd9 deploy.sh: remove the images a deploy replaced
Test and deploy / test (push) Successful in 30s
Test and deploy / deploy (push) Successful in 2m1s
Each deploy left a 321 MB app image dangling on the NVMe (13 after a day
of deploys).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 04:21:39 +02:00
Daan MeijerandClaude Opus 5.5 84d3af5511 Rebuild: a proper deployment for voyager 2
Test and deploy / test (push) Successful in 48s
Test and deploy / deploy (push) Successful in 2m12s
Dockerfile with two targets: app (compiled AdonisJS, production
dependencies, Node 24.16 as in CI) and edge (the Rust worker, cargo
caches as build mounts). deploy/compose.yaml, project usenet-rebuild:
postgres (data on the HDD, catalog tablespace on the NVMe), migrate,
web, coordinator, edge; edge-ts and ace behind profiles.
deploy/deploy.sh (~/bin/deploy-usenet-rebuild on homelab): fetches the
commit (must be on rebuild), builds, migrates, recreates web,
coordinator and edge (the worker stopped first), never postgres.

CI deploys a push to rebuild that passes: the deploy key's forced
command passes "deploy-rebuild <sha>" on. A push to master no longer
deploys from this branch's workflow. deploy/README.md.

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