# 09 — THE UNATTENDED NIGHT: an app updates with nobody pressing anything # # This is the phase the previous session's brief contained and **did not run, and did not say so** # (R-611). It runs here. The caller is `unattended-caller.py` in this directory — EVIDENCE, NOT # PRODUCT: it presses exactly `POST /api/stacks//update`, the same button a person presses, and # nothing else. No controller code was added for it. Guest 9202, controller v0.261.0. ## Scenario F — the success night: PROVEN `uptime-kuma` **2.5.0 → 2.5.1** was applied by the caller with no human action, against a real one-step catalog edge (DRILL 2, `ae08a037fd68`). Confirmed on the box afterwards: uptime-kuma installed = louislam/uptime-kuma:2.5.1 catalog = louislam/uptime-kuma:2.5.1 updating = False update_phase = done hold = none **HONEST GAP, and it is the coordinator's own instrumentation error:** that first run's stdout was piped through `tail`, which buffers, and the run was later killed — **so the caller's own log lines for the F press were lost.** The OUTCOME is solid (the box moved 2.5.0 → 2.5.1 and only the caller pressed it), but the per-pass log for F is gone. The second run below was written straight to a file for exactly this reason. Recorded rather than quietly omitted. ## Scenario G — two results, and the first one is the more interesting ### G-a. The deliberately broken edge was NEVER ATTEMPTED — the safety rule filtered it first The C3-class negative control was `vikunja: 2.6.0 → alpine:3.20`. The caller **skipped it**, because `alpine:3.20` and `vikunja/vikunja:2.6.0` are different repositories and therefore cannot be ordered, so the edge is "across" and belongs to a human (`09` §3 decision 3, §3b Q3). The box was never asked to run it: `vikunja` ended the night still on 2.6.0, no update, no hold, untouched. **That is a real finding for Slice 6 and it cuts both ways.** The within-a-major rule is the FIRST line of defence and it works — a catalog edge that cannot be ordered never reaches the guarded update unattended. But it also means **this shape of broken edge cannot be used to measure the unattended HOLD path**, because the rule that makes automatic updates safe is the same rule that refuses it. ### G-b. The no-retry property, PROVEN over three passes Reverting the catalog (`f5f6a152b513`) left all four apps running something NEWER than the catalog — R-524's Ahead state. The caller then had a genuine TERMINAL refusal to react to: pass 1/3 glance BEHIND and within a major — pressing Update glance REFUSED reason=downgrade TERMINAL — will not press again. „Ez a változat újabb a katalógusban lévőnél — visszalépés csak az üzemeltető kérésére." ... the same for uptime-kuma, vikunja and wishlist ... pass 2/3 (nothing) pass 3/3 (nothing) summary outcomes={} never_again=['glance','uptime-kuma','vikunja','wishlist'] **Four apps, pressed exactly once each, then never again across two further passes.** Nothing on the box changed: no update ran, no hold was set, no journal was written. **This is R-524 and R-609 working together end to end, unattended.** Before R-609 put `reason` on the wire the caller would have had only a Hungarian sentence to parse, and the only safe readings were "give up on everything" or "press for ever". The full log is `09-unattended-night.log`. ## What Slice 6's design now knows that it did not | question | answer, from measurement | |---|---| | how long does one app take end to end, unattended? | 51 s – 1 m 26 s for these four small apps, including the health wait — see 04/05/07 | | does the caller need new controller code? | **No.** It presses the existing guarded Update and reads the existing state. | | can it tell "wait" from "never"? | **Yes, since v0.261.0** — and not before | | does the within-a-major rule hold? | **Yes, and it is the first thing that fires** — G-a | | what does a held app look like the next morning? | **STILL UNKNOWN unattended** — see below | ## NOT MEASURED, stated plainly **The unattended HOLD path.** `09` §3b Q4 asks who is told when an automatic update ends HELD. This night never produced a hold, because the only failing edge available was one the safety rule correctly refused (G-a). Measuring it needs an edge that **passes** the within-a-major test and still fails its health check — same repository, same major version, a tag that starts and does not serve. Real images rarely offer one, so this probably needs a purpose-built image rather than a catalog move. **Q4 therefore still rests on the ATTENDED hold measured in slice 4 (v0.238.0, Scenario F), not on an unattended one.** Recorded as the gap it is.