c85262111c
gates / gates (push) Successful in 23s
Part 0 — floor raised to 0.260.0, MinAgent 0.131.0 declared. 3 boxes below, all down or blocked; both demo boxes SERVED. Part 1 (R-610) — the DANGEROUS power cut, measured three times with three apps and two cut mechanisms. All ended honest: resumed, completed, and pinned/installed/live compose/docker inspect all agreed. vikunja's 2.6.0 migration had ALREADY run 0.64 s after the cut decision and the seeded data read back intact — so the branch that is one step from old-binary-on-migrated-database is now evidence, not argument. Instrument limit stated: `starting` lasts under a second; all three landed in `verifying`, which RecoverUpdates handles in the same branch. Part 3 (R-611) — the night the previous session skipped without saying so. An app updated with nobody pressing anything; a terminally-refused app was pressed exactly once and never again over three passes. The unattended HOLD was NOT produced: the within-a-major rule correctly refused the broken edge before it was attempted, so Q4 still rests on the attended hold from slice 4. Said plainly rather than implied. Rows: closed R-608/609/610/611; opened R-612 (P1 wishlist unusable on a fresh install, and its error is a lie), R-613 (uptime-kuma healthy on its setup wizard), R-614 (stale update phase survives a redeploy). R-520's pointer corrected. Catalog: two drill pairs, both reverted; every image line byte-identical to ff9717d3. The alpine:3.20 negative control a security review flagged is cleared. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
130 lines
8.3 KiB
Plaintext
130 lines
8.3 KiB
Plaintext
# 04 — SCENARIO A: vikunja 2.3.0 -> 2.6.0, cut decided in `starting`
|
|
# guest 9202 (demo-hp-scratch), controller 0.260.0, 2026-09-21
|
|
#
|
|
# VERDICT: the box ended HONEST. The update resumed after the reboot and finished `done`;
|
|
# all four version observables agree on 2.6.0; the seeded task read back unchanged; the
|
|
# journal is gone; the household sentence is „Naprakesz" / "Up to date".
|
|
#
|
|
# THE ONE THING THAT DID NOT GO AS THE BRIEF ASSUMED — stated first because it changes
|
|
# how capture (1) should be read:
|
|
# The DECISION was taken in `starting` (12:28:26.244 UTC, poll cadence ~21 ms).
|
|
# But `pct stop 9202` took 3 759 ms to return, and the update moved on inside that window.
|
|
# The journal read OFF the stopped guest proves where the box actually died:
|
|
# phase "verifying", not "starting".
|
|
# `starting` on this box lasts about 0.6 s (12:28:26.244 -> vikunja's own 14:28:26.881+02:00
|
|
# migration line). NO instrument available here can land a guest kill inside it: the poll is
|
|
# fast enough (21 ms), the CUT COMMAND is not (3.8 s).
|
|
# This costs nothing for the measurement, because RecoverUpdates handles `starting` and
|
|
# `verifying` in the SAME branch (update.go:909 `case UpdatePhaseStarting, UpdatePhaseVerifying`).
|
|
# Scenario A and Scenario B therefore exercise one recovery arm, not two. Recorded, not hidden.
|
|
|
|
## (1) TIMESTAMP TABLE
|
|
poll target : GET /api/stacks/vikunja, HTTPS keep-alive from DooPlex
|
|
measured poll cadence : ~21 ms (per-sample HTTP cost 1.1-1.3 ms + 20 ms sleep)
|
|
Update pressed : 12:28:23.075 UTC (POST /api/stacks/vikunja/update -> {"accepted":true})
|
|
phase AT THE DECISION : "starting" observed 12:28:26.244 UTC
|
|
cut command : ssh -S <prewarmed master> demo-hp 'pct stop 9202'
|
|
cut command LATENCY : 3 759 ms (returned 12:28:30.006 UTC, rc=0, no output)
|
|
phase the box DIED in : "verifying" (from update-journal.json read off the stopped guest)
|
|
guest restarted : pct start 9202 returned after 3.6 s; controller up 12:29:48 UTC
|
|
total app downtime : ~79 s (vikunja stopped 12:28:26.9 .. restarted 12:29:47.3 UTC)
|
|
|
|
## (1b) the phase trace, verbatim from the poller
|
|
12:28:21.860 updating=False phase='' label='' state=running err=''
|
|
12:28:23.088 updating=True phase='safety-dump' label='Adatbázis pillanatkép…' state=running err=''
|
|
12:28:23.110 updating=True phase='pinning' label='Új verzió letöltése…' state=running err=''
|
|
12:28:23.132 updating=True phase='pulling' label='Új verzió letöltése…' state=running err=''
|
|
12:28:26.244 updating=True phase='starting' label='Indítás az új verzióval…' state=running err=''
|
|
--- DECISION at 12:28:26.244: phase='starting' -> firing cut: ssh -S /tmp/cm-demohp demo-hp 'pct stop 9202'
|
|
--- CUT returned rc=0 after 3759 ms
|
|
--- CUT stdout:
|
|
--- CUT stderr:
|
|
|
|
=== TIMESTAMP TABLE (vikunja) ===
|
|
poll cadence : measured below
|
|
phase at decision : 'starting' at 12:28:26.244 UTC
|
|
cut command : ssh -S /tmp/cm-demohp demo-hp 'pct stop 9202'
|
|
cut command latency : 3759 ms (returned 12:28:30.006 UTC)
|
|
|
|
## (1c) update-journal.json read from the STOPPED guest
|
|
# The brief's path was WRONG for this guest: /var/lib/lxc/9202/rootfs/var/lib/felhom is an
|
|
# EMPTY MOUNTPOINT while the guest is stopped, because mp0 is a separate raw volume
|
|
# (nvme-scratch:9202/vm-9202-disk-1.raw). The POSITIVE CONTROL failed there: no catalog-cache/.
|
|
/bin/bash: line 131: pct: command not found
|
|
# DOES attach mp0, and then the same path is real (catalog-cache/ present).
|
|
/bin/bash: line 132: pct: command not found
|
|
/bin/bash: line 132: pct: command not found
|
|
# Remember to afterwards or refuses.
|
|
{
|
|
"updates": {
|
|
"vikunja": {
|
|
"phase": "verifying",
|
|
"started_at": "2026-09-21T12:28:23.06699273Z",
|
|
"prev_pin": {
|
|
"vikunja": "vikunja/vikunja:2.3.0"
|
|
},
|
|
"prev_compose": "/opt/docker/stacks/vikunja/pre-update-compose.yml",
|
|
"prev_applied": "/opt/docker/stacks/vikunja/pre-update-applied.yml",
|
|
"proven_copy_at": "2026-09-21T12:26:12Z",
|
|
"proven_tier": 1
|
|
}
|
|
}
|
|
}
|
|
## (2) RecoverUpdates log lines after the restart, VERBATIM
|
|
2026/09/21 12:29:48 update.go:909: [WARN] [stacks] update recovery: vikunja was interrupted in verifying (started 2026-09-21T12:28:23Z) — the new version may have run; marking it Updating and RESUMING the health wait
|
|
2026/09/21 12:29:48 update.go:951: [INFO] [stacks] update vikunja: resuming after a controller restart — `up -d` then the health wait
|
|
2026/09/21 12:29:48 update.go:858: [INFO] [stacks] update vikunja: phase verifying
|
|
2026/09/21 12:29:48 update.go:652: [INFO] [stacks] update vikunja: healthy after 0s (the app's health check passed)
|
|
2026/09/21 12:29:49 update.go:658: [INFO] [stacks] update vikunja: DONE in 1m26s
|
|
|
|
## (3) THE FOUR VERSION OBSERVABLES, SIDE BY SIDE (after recovery)
|
|
1_pinned_images : {"vikunja": "vikunja/vikunja:2.6.0"}
|
|
2_installed_images : {"vikunja": "vikunja/vikunja:2.6.0"} | digest: {"vikunja": "sha256:417ada6f94e81f0267a"}
|
|
(updating=False phase=done label=Frissítve err=- hold=-)
|
|
3_live compose line: image: vikunja/vikunja:2.6.0
|
|
4_docker inspect : vikunja/vikunja:2.6.0 | RepoDigest: sha256:417ada6f94e81f0267a | started 2026-09-21T12:29:47.287254768Z
|
|
-> all four name vikunja/vikunja:2.6.0; installed digest and the running container's
|
|
RepoDigest are the same sha256:417ada6f94e81f0267a...
|
|
|
|
## (4) the seeded data, read back through vikunja's own front door
|
|
vikunja version: v2.6.0
|
|
TASK 1 'SEED-VIKUNJA-CANARY-9f3c1e-20260921' desc= 'power-cut drill canary'
|
|
POSITIVE CONTROL: seed present = True
|
|
NEGATIVE CONTROL: absent string present = False
|
|
|
|
## (4b) the vikunja MIGRATION line, VERBATIM from its container log
|
|
3:time=2026-09-21T14:28:26.881+02:00 level=INFO msg="Running migrations…"
|
|
5:time=2026-09-21T14:28:26.915+02:00 level=INFO msg="Ran all migrations successfully."
|
|
9:time=2026-09-21T14:28:26.922+02:00 level=INFO msg="Vikunja version v2.6.0"
|
|
14:time=2026-09-21T14:29:47.713+02:00 level=INFO msg="Running migrations…"
|
|
16:time=2026-09-21T14:29:47.734+02:00 level=INFO msg="Ran all migrations successfully."
|
|
20:time=2026-09-21T14:29:47.745+02:00 level=INFO msg="Vikunja version v2.6.0"
|
|
-> the FIRST migration ran at 14:28:26.881+02:00 = 12:28:26.881 UTC — 0.64 s AFTER the cut
|
|
decision and 3.1 s BEFORE pct stop returned. The 2.6.0 schema migration had ALREADY
|
|
been applied to the customer's SQLite database when the power went. The pin did not
|
|
roll back (that only happens in the pinning/pulling branch), so old binary vs migrated
|
|
database never happened here — but it is the failure this branch is one step away from.
|
|
|
|
## (5) the app page's sentence to the household, both languages
|
|
vikunja [hu] http=200
|
|
[Naprak] ...tems:center;gap:.5rem"> <span class="stack-state-badge state-run">Fut</span> <span class="tag tag-ok" title="Ez az alkalmazás a legfrissebb elérhető változatot futtatja.">Naprakész</span> <a href="https://tasks.enkisfelhom.hu" target="_blank" class="btn btn-sm btn-outline">Megnyitás ↗</a> <a href="/stacks/vikunja/logs" class="btn btn-sm btn-outl
|
|
NEGATIVE CONTROL 'ZZZNOTPRESENT' found: False
|
|
vikunja [en] http=200
|
|
[Up to date] ...align-items:center;gap:.5rem"> <span class="stack-state-badge state-run">Running</span> <span class="tag tag-ok" title="This app is running the newest version available.">Up to date</span> <a href="https://tasks.enkisfelhom.hu" target="_blank" class="btn btn-sm btn-outline">Open ↗</a> <a href="/stacks/vikunja/logs" class="btn btn-sm btn-outline"
|
|
NEGATIVE CONTROL 'ZZZNOTPRESENT' found: False
|
|
|
|
## (6) done or HELD, and did a journal entry survive?
|
|
ended: update_phase=done, update_phase_label='Frissitve', updating=false, hold_reason=none
|
|
controller log: 'update vikunja: DONE in 1m26s'
|
|
POSITIVE CONTROL: catalog-cache present -> this IS the controller data dir
|
|
ls: cannot access '/var/lib/docker/volumes/felhom-controller-data/_data/data/update-journal.json': No such file or directory
|
|
-> no journal entry survived the reboot.
|
|
|
|
## STOP CONDITIONS — none tripped
|
|
seeded data gone/unreadable : NO (read back byte-identical)
|
|
updating:true that never clears : NO (cleared 1.3 s after boot)
|
|
journal surviving a 2nd reboot : N/A, no journal survived the 1st
|
|
pin naming one version, container another : NO
|
|
resumed update retrying in a loop : NO (one resume, one success)
|
|
HOLD with no household sentence : N/A, no hold
|