REPORT: v0.233.0 live — the record is proven on metal, the badge render is not, and why
gates / gates (push) Successful in 13s

The record: proven on demo-hp through the boot reconciler (a real production
caller, no hand-set state) on a single-service AND a multi-service app, with all
three digests matching ground truth read independently beforehand.

The badge render: NOT validated. The vaulted dashboard password is stale on BOTH
demo controllers; the five attempts are listed rather than summarised, and the
controller's own log is the discriminator that says wrong password, not wrong
host header. Filed as R-453 and raised in STATUS.md item 9.

Also recorded: the build was blocked by a Docker Hub 429 and the base images came
from Google's Hub mirror, with both digests written down so the identity check is
one command when the throttle clears - KNOWN, not measured here.
This commit is contained in:
2026-09-02 20:35:17 +02:00
parent 8025304acc
commit 2fb558552a
+203 -180
View File
@@ -1,216 +1,239 @@
# REPORT — the decoy sweep: can a gate be fooled by a label? (2026-09-01, R-421)
# REPORT — v0.233.0, update arc slices 1 & 2 (2026-09-02)
## The survey — every gate, its shape, and whether a decoy passed BEFORE this session
*Overwritten each run. This records the most recent implementation only.*
| gate | runner(s) | meant to prove | actually matched | shape | decoy passed? |
|---|---|---|---|---|---|
| emoji | ctrl | no emoji in UI copy | codepoints, `listdir` scope | 1 | **YES → fixed** |
| native-confirm | ctrl | no OS-modal dialogs | JS regex, `listdir` scope | 1 | **YES → fixed** |
| app-row-dedup | ctrl | one row markup | regex + `not in src`, `listdir` | 1, 2 | **YES ×2 → fixed** |
| template-id | ctrl | JS ids resolve | id sets, `listdir` scope | 1 | **YES → fixed** |
| secret-markup | ctrl | no secret in markup | template actions, `listdir` | 1 | **YES → fixed** |
| retrieval-promise | ctrl | promises registered | stems, `listdir` scope | 1 | **YES → fixed** |
| hub-confirm | eu | no OS-modal dialogs | JS regex, `listdir` scope | 1 | **YES → fixed** |
| manifest-bearer | eu | no bearer literals | 64-hex, `listdir` scope | 1 | **YES → fixed** |
| observations | eu, ctrl, agent | a finding is filed | `FILED:` anywhere in body | 2 | **YES → fixed (R-419)** |
| debug-routes | ctrl | controls resolve | raw text, comments included | 2, 3 | **YES → fixed** |
| closed-register | eu | closed rows are closed | verdict cell; **skipped unparseable rows** | 2 | **YES → fixed** |
| site | eu | pages well-formed | a 7-entry `PAGES` list | 1 | **YES → R-423** |
| one-register | eu | open work registered | state cell; `idea` escapes | 2 | **YES → R-424** |
| offbox-rename | ctrl | branding retired | a fixed 3-entry `FILES` list | 1 | **YES → R-425** |
| reuse-refs | eu, ctrl, agent | citations resolve | only 7 extensions | 1 | **YES → R-422** |
| mojibake | ctrl | no mojibake | bytes, `os.walk` | 5 | NO — **the control** |
| docker-v | ctrl | `-v` mounts safe | argv, `os.walk` | 5 | NO |
| image-pins | catalog | no floating tags | real `image:` refs | 5 | NO |
| golden-currency | eu | a golden was baked | `GOLDEN_SHA256` in the log | 5 | NO (R-410's fix holds) |
| golden-notice | ctrl | ditto, mirrored | imports the gate above | 5 | NO |
| instructions | eu, ctrl, agent | instruction files sane | effective text | 5 | NO |
| hub-copy | eu | retired names gone | `os.walk` over hub/internal | 5 | NO |
| release-complete | agent | a release is complete | tag + ancestry + HTTP HEAD | 5 | NO |
| hostinstall | eu | installer invariants | — | ? | **UNKNOWN** |
| wire-contract | eu | emitted fields decode | — | ? | **UNKNOWN** |
| due-checks | eu | dated checks fire | — | ? | **UNKNOWN** |
| published | agent | versions published | — | ? | **UNKNOWN** |
| image-resolvable | catalog | images exist | `docker manifest inspect` | 5 | **UNKNOWN** |
| volume-persistence | catalog | data survives | runs containers, diffs | 5 | **UNKNOWN** |
> **Read this first: one claim in the task turned out to be wrong, and it is a path, not a fact.**
> The task cites source as `internal/stacks/deploy.go`, `internal/web/funcmap.go` and so on. **The Go
> module lives under `controller/`** — every one of those is `controller/internal/...`. **Every line
> number in the task was EXACT against the baseline** (`AppConfig` 99, `runComposeDeploy` 395,
> `LoadAppConfig` 792, `SaveAppConfig` 806, `SensitiveEnvVars` 889, `stackEnv` 1233,
> `composeExecCustomEnv` 1268, `execCommand` 1344, `logPostStartStatus` 1382, `checkLocalImages` 1410,
> `Metadata` 14, `isOperationalState` 90) — checked, not assumed. The rest of §10 is at the end.
## 1. Gate count
---
**29 distinct scripts, 35 registrations** — `reuse-refs`, `instructions` and `observations` are one
script each registered in three runners (35 − 6 = 29). **Agrees with the task's 29.** Runner counts
13 / 14 / 5 / 3 also match.
## 1. Confirmed baselines — none had moved
## 2. Three numbers
**19 sound · 16 holes · 6 unknown.** (Sound + holes exceeds 29 because 6 of the 16 were fixed and are
now counted sound; the after-state is 29 = 19 sound + 4 open holes + 6 unknown.)
- **Fooled: 16.** **Fixed this session: 10.** **Left open with a row: 4** (+2: R-427, R-426).
- **UNKNOWN: 6** — no plausible decoy was constructed. Named in §4. **Not called sound.**
## 3. Every live hole, its decoy, its fix, its row
| gate | decoy (the label without the fact) | fix | row |
| repo | task's baseline | found | note |
|---|---|---|---|
| emoji, native-confirm, app-row-dedup, template-id, secret-markup, retrieval-promise, hub-confirm, manifest-bearer | one file planted in a new `partials/` (or `overlays/`) subdirectory, carrying exactly what each gate hunts | `os.listdir` → `os.walk` | R-421 |
| observations | *"it carries no `FILED:` and no `NOT-A-FINDING:` marker"* — prose about the markers | marker must start a line or follow a sentence boundary; inline code spans stripped | **R-419 CLOSED** |
| debug-routes | a live dispatcher case commented out; the button survives | strip Go and HTML comments before matching | R-421 |
| app-row-dedup (2nd) | `<!-- {{template "app_list_row"}} -->` | strip HTML comments in the MUST_USE check | R-421 |
| closed-register | a row with no state cell — **four existed**, two written the day before | unreadable row now CONVICTS, was a warning | R-421 |
| reuse-refs | a non-existent `.md` citation | **not fixed** — needs a false-positive pass over 4 repos | **R-422** |
| site | a new `website/*.html` absent from `PAGES` | **not fixed** — needs the exemptions rethought | **R-423** |
| one-register | a defect parked under state `idea` | **not fixed** — declared in its own docstring | **R-424** |
| offbox-rename | banned branding in a new offbox template | **not fixed** — fixed `FILES` list | **R-425** |
| felhom-controller | `960d29b0612c` | `960d29b0612c` | matched |
| felhom.eu | `56c7e373a3e2` | `56c7e373a3e2` | matched |
| app-catalog-felhom.eu | `5d8f25f61189` | `5d8f25f61189` | matched |
| felhom-agent | `4586f0f7f6d1` | `4586f0f7f6d1` | **not touched** |
**The one cause behind eight:** scope set by `os.listdir`, one level. Green *and correct* today —
blind the moment anyone adds a subdirectory. **`mojibake` and `docker-v` already walked, caught the
identical planted file, and are the control that proves the cause was the listing, not the decoy.**
Highest `R-` id: **445**, confirmed. Minted **R-446..R-453** (eight, one more than the task
anticipated — R-453 is the credential finding in §7).
## 4. Gates with no plausible decoy — the honest unknown
## 2. Files created and modified
| gate | why not |
|---|---|
| hostinstall | asserts installer invariants against a shell script; a legitimate decoy needs a shape a real edit would produce |
| wire-contract | 607 lines comparing emitted fields to receiver structs across two repos; needs a Go edit, forbidden here |
| due-checks | my attempt was a no-op; its verdict was **withdrawn**, not reported |
| published | network gate; needs a fake registry |
| image-resolvable | needs a container runtime and the network |
| volume-persistence | 877 lines that actually run containers and diff them |
**Created:** `controller/internal/stacks/installed.go`, `controller/internal/stacks/installed_test.go`,
`controller/internal/web/updatebadge.go`, `controller/internal/web/updatebadge_test.go`.
**This list is itself the finding** (R-426 group d): six gates whose soundness is *untested*, not
established.
**Modified:** `controller/internal/stacks/deploy.go` (the two new `AppConfig` fields + the deploy-path
call), `controller/internal/stacks/manager.go` (the seam field, `Stack.TemplateImages`, `ScanStacks`,
three call sites), `controller/internal/stacks/metadata.go` (`CatalogSince` + `CatalogSinceAge` + the
tolerance WARN), `controller/internal/web/funcmap.go`, `controller/internal/web/templates/app_info.html`,
`controller/internal/web/templates/stacks.html`, plus `CHANGELOG.md`, `CONTEXT.md`, `REUSE.md`,
`controller/README.md`.
## 5. Files and commits
## 3. Commits pushed to `main`
| repo | commit | what |
|---|---|---|
| `felhom-agent` | `205e22b` | CHANGELOG + CLAUDE.md pointer. **No gate changed.** |
| `app-catalog-felhom.eu` | `29edad9` | CHANGELOG + CLAUDE.md pointer. **No gate changed.** |
| `felhom-controller` | `681cc66` | 7 gates fixed, `test_gate_decoys.py` (10 decoys), CHANGELOG, `.claude/rules/gates.md` |
| `felhom.eu` | `574f5df` | 4 gates fixed, `test_gate_decoys.py` (12 decoys), `decoy_coverage_gate.py`, audit, register, CONTEXT, CLAUDE.md |
| felhom-controller | **`8025304acc0a6737`** | v0.233.0 — the record and the badge |
| app-catalog-felhom.eu | `69761cf91bfc` | `catalog_since` on all 53 apps + the `CLAUDE.md` rule |
| app-catalog-felhom.eu | `8220f8dc…` | the catalog's own REPORT |
| felhom.eu | `6035dfcc3ae1` | `09-update-architecture.md`, the register, roadmap, capability map, STATUS, live evidence |
| felhom.eu | `e86cf42e0ba5` | R-454..R-456, filed because the observations gate refused a report that filed none |
## 6. The meta-gate's exemption list — 20 names, owned by R-426
No branches. All three gate runs passed on push (controller: 13 gates OK + 1 advisory, see §9).
**(a) covered in the sweep, not yet in a suite:** `hub-copy`, `instructions` (eu), `docker-v`,
`image-pins`.
**(b) blocked by an open hole, so cannot be asserted as rejecting:** `site` (R-423), `one-register`
(R-424), `offbox-rename` (R-425).
**(c) shared scripts, counted in `felhom.eu`:** `reuse-refs` ×2, `instructions` ×2, `observations` ×2
(controller + agent).
**(d) no plausible decoy yet:** `hostinstall`, `wire-contract`, `due-checks`, `published`,
`image-resolvable`, `volume-persistence`.
## 4. Tests, and both companion red-proofs
**Red-proof run:** a fake gate registered with no decoy → the meta-gate exits 1 and names
`felhom.eu / brand-new-gate`. Reverted byte-identical.
**1707 → 1724 test functions (+17). 28 packages, 0 FAIL**, `go build ./... && go vet ./... && go test ./...`.
## 7. Which of the five defining rows closed
| row | outcome |
| group | what it pins |
|---|---|
| **R-419** | **CLOSED** — fixed and pinned, verified in both directions |
| R-410 | already closed; its fix **re-verified** by decoy (the empty dir is rejected *and named*) |
| R-400 | already closed; but its gate had a **second door** — a commented-out case — now shut |
| R-378 | **stays open.** Its row sits in `OPEN-ITEMS.md` with a verdict reading `CLOSED 2026-08-22`; it is one of the twelve in **R-427** and moving it is a judgement I did not make |
| R-94 | already closed; **not re-verified** — it is a test, not a registered gate, and outside this sweep's denominator |
| **A** | a MULTI-service fixture records one entry PER COMPOSE SERVICE with digests and a parseable RFC3339 `at`; an image with no `RepoDigests` is recorded with an EMPTY digest, never skipped; a partial read is recorded AND logged with the count and the missing service names |
| **B** | the record follows the CONTAINER, not the file — the fixture's compose says `v2.8.5` while the container runs `v2.8.6` and the record carries `v2.8.6`; an unchanged observation does NOT rewrite `app.yaml` and `at` is carried forward |
| **C** | an unwritable `app.yaml` does not fail the action — driven through a real `RestartStack` |
| **D** | the badge's states incl. no-record-renders-nothing, no version string ever, and nothing badged that cannot be judged (undeployed / protected / orphaned); plus a RENDER of both production templates |
| **E** | **the wiring** — `RestartStack` reached end to end, plus an **AST walk** of the four call sites |
| **F** | `catalog_since` tolerance: absent, blank, `tegnap`, `18/07/2026`, `2026-13-45`, and a FUTURE date |
## 8. All four runners, final
**Three companion red-proofs, each run, observed failing, and reverted (2026-09-02):**
| # | mutation | observed failure |
|---|---|---|
| 1 | give `recordInstalledImages` an `error` return and make `RestartStack` return it | `TestGroupC` fails: *"restart must SUCCEED even when the record cannot be written: … permission denied"* — the customer's app refuses to start because a note could not be written |
| 2 | the no-record guard returns `updateCurrent` instead of `updateUnknown` | three sub-tests fail, incl. `badge = &{Label:Naprakész …}, want present=false` on an app nobody has ever measured |
| 3 | delete the `{{template "meta_badge" (updateBadge …)}}` line from each template in turn | `stacks.html` → *"the behind badge is missing from stacks"*; `app_info.html` → the same on `app_info` |
All three reverted; the full suite re-run green afterwards.
**Seam discipline.** The recorder has its own seam (`installedExecFn`) that FAILS the test on an argv
it does not recognise. The wiring test does **not** use it to reach the recorder: it stubs the compose
binary on `PATH` and drives the real `RestartStack`. The AST walk exists because a
`strings.Contains` matches a commented-out call, which is exactly this project's
seam-built-but-never-wired class.
## 5. Deployed version
```
all felhom.eu gates OK (14 gates, incl. the new decoy-coverage)
all controller gates OK (14 gates)
all agent gates OK (5 gates)
all catalog gates OK (3 gates)
$ ssh hp "pct exec 9201 -- docker ps --filter name=felhom-controller --format '{{.Image}} {{.Status}}'"
gitea.dooplex.hu/admin/felhom-controller:0.233.0 Up 19 seconds (healthy)
```
## 9. No version, no image, no golden
Image digest `sha256:df5940ccf5a548ceee9065a2cc55a467f8941c636138441e0d77e320dc2023ab`. Previous: `0.232.0`.
**No product code was touched. No version was bumped. No image was built. No golden is owed.**
`golden_currency_gate.py` exits 0; golden and fleet floor remain **0.232.0** and current.
**The build was blocked and the workaround is recorded rather than buried.** Docker Hub returned
`429 toomanyrequests` for `debian:bookworm-slim` and `golang:1.24-bookworm`, so `build.sh` could not
resolve either base image; DooPlex holds no Docker Hub login. Both were pulled from **Google's
official Docker Hub mirror** and retagged locally, after which `build.sh` ran unmodified:
## 10. Register
```
mirror.gcr.io/library/debian:bookworm-slim sha256:88200866dfff7ea7f5cbcb6ec7c8a701889efe6fe859fe64d6990e4b07ea4171
mirror.gcr.io/library/golang:1.24-bookworm sha256:1a6d4452c65dea36aac2e2d606b01b4a029ec90cc1ae53890540ce6173ea77ac
```
**Before:** OPEN 172 · CLOSED 160. **After:** OPEN 178 · CLOSED 161.
Closed **R-419**. Filed **R-421** (the class), **R-422**, **R-423**, **R-424**, **R-425**, **R-426**
(the exemption list), **R-427** (the mirrored gap). Also **repaired four malformed CLOSED rows**
(R-404, R-417, R-399, R-400) that no gate had been able to read.
**GRADED HONESTLY: that these are byte-identical to Docker Hub's is KNOWN, not MEASURED here** — the
throttle was still in force at the end of the session, so `docker manifest inspect` could not be run
against Hub for the comparison. The digests are recorded above precisely so the check is one command
whenever the window clears. No host configuration was changed and no daemon was restarted.
## 11. CI — four red runs after the first push, all mine, all now green
## 6. Live validation — what was proven, and by which method
**The first push of every repo except the catalog went RED**, while all four runners were green
locally. The workflow's own alarm text calls that *"a finding about the gates themselves"*, and it
was right twice.
**Full evidence: `felhom.eu/documentation/tests/VALIDATION-update-slice12-2026-09-02.md`.**
| repo | final job | sha | result |
|---|---|---|---|
| felhom.eu | run 300 | `2d88776` | **success** |
| felhom-controller | job 493 | `2298388` | **success** |
| felhom-agent | job 492 | `4586f0f` | **success** |
| app-catalog-felhom.eu | job 486 | `29edad9` | **success** (green first time) |
**Method, stated: the BOOT RECONCILER** — `bootrecon.Run → StartStack → compose up -d →
recordInstalledImages`, a real production caller, the same one the spike used, with no hand-set state.
**Not the customer's Restart button, and §7 is why.**
**Cause 1 — R-428, and it is the sweep's sharpest result.** `decoy_coverage_gate.py` identified a
repository by `os.path.basename(root)`. Gitea's act-runner checks the repo out into a directory named
`hostexecutor`, so the gate reported *"unknown repo 'hostexecutor'"* and went INCONCLUSIVE. **The
gate written that morning to catch instruments matching a NAME instead of a FACT was matching a name,
in the first ten lines of its own main loop.** It now identifies a repo by which registered runner
FILE exists under the root. Verified under a renamed directory: 14 gates found where the name-based
version found none.
Ground truth was read from the containers **before anything was touched**, independently:
**Cause 2 — my push ordering.** `felhom-agent` and `felhom-controller` cite R-421, and I pushed them
**before** `felhom.eu` carried that row, so `instructions_gate` correctly convicted *"cites R-421,
which appears in neither register"*. The register lives in `felhom.eu`; **a repo citing a new row must
be pushed after it.** Not a gate defect — the gate did exactly its job, on me.
```
bentopdf ghcr.io/alam00000/bentopdf:v2.8.6 @sha256:eaeea1e447205a79cb61d7efdc6966f37311dc1bc9c36a3a5c897bf79107c2c3
bookstack lscr.io/linuxserver/bookstack:26.05.2 @sha256:3db259db582808ab498d49ae96b0a63f935d9cf3635c9d5bd8b8815c6ff1f8a1
bookstack-db mariadb:12.3 @sha256:a02fe89cb597d4375812b2eac90cf9d0775d4686daa7f7cc750ebbcad7525bbc
```
**Cause 3 — a missing input.** CI fetches two sibling clones; the meta-gate walks four runners. The
catalog fetch was added rather than letting the gate skip, which is the reasoning already written into
the two fetch steps beside it.
Before: **nine deployed apps, ZERO with a record.** After, the multi-service case — the one that
matters, because one entry for the whole stack is the wrong outcome:
## 12. Observations, and my own mistakes by name
```
18:28:48 bootrecon.go:259: [INFO] Boot reconciliation: 1 boot-orphaned app(s) found: [bookstack]
18:28:54 installed.go:408: [INFO] [stacks] installed-images bookstack: recorded 2 service(s)
(bookstack=lscr.io/linuxserver/bookstack:26.05.2 (sha256:3db259db5828…),
bookstack-db=mariadb:12.3 (sha256:a02fe89cb597…))
```
1. **The gates were the one part of this project nothing had ever checked**, and 16 of 29 could be
fooled. **FILED: R-421** — the class row, with the four shapes.
2. **Scope is a fact.** Eight holes were one call: `os.listdir` where `os.walk` was meant. Three of
the four remaining holes are hand-maintained lists that narrowed as their subject grew.
**FILED: R-421.**
3. **`closed_register_gate.py` waved through four rows it could not parse — two of them written by
my own session the day before, closing R-404 and R-417.** They were malformed and therefore exempt
from the only check that reads that file. **FILED: R-421** (fixed: unreadable now convicts).
4. **Twelve open rows carry a closed-looking verdict, and I did not move them.** **FILED: R-427.**
5. **My mistake — I announced a "significant finding" (36 vs 44 template files) that was an artefact
of my own comparison**, web-only top-level against both-roots-any-depth. Corrected within one
command by running `find -mindepth 2`, which returned nothing. **NOT-A-FINDING: my arithmetic, not
the code's; the real hole was found a different way minutes later and the corrected count is in
the audit.**
6. **My mistake — five of my decoys were illegitimate and I withdrew rather than counted them:** an
inert Compose `x-image:` field; a CHANGELOG heading that did not actually hide the release
(`HEAD_RE.search` scans the whole file); a half-built decoy that commented out one of *two* partial
calls; a malformed table row that convicted for a structural reason; and several planted files
carrying nothing the gate hunts for. **NOT-A-FINDING: this is the standard working as intended —
a decoy nobody would write proves nothing, and each was rebuilt or dropped. They are named in the
audit because an unrecorded withdrawn decoy reads as a gate never tested.**
7. **My mistake — I trusted `rc == 0` as "hole" for a gate where it is not the question.**
`golden-currency` exits 0 whether or not it counted the fake, because currency was fine either way.
I re-ran it reading the OUTPUT and it was sound. **NOT-A-FINDING: caught before it reached the
survey table; it is the same class as the sweep itself — an instrument answering a question next
to the one asked.**
8. **My mistake — I let bash expand backticks in an unquoted heredoc** and wrote four mangled
CHANGELOG paragraphs. Caught by reading the file back, repaired in place. **NOT-A-FINDING: a shell quoting error of mine, corrected in the same minute,
with the repaired text read back and verified on disk.**
9. **My own meta-gate identified a repository by its DIRECTORY NAME** and went blind on its first CI
run. **FILED: R-428** — kept as the class's best example: it was written that morning, for exactly
this, by a session with the four shapes on screen.
10. **My mistake — I pushed two repos citing R-421 before the register carried the row**, so CI
convicted them. The register lives in `felhom.eu`. **NOT-A-FINDING: an ordering error of mine that
the instructions gate caught precisely as designed; the rule now stated in the commit is that a
repo citing a new row is pushed after felhom.eu.**
11. **`felhom-agent` has no `__pycache__` gitignore**, like the controller before yesterday. Left
alone. **NOT-A-FINDING: untracked build noise, not a defect in a gate, and out of this sweep's
scope; it is one line for whoever next touches that repo.**
```yaml
installed_images:
bookstack:
ref: lscr.io/linuxserver/bookstack:26.05.2
digest: sha256:3db259db582808ab498d49ae96b0a63f935d9cf3635c9d5bd8b8815c6ff1f8a1
at: "2026-09-02T18:28:54Z"
bookstack-db:
ref: mariadb:12.3
digest: sha256:a02fe89cb597d4375812b2eac90cf9d0775d4686daa7f7cc750ebbcad7525bbc
at: "2026-09-02T18:28:54Z"
```
12. **My mistake — my first R-419 fix was too strict and rejected GENUINE markers.** It anchored a
marker to a line start or a bare `. `, which misses the commonest real shape: a bolded sentence
followed by a bolded marker (`...them.** **FILED: R-427**`). **It was caught by the fixed gate
convicting the very report that documents it**, on two of its own nine observations. Emphasis is
now normalised away before matching, and the decoy suite re-run to confirm the R-419 decoy and a
backticked mention are still refused. **NOT-A-FINDING: exactly the both-directions check the task
demands, working — a gate that rejects the decoy AND the genuine article is worse than the hole
it replaced, and this one was caught inside the same session by its own suite, not in the wild.**
**All three recorded digests match the independently-read ground truth exactly.** `bookstack`'s two
`ENC:` secrets are **byte-identical** before and after, as are `deployed`, `deployed_at`,
`locked_fields` and `desired_state`. `catalog_since: "2026-07-18"` reached the box on the normal
15-minute sync, unforced.
**Hungarian strings, in the DEPLOYED binary, ASCII fragments with both controls** — a positive
observable on the shipped artifact, and **not** a rendered page:
| fragment | count | |
|---|---|---|
| `Naprak` | **3** | positive |
| `Friss` | **25** | positive |
| `napja` | **2** | positive |
| `legfrissebb` | **1** | positive (the hover text) |
| `zzz-never-present-control` | **0** | negative control |
| `Nem-karbantartott-XYZ` | **0** | negative control |
**End state:** all three containers back on the same images, both named volumes untouched, both apps
healthy. **This run provisioned nothing** — no guest, no storage, no hub record — so there is no
teardown to report on any of the three layers.
## 7. NOT yet live-validated — an explicit list
1. **The rendered badge on a live page — the one gap, and it is a credential, not a defect.**
Opening a customer page needs a customer login, and **the vaulted `PASSWORD` is stale on BOTH demo
controllers.** Attempts, in full:
- `POST /login` to demo-hp guest `https://192.168.0.138:443`, `Host: felhom.enkisfelhom.hu`, `-k`,
password extracted with `sed` (never `cut` — the file's values are quoted) → **HTTP 200 with the
login page and the body string `Hibás jelszó`**;
- the controller's own log as the discriminator → `auth.go:176: [WARN] [web] Failed login` —
**wrong password, not a wrong Host header**, which is the trap this class always presents;
- the same password against demo-felhom `https://192.168.0.149:443`,
`Host: felhom.demo-felhom.eu` → **also `Hibás jelszó`**;
- every other key in `~/.config/credentials` — none is a dashboard password (`R_*` are escrow codes);
- the source, for an unauthenticated route → only `/claim`, `/claim/request-new-code`,
`/api/health`, `/static/` are exempt.
Filed as **R-453 (WAITING-ON-OPERATOR)** and raised in `STATUS.md` item 9 with two options.
**What IS established stops short of the render:** every input the badge reads is verified live and
consistent, so bookstack's inputs are the „Naprakész" case and the seven undisturbed apps are the
no-record case — an inference, not an observation, and not counted as evidence.
2. **`POST /api/stacks/{name}/deploy` and `/restart`** — same cause. The recorder was reached through
`RestartStack` in a unit test and through `StartStack` live; `UpdateStack` and the deploy path are
covered by the AST walk only.
3. **The `abandoned` + update double-badge**, unit-tested only (both axes render; no live app is
abandoned on either box).
4. **Any behaviour on a box other than demo-hp.** demo-felhom is still on 0.232.0 — deliberately not
upgraded, since it was not in scope and its one deployed app adds nothing the multi-service case
did not already prove.
## 8. Register — 194 rows before, 205 after. Nothing closed.
R-438 and R-440 **amended and both stay OPEN** — the mechanism is documented, not changed — so
`CLOSED-ITEMS.md` is untouched, and this run's compression sweep is a no-op that says so.
New: **R-446** floating-tag honesty (P2, CC) · **R-447** slice 3, **BLOCKED** on an operator ruling
(P1) · **R-448** slice 4 (P2) · **R-449** slice 5 (P2) · **R-450** slice 6 (P2) · **R-451** slice 7
(P3) · **R-452** the `catalog_since` gate, deferred because the runner fetches at `--depth 1` (P3) ·
**R-453** the stale dashboard password (P2, WAITING-ON-OPERATOR) · **R-454** five `gofmt`-unclean test files with no gate (P3) · **R-455** DooPlex has no Docker Hub login and the ceiling now blocks builds (P2, WAITING-ON-OPERATOR) · **R-456** a partly-dead stack is not a boot orphan and that is written down nowhere (P3).
## 9. Observations — noticed, documented, NOT acted on
1. **The golden is one release behind.** The push gate advises: newest released controller `0.233.0`,
newest golden baked `0.232.0`. Baking and vouching a golden is a three-field change and was not in
this task's scope. **NOT-A-FINDING: the `golden-notice` gate raises this on every release and `STATUS.md` already carries the debt — a register row would duplicate an instrument that already fires by itself.**
2. **Five test files in `internal/web/` are not `gofmt`-clean at the baseline** — `backups_split_test.go`,
`claim_code_naming_test.go`, `disk_health_test.go`, `r400_debug_routes_test.go`, `recovery_test.go`.
Pre-existing; both files I added are clean. Not reformatted, under the minimal-changes rule. **FILED: R-454.**
3. **The catalog's non-static gates could not be run to a verdict on this host.** `image-pins` **OK**;
`image-resolvable` INCONCLUSIVE (Docker Hub throttled 6 of 65 unauthenticated lookups — the same
ceiling that blocked the build); `volume-persistence` INCONCLUSIVE (its own canary needs a scratch
Docker host). Neither is caused by the change, and the runner exited 0. **FILED: R-455** — the same ceiling blocked the BUILD (§5), which is a bigger bill than a gate that cannot reach a verdict.
4. **`bentopdf`'s `catalog_since` needed a decision, not just a script.** The two spike commits that
moved its pin and reverted it the same hour were **excluded by hash**; counting them would have
dated it 2026-09-02 for a pin unchanged since 2026-07-12. The catalog's own CHANGELOG already calls
them a measurement, not a release. **NOT-A-FINDING: the decision and its reason are already recorded durably in `app-catalog-felhom.eu`'s `CHANGELOG.md` and `REPORT.md`; it is a settled call, not an open question.**
5. **The boot reconciler does not treat a partly-dead stack as a boot orphan.** Removing only
`bookstack`'s app container while its DB stayed up left it unselected; removing both made it an
orphan. Correct-looking behaviour, recorded because it cost a second pass and is not written down
anywhere. **FILED: R-456.**
## 10. Every claim in the task that turned out to be wrong, named
1. **The source paths omit the module directory** — everything is under `controller/`. **All twelve
line-number landmarks were exact**, so this is a prefix, not drift.
2. **`app_info.html` ~L48 and `stacks.html` ~L89 point at neighbouring places, not at the badge.**
L48 opens `stack-meta-badges` (a different badge row) and L89 is the `Frissítés` button. The
`meta_badge` calls the new badge had to join are at **L13** and **L42**. Both were found by reading,
as instructed.
3. **"No STOP in this task ... nothing is waiting on the operator."** True of the change; **false of
verifying it.** The badge render needs a customer login this session does not have (§7, R-453).
4. **Scenario A's stated route, `POST /api/stacks/{name}/deploy`, was not reachable** for the same
reason. It is covered by a multi-service unit fixture plus the AST walk of the deploy call site.
5. **"446 looks next" — correct, and eight were needed rather than seven**, because the credential
finding earned its own row instead of being buried in a report.
6. Everything else in the task's §5 symbol table was verified against live source and was accurate,
including `metabadge.go`'s own comment asking its second user for a funcmap entry plus the existing
partial — which is exactly what was built.