docs(report): STOP-1 evidence — both legs passed; P1 answered; new R-55 finding
This commit is contained in:
@@ -128,13 +128,86 @@ promoted into `documentation/PROMPT-TEMPLATE.md` §10 (Part-5 rider).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Live validation
|
## 6. Live validation — STOP-1 RAN, both legs PASSED (operator-present)
|
||||||
|
|
||||||
**None claimed for R-51/R-52.** The three legs are destructive and operator-present. The available
|
Method: the exact endpoints the UI calls, driven from inside guest 9201 through traefik
|
||||||
method here is endpoint-level (no browser on DooPlex); these legs additionally need a container kill
|
(`--resolve felhom.demo-felhom.eu:443:127.0.0.1`, session cookie + CSRF token), plus container-level
|
||||||
and a guest reboot on the production demo box, so they are STOP-1, not a CC action.
|
truth from `docker ps -a` and the controller's own log. No browser (none on DooPlex). The session
|
||||||
|
cookie jar was deleted from the guest afterwards.
|
||||||
|
|
||||||
What IS verified without the box: the full green gate, all four design gates
|
**Deploy first, per the resolved ordering:** the operator saved the floor → `0.156.0`, the box
|
||||||
|
self-updated, and the R-23 datapoint came free —
|
||||||
|
`[selfupdate] Post-update startup: update successful (0.155.0 → 0.156.0)` then
|
||||||
|
`Current version 0.156.0 is up to date`: **one swap, no re-fire.**
|
||||||
|
|
||||||
|
### Leg A — R-51, the dead primary (12:50:40 → 12:51:52 CEST)
|
||||||
|
|
||||||
|
| Time | Event |
|
||||||
|
|---|---|
|
||||||
|
| 12:50:40 | `docker stop immich-server` → `exited | restart-policy=unless-stopped`; the three helpers stay `running` — the exact F4 shape |
|
||||||
|
| **12:50:53** | **stack state = `degraded`** (13 s). `immich-server -> exited | Exited (143)`, three helpers `running`. This read `running` for 18 hours on 2026-07-20 |
|
||||||
|
| 10:51:11Z | **exactly ONE** `Event pushed: app_start_failed (warn) — Telepített alkalmazás nem fut: Immich` — single-fire verified by `grep -c`, = 1 |
|
||||||
|
| — | Dashboard: banner *"Telepített alkalmazás nem fut: Immich (degraded)"* + link *Rendszermonitor*, and the new „Részlegesen leállt" label present in the rendered page |
|
||||||
|
| 12:51:37 | `docker start immich-server` |
|
||||||
|
| 12:51:52 | state back to `running`; **banner self-cleared** (state-based, as designed) |
|
||||||
|
|
||||||
|
The `(degraded)` in the banner is the English-state wart predicted in §7 — visible now, pre-existing,
|
||||||
|
still a copy decision rather than a bug.
|
||||||
|
|
||||||
|
### Leg B — R-52, the boot orphans (12:53:07 CEST reboot)
|
||||||
|
|
||||||
|
Fixture: `docker stop` on **bookstack** (2 containers) and **calibre-web** (containers left in
|
||||||
|
place); **UI Stop** on **immich** via `POST /api/stacks/immich/stop` (`compose down` → 0 containers).
|
||||||
|
Then `pct reboot 9201`.
|
||||||
|
|
||||||
|
```
|
||||||
|
10:53:22Z [bootrecon] Boot reconciliation: 1 boot-orphaned app(s) found: [bookstack] — up to 2 attempt(s)
|
||||||
|
10:53:28Z [bootrecon] attempt 1/2: started "bookstack" (took 6.0s)
|
||||||
|
10:53:28Z [bootrecon] complete: 1 app(s) recovered in 1 attempt(s): [bookstack]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Zero `app_start_failed`** since the reboot — a successful recovery inside the boot grace is silent,
|
||||||
|
which was the design claim. And the quiet path is observable on the healthy box too: the earlier
|
||||||
|
0.156.0 boot logged `Boot reconciliation: no boot-orphaned apps (nothing to start)`, so "nothing to
|
||||||
|
do" and "never ran" are distinguishable in production, not just in a test.
|
||||||
|
|
||||||
|
### P1 — answered, and the F5 hypothesis CONFIRMED
|
||||||
|
|
||||||
|
bookstack carries `restart=unless-stopped`. The Docker daemon came up at ~10:53:15Z. The container's
|
||||||
|
`StartedAt` is **`10:53:28.05Z` — the exact moment `bootrecon`'s `StartStack` returned.** Docker's
|
||||||
|
own restart policy did **not** resurrect it: a container stopped before shutdown is recorded
|
||||||
|
user-stopped and stays down across the reboot. Only R-52 brought it back. That is the F5 hypothesis
|
||||||
|
the audit could not test, settled with direct evidence and at zero extra cost.
|
||||||
|
|
||||||
|
### The finding this leg produced — new R-55 (it is the opposite of what the leg set out to prove)
|
||||||
|
|
||||||
|
Leg B was designed to show that a customer's deliberate Stop survives a reboot. **It does not — for
|
||||||
|
any drive-backed app.** immich, stopped from the UI seconds earlier, came back **running**:
|
||||||
|
|
||||||
|
```
|
||||||
|
10:53:18Z [gate] boot …: live bind confirmed — recreating drive-backed app immich (state=stopped) onto /mnt/felhom-drives/hdd_1
|
||||||
|
10:53:18Z [stacks] Stopping stack: immich → Starting stack: immich
|
||||||
|
```
|
||||||
|
|
||||||
|
`internal/web/intermediary.go`'s boot bind gate selects on `cfg.Deployed && HDD_PATH` alone and runs
|
||||||
|
`StopStack` + `StartStack` on every match; the stack's `state` is passed in **for the log line only**
|
||||||
|
and never consulted. calibre-web went the same way; bookstack, not drive-backed, fell through to
|
||||||
|
R-52 — which is why the sweep found exactly one orphan.
|
||||||
|
|
||||||
|
**R-52 is not implicated.** Its own gate behaved exactly as specified: immich, at zero containers,
|
||||||
|
was never a candidate. But two things follow and need an operator ruling rather than a drive-by fix
|
||||||
|
(the gate exists to fix a real bind-ordering bug and must keep doing that):
|
||||||
|
|
||||||
|
1. A customer's Stop is silently undone on drive-backed apps at every reboot.
|
||||||
|
2. **R-52's practical scope on a real box is narrower than the brief assumed** — the gate reaches
|
||||||
|
every drive-backed app first, so the boot-orphan sweep only ever sees the remainder.
|
||||||
|
|
||||||
|
Filed as **R-55**; likely shape is that the gate should recreate only apps that were RUNNING at
|
||||||
|
shutdown, i.e. the same running/stopped distinction R-52 already draws.
|
||||||
|
|
||||||
|
## 6b. What was NOT claimed live
|
||||||
|
|
||||||
|
**Nothing beyond the above.** What is verified without the box: the full green gate, all four design gates
|
||||||
(`template_id_gate.py`, `emoji_gate.py`, `native_confirm_gate.py`, `offbox_rename_gate.py` — all
|
(`template_id_gate.py`, `emoji_gate.py`, `native_confirm_gate.py`, `offbox_rename_gate.py` — all
|
||||||
OK), and the image build+push.
|
OK), and the image build+push.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user