Files
felhom-controller/REPORT.md
T
2026-10-01 08:39:51 +02:00

2.7 KiB

REPORT — v0.285.0: a box keeps two controller versions (decision 56); the update clean-up's crash (R-751) — 2026-10-01

Full session report: felhom.eu/REPORT-rulings-2026-10-01.md. Evidence: felhom.eu/documentation/audits/rulings-2026-10-01/B/. Architecture read: 09 §3 decisions 30, 45, 52, 53, 56; 03-host-agent.md (the controller swap); agent internal/localapi/controllerswap.go.

What changed

  • internal/stacks/controller_image_retention.go — RetainControllerImages(ControllerImageRecord): keeps every image a container uses, the running version's tag, the previous one (the swap record, selfupdate.UpdateState.RecordedPrevious; version order only when the record names none present), every version above the running one and every non-version tag; deletes older and untagged controller images by exact name/ID; nothing while the controller swaps itself. Called 3 minutes after every start (cmd/controller/main.go).
  • internal/stacks/image_retention.go — R-751: RetainImagesAfterUpdate returns when the app is gone after its rescan (it dereferenced a nil stack in a goroutine; a panic there ends the process).
  • internal/stacks/r650_main_test.go — both retention seams are no-ops in the package's tests.

Measured before building

The agent's swap rolls back to what /etc/felhom-controller-image named when the swap began — the running image. The controller never hands it a previous image (SwapController(ctx, target)). So the self-update's own roll-back needs only the running image; "the previous" is kept for a roll-back by hand, as ruled.

Tests and red-proofs

TestControllerRetention_* (6), TestRecordedPrevious, TestRetainImagesAfterUpdate_AppGoneDoesNotPanic. Each guard was broken on purpose and its test failed with the wrong value visible: the previous dropped from the keep switch (0.284.2 deleted), the record ignored (0.283.1 deleted), the swap check removed (deleted while swapping), the in-use check removed (an image a container uses deleted), the success check removed (a failed swap's image named as previous), the nil-stack check removed (panic). Full suite go build/vet/test ./... green; controller_gates.py --fast OK.

Live

box controller images before → after Docker images (system df) how
9202 5 → 2 3.17 → 3.10 GB bootstrap deploy (self-update is off there); previous by version order
demo-hp 9201 84 → 2 15.2 → 11.65 GB floor 0.285.0; previous from the swap record
N100 9201 76 → 2 6.07 → 1.11 GB floor 0.285.0; previous from the swap record

Each kept 0.285.0 (running) and 0.284.2 (previous). Every app container stayed up. Golden 0.285.0 baked and vouched.