fix(appliance): narrate the slow image load, and say so on every console when setup stops (#1028) - #1033
Merged
Merged
Conversation
…ole when setup stops (#1028) Two halves of the same problem: a first boot that is working and a first boot that has died looked identical on the console, and both looked like "still starting". The load. `podman load` prints nothing a console ever sees, and on USB media the step runs for minutes — 3m47s measured on the HP bench — behind a line promising "a minute or two". A working box was read as hung twice, once from the console photo and once live. A rising elapsed count is the whole fix: it is the one thing that separates slow from stuck. Every 30s, so a four-minute load costs eight lines. The heartbeat is the background job and the load stays in the FOREGROUND. Backgrounding the load and polling it with `kill -0` looks equivalent and is not: a finished-but-unwaited child is a zombie that still answers, so a fast load would pay a full sleep interval for work already done. Keeping the load in front also preserves its exit status untouched. The failure. `error` writes to stderr, which systemd routes to /dev/console — ONE device, whichever the kernel cmdline named last. On a box whose monitor is not that device a fatal failure is invisible, so the newest line on screen stays "preparing the setup page" and a stopped box reads as a slow one for as long as the operator is willing to wait. That is exactly how a three-minute failure was mistaken for an hour of progress. The wizard's fatal path now says it through _console, which reaches every physical console, and names the command that explains why. Four unit tests, including the fast-load case that fails if the zombie race is reintroduced. The heartbeat interval takes a test seam so the slow case runs in seconds rather than minutes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6 tasks
VijitSingh97
changed the base branch from
fix/1029-readonly-root-install
to
develop-v2
August 16, 2026 18:02
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1028. Stacked on #1032 (
fix/1029-readonly-root-install) — merge that first, then retarget this todevelop-v2withgh api -X PATCH repos/p2pool-starter-stack/pithead/pulls/N -f base=develop-v2(gh pr edit --baseis currently throwing GraphQL 502s).Two halves of one problem: a first boot that is working and a first boot that has died looked identical on the console, and both looked like "still starting".
The silence
podman loadprints nothing a console ever sees, and on USB media the step runs for minutes — 3m47s measured on the HP bench — behind a line promising "a minute or two".That is not hypothetical. It caused a wrong "it's hung" call twice today: once by me from the issue's console photo, and once by the operator watching a box that was in fact healthy and came up 4m13s after boot.
A rising elapsed count is the whole fix — it is the one thing that separates slow from stuck. Every 30s, so a four-minute load costs eight lines.
The heartbeat is the background job; the load stays in the foreground. Backgrounding the load and polling it with
kill -0looks equivalent and is not: a finished-but-unwaited child is a zombie that still answers, so a fast load would pay a full sleep interval for work already done. Keeping the load in front also leaves its exit status untouched.The failure
errorwrites to stderr, which systemd routes to/dev/console— one device, whichever the kernel cmdline named last. On a box whose monitor is not that device, a fatal failure is invisible, so the newest line on screen stays "preparing the setup page" and a stopped box reads as a slow one for as long as the operator is willing to wait.That is exactly how a three-minute failure was mistaken for an hour of progress in #1029. The wizard's fatal path now says it through
_console, which reaches every physical console, and names the command that explains why.Verification
make lintshfmtapplied)tests/stackThe heartbeat interval takes a test seam (
PITHEAD_LOAD_HEARTBEAT_SECS) so the slow case runs in seconds rather than minutes — same idiom as the otherPITHEAD_*seams.Related: #1030 covers what interrupted the write, and notes that a volatile journal is why none of this was diagnosable after the fact.