Files
felhom.eu/REPORT-usenet-2026-10-12.md
T
admin 52615d9139
gates / gates (push) Successful in 6m34s
Website + evidence: the Usenet pair (R-988 closed), and the drill route filed as R-989
The catalog published SABnzbd and NZBGet today (app-catalog 8ee687e). Here:

- two cards in the media category on both language sets, each with the project's own logo and
  each saying IN BOLD that a paid Usenet subscription is the household's own
- the published count 60 -> 62 everywhere it is stated; the category badges are derived from
  the cards now (media read 15 with 17 cards, otthon/home read 14 with 16 — both stale)
- documentation/audits/usenet-2026-10-12/: both bench runs, both box steps and verdicts, the
  nine defects with their measurements, what a missing provider left unmeasured, the teardown
- R-988 closed (moved to CLOSED-ITEMS in this commit); R-989 filed: the drill-catalog route of
  09 §6.5 cannot be followed — that repo is private and no box has catalog credentials, so the
  templates were staged in the box's own catalog cache instead
- walk.app_env: a SECRET field in app.yaml is stored ENC:, so that helper returns ciphertext —
  the docstring says so now, measured the hard way
- STATUS.md and REPORT-usenet-2026-10-12.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117kRTSgs3rJWUFGxyoWN6Y
2026-10-12 22:58:59 +02:00

6.8 KiB

REPORT — 2026-10-12 (late night): the Usenet pair published (R-988)

The operator asked for SABnzbd and NZBGet and asked one question first: does testing need a Usenet account? Answered with the line the work then followed — no, except for the download chain itself, which is recorded as unmeasured rather than glossed over.

What shipped

  • app-catalog-felhom.eu 8ee687e — templates/sabnzbd/ and templates/nzbget/ with onboarding/sabnzbd.md and onboarding/nzbget.md in ONE commit, plus the README tables, two FIRST-ADMIN.md class-1 rows and a fixture per app in both venues.
  • This repo — the two app cards (both language sets) with the projects' own logos, the published count 60 → 62 everywhere it is stated, corrected category badges (now derived from the cards), documentation/audits/usenet-2026-10-12/, the register changes, and this report.

What was measured, and what was not

Bench LXC 9401 (twelve questions per app) and scratch guest 9202 through the product (install from a staged FROM pin, stranger and household through traefik on the app's own public name, the guarded Update with its per-app backup, both remove choices). Both ladder steps are proven in both venues, written by upgrade-test.py --write-ladder; C3, the harness's negative control, came back failed first.

Not measured, and stated in both records and on both app pages: a household must bring a PAID Usenet provider, and this session had none, so connecting to a provider, par2 repair, unpacking, the finished file on the drive, and memory under that load are untested. The queue — the store an upgrade must not lose — is measured in both apps, seeded through their own APIs with a hand-built NZB whose articles do not exist. The operator was offered a trial account or a free text-only server and chose to publish with the gap stated; adding the download measurement later is one bench phase.

Nine defects, found by measuring

Four are lessons beyond these two apps. inet_exposure = 5 protected nobody in SABnzbd: it asks only an "external" visitor to log in, and the app's built-in LAN ranges include the 172.16/12 that traefik arrives from — a request with no credentials at all answered 200 and served the Quick-Start Wizard, until local_ranges = 127.0.0.1 replaced those defaults (which also stops the app trusting X-Forwarded-For). NZBGet kept its queue, nzb files and temp dir under MainDir, which ships as /downloads — the household's drive, the one folder this catalog classifies "optional, fetchable again", so a restore would have returned the finished files and lost what was downloading. A backup or data_paths entry must name a path the compose actually binds, or the controller rejects the block out loud and the data has no class at all (SABnzbd's first version bound two subfolders and declared their parent). An after_install readback must match the app's own JSON spacing — SABnzbd answers "key":value, the greps expected a space, so the marker never printed, the install held and the box kept the app closed, which is the gate working exactly as designed.

The rest: NZBGet's image has no curl, so the healthcheck could never pass (busybox wget now, proven both ways); its shipped config carries the documented default password in plain text and thereby breaks the app's own CLI; it asks nzbget.com for new versions; SABnzbd's healthcheck dialled /, which answers 303; and two of my own fixtures assumed tools inside containers that lack them.

Two measurement artefacts, recorded as such. NZBGet looked broken because my probe ran its CLI with docker exec, which defaults to root in that image, and recreated the app's directories as root. And the box fixture read the API key from app.yaml, where a deploy secret is stored encrypted, so the app rightly answered "API Key Incorrect"; walk.app_env's docstring now says what an ENC: value does, since the next session would have made the same mistake.

The documented drill route could not be followed — filed, not papered over

09 §6.5 runs a new app's box walk from the drill catalog. admin/app-catalog-drill is private (Gitea API: private=true; the live catalog is private=false) and no controller.yaml on 9202, current or any of its 30 saved copies, has ever carried git.username/git.token, so the box's clone fails with fatal: could not read Username, exit 128. The route worked for the campaigns of 2026-10-10 and the torrent pair earlier today, so the repository's visibility changed in between.

Rather than put a credential on a box or change a repository's visibility unasked, the two templates were staged in the box's own catalog cache — where the sync copies a catalog change anyway — with the sync interval raised to 12h for the duration and rescan used in place of sync. R-992 asks the operator to choose the real fix.

Gates and CI

catalog_gates.py --fast (whole catalog): all OK. catalog_gates.py sabnzbd nzbget: the same but for image-resolvable (needs network) and volume-persistence (refuses a host that is not a scratch host) — the two documented periodic ones, both covered on the bench. site_gates.py: OK, including the logo gate (64 catalog apps, each with its logo) and the sitemap. repo_gates.py --fast here still reports instructions and script-tests failing and wire-contract inconclusive — the same pre-existing, Windows-shaped results as this afternoon, none of them about this work; CI on the DooPlex-shaped runner is the authority and this afternoon's run was green.

Teardown — three layers, verified

Both apps removed through the product on 9202 (volumes gone, no containers, the two download folders deleted from the scratch drive, the standing apps untouched); the staging undone (out of the cache and out of /opt/docker/stacks, sync interval back to 15m), with the catalog state proven by sha256 against the published origin/main plus a decoy that must differ; bench 9401 emptied — including the three anonymous volumes it was left with, removed by name, never a prune — and stopped as it was found; the drill catalog reset to live main; the DooPlex clone clean at the published commit. Hub: nothing to undo. media/torrents and media/transmission exist again on the scratch drive as empty directories, created by the product's own storage sync for published apps, not by this campaign.

Register

Rows before 117, after 120 - a parallel session filed three of its own (R-989, R-990, R-991) while this one ran, which is also why the drill-catalog row is R-992 and not R-989. This session opened 1 (R-992) and closed 1 (R-988, moved to CLOSED-ITEMS.md in the same commit). Fixed without a row: the nine defects above, the two fixture defects, the stale category badges on the app page, and walk.app_env's docstring.