# undo case (the load fails) — 2026-09-30T12:55:47+0200
before: PG_VERSION=15 pinned={'sparkyfitness-db': 'postgres:15-alpine', 'sparkyfitness-frontend': 'codewithcj/sparkyfitness:v0.17.3', 'sparkyfitness-server': 'codewithcj/sparkyfitness_server:v0.17.3'}
    sparkyfitness: readback of the seeded weight http=200 equal=True
before: seed reads back through the front door = True
setup: CREATE EXTENSION adminpack -> CREATE EXTENSION
setup: extensions now: adminpack plpgsql
control: 18 has no adminpack: 0
  phase +0.0s backing-up | err=None
  phase +25.7s safety-dump | err=None
  phase +28.7s pulling | err=None
  phase +29.8s copying | err=None
  phase +32.8s converting | err=None
  phase +43.1s undoing | err=None
  phase +74.9s undone | err=None
result: {"accepted": true, "http": "202", "duration_s": 74.9, "final_phase": "undone", "update_error": null, "hold_reason": null, "state": "running"}
    sparkyfitness: readback of the seeded weight http=200 equal=True
after: PG_VERSION=15 pinned={'sparkyfitness-db': 'postgres:15-alpine', 'sparkyfitness-frontend': 'codewithcj/sparkyfitness:v0.17.3', 'sparkyfitness-server': 'codewithcj/sparkyfitness_server:v0.17.3'} state=running
after: seed reads back through the front door = True
controller lines:
2026/09/30 10:56:17 update.go:536: [INFO] [stacks] update sparkyfitness: accepted — guarded update started
2026/09/30 10:56:17 update.go:1365: [INFO] [stacks] update sparkyfitness: phase checking
2026/09/30 10:56:17 update.go:786: [INFO] [stacks] update sparkyfitness: ladder — the last step (1 of 1) — the catalog's current definition
2026/09/30 10:56:17 update.go:800: [INFO] [stacks] update sparkyfitness: this step CONVERTS sparkyfitness-db PostgreSQL 15 → 18 (the ladder entry's mark); database volume sparkyfitness_sparkyfitness_db_data
2026/09/30 10:56:17 update.go:816: [INFO] [stacks] update sparkyfitness: no usable copy on any tier — younger than 24h0m0s and not older than this install's deploy (2026-09-30T10:55:10Z) (found: none) — backing up first
2026/09/30 10:56:17 update.go:1365: [INFO] [stacks] update sparkyfitness: phase backing-up
2026/09/30 10:56:42 update.go:831: [INFO] [stacks] update sparkyfitness: precondition met after the backup — Tier 2 (second drive) copy from 2026-09-30T10:56:18Z
2026/09/30 10:56:42 update.go:1365: [INFO] [stacks] update sparkyfitness: phase safety-dump
2026/09/30 10:56:43 update.go:846: [INFO] [stacks] update sparkyfitness: safety dump done (1 file(s)) [/mnt/sys_drive/felhom-data/backups/primary/sparkyfitness/db-dumps/pre-restore-20260930T105643Z-sparkyfitness-postgres.sql]
2026/09/30 10:56:44 undo.go:287: [INFO] [stacks] update sparkyfitness: the undo copy will hold 3 named volume(s), 67.5 MiB
2026/09/30 10:56:45 pgconvert.go:340: [INFO] [stacks] update sparkyfitness: conversion space — database volume sparkyfitness_sparkyfitness_db_data is 67 MB; the dump needs up to 84 MB + the 2 GB floor; 27.7 GB free beside the stack dir
2026/09/30 10:56:45 update.go:1365: [INFO] [stacks] update sparkyfitness: phase pinning
2026/09/30 10:56:45 pin.go:373: [INFO] [stacks] update sparkyfitness: pin advanced to /opt/docker/felhom-controller/data/catalog-cache/templates/sparkyfitness/docker-compose.yml (sparkyfitness-db=postgres:18-alpine, sparkyfitness-frontend=codewithcj/sparkyfitness:v0.17.3, sparkyfitness-server=codewithcj/sparkyfitness_server:v0.17.3)
2026/09/30 10:56:45 update.go:1365: [INFO] [stacks] update sparkyfitness: phase pulling
2026/09/30 10:56:46 update.go:1365: [INFO] [stacks] update sparkyfitness: phase copying
2026/09/30 10:56:47 update.go:1365: [INFO] [stacks] update sparkyfitness: phase copying
2026/09/30 10:56:48 undo.go:437: [INFO] [stacks] update sparkyfitness: copied sparkyfitness_sparkyfitness_backup → sparkyfitness_sparkyfitness_backup.pre-update-20260930T105647Z in 529ms
2026/09/30 10:56:48 update.go:1365: [INFO] [stacks] update sparkyfitness: phase copying
2026/09/30 10:56:49 undo.go:437: [INFO] [stacks] update sparkyfitness: copied sparkyfitness_sparkyfitness_db_data → sparkyfitness_sparkyfitness_db_data.pre-update-20260930T105647Z in 871ms
2026/09/30 10:56:49 update.go:1365: [INFO] [stacks] update sparkyfitness: phase copying
2026/09/30 10:56:49 undo.go:437: [INFO] [stacks] update sparkyfitness: copied sparkyfitness_sparkyfitness_uploads → sparkyfitness_sparkyfitness_uploads.pre-update-20260930T105647Z in 423ms
2026/09/30 10:56:49 update.go:1365: [INFO] [stacks] update sparkyfitness: phase converting
2026/09/30 10:56:49 pgconvert.go:423: [INFO] [stacks] update sparkyfitness: CONVERTING sparkyfitness-db PostgreSQL 15 → 18 (volume sparkyfitness_sparkyfitness_db_data, kept copy sparkyfitness_sparkyfitness_db_data.pre-update-20260930T105647Z)
2026/09/30 10:56:53 pgconvert.go:468: [INFO] [stacks] update sparkyfitness: pg_dumpall from 15 done in 669ms — 369 kB, completion line present; before: 2 database(s), 94 table(s), 262 row(s)
2026/09/30 10:56:53 update.go:1365: [INFO] [stacks] update sparkyfitness: phase converting
2026/09/30 10:56:54 pgconvert.go:484: [INFO] [stacks] update sparkyfitness: database volume sparkyfitness_sparkyfitness_db_data emptied (its copy sparkyfitness_sparkyfitness_db_data.pre-update-20260930T105647Z holds the old datadir, marker checked twice)
2026/09/30 10:56:59 update.go:1066: [ERROR] [stacks] update sparkyfitness FAILED after the new version was started: conversion failed: loading the dump into 18: exit status 3 (psql: ERROR:  extension "adminpack" is not available)
2026/09/30 10:56:59 update.go:1058: [INFO] [stacks] update sparkyfitness: kept 22695 bytes of the app's own log at /opt/docker/stacks/sparkyfitness/hold-logs/20260930T105659Z/compose-logs.txt before stopping it (R-621)
2026/09/30 10:56:59 update.go:1365: [INFO] [stacks] update sparkyfitness: phase undoing
2026/09/30 10:56:59 undo.go:515: [WARN] [stacks] update sparkyfitness: UNDO — putting back the previous version and its 3 volume copy(ies) (reason: conversion failed: loading the dump into 18: exit status 3 (psql: ERROR:  extension "adminpack" is not available))
2026/09/30 10:57:31 unattended.go:511: [INFO] [stacks] update sparkyfitness: step sparkyfitness-db=postgres:18-alpine, sparkyfitness-frontend=codewithcj/sparkyfitness:v0.17.3, sparkyfitness-server=codewithcj/sparkyfitness_server:v0.17.3 recorded as undone — the automatic leg will not press it again until the catalog's ladder changes (ladder e1a1c63b3baeb597)
2026/09/30 10:57:31 undo.go:640: [INFO] [stacks] update sparkyfitness: event app_update_undone
2026/09/30 10:57:31 undo.go:568: [INFO] [stacks] update sparkyfitness: UNDONE in 31s — the previous version is running on the data from before the update (the app's health check passed)

cleanup: DROP EXTENSION adminpack -> DROP EXTENSION
RESULT undo case ok=True final_phase=undone PG_VERSION=15 seed_after=True
