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

98 lines
6.8 KiB
Markdown

# 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.