Say what an image build is doing, and keep saying it

A build is the slow part of a first run and the thing --install triggers: apt, a Node
tarball, an npm install. Every byte of podman's transcript used to go to a log file, so
minutes of silence looked exactly like a wedge -- and a wedge is what people interrupt,
leaving a half-built image.

One line per build step, plus a notice every AISB_BUILD_QUIET_SECS (15) that a step has
shown the terminal nothing, whether it is producing output the view drops or no output at
all. AISB_BUILD_OUTPUT=progress|full|quiet picks how much the terminal sees; the complete
transcript stays in $AISB_STATE_DIR/build-*.log in all three, because the progress view is
a filter and a failed build has to be diagnosable from the raw apt output. The first line
names the extra packages going in, which is what answers "why is this run building when
the last one did not".

podman build writes its transcript to *stdout* -- the same stdout the
$(ensure_image ...) call reads back as the image ref -- so the transcript is routed onto
stderr and the ref stays one clean line. A failed build now names the package apt could
not find instead of pointing at a file to go read, and reports the time it took.
Resolving a digest by pulling the base says so too: that is a download of the base image.

tests/unit/11_build.sh stubs podman for both heartbeat paths and checks the ref, the
failure text and that a canary credential appears nowhere.

LLM-Generated: true
This commit is contained in:
2026-10-30 22:53:57 -04:00
parent 90d98dcc9e
commit ac2f310d10
5 changed files with 353 additions and 10 deletions
+30 -1
View File
@@ -233,6 +233,34 @@ distinct policy and tagged by content hash: git, curl, jq, build tools, python3,
PKG` adds packages and produces a different tag, so variants coexist, and
`--base-image` swaps the base.
### A build is not a hang
A run whose policy names an image that does not exist yet — a first run, a new
`--install`, a refreshed base, a new release of ai-sandbox itself — builds that image
before it starts anything: apt, a Node tarball, an `npm install`. Tens of seconds to a
few minutes, said out loud as it happens:
```console
ai-sandbox: building the sandbox image with 2 extra package(s): rustc cmake -- one build per policy change, reused by every run after it
ai-sandbox: build: localhost/ai-sandbox:ubuntu-1a2b3c4d5e6f (transcript: ~/.local/state/ai-sandbox/build-sandbox-1a2b3c4d5e6f.log)
ai-sandbox: build: [4/21] RUN apt-get update && apt-get install -y --no-install-recomme
ai-sandbox: build: still on [4/21] RUN apt-get update && apt-get install -y --no-in (52s, 61s total)
ai-sandbox: built localhost/ai-sandbox:ubuntu-1a2b3c4d5e6f in 84s
```
One line per build step, plus a notice every `AISB_BUILD_QUIET_SECS` (15) that a step has
shown nothing — a step downloading a toolchain and a step wedged look identical from the
terminal, and only the clock tells them apart. The names go in the first line because
that is what answers "why is *this* run building when the last one did not".
Whatever the terminal shows, the **complete** transcript of every build is written to
that file under `AISB_STATE_DIR`, and the last 25 lines of it are printed when a build
fails — with the package names called out, since a name apt has never heard of is what
`--install` usually gets wrong and it drowns in the package lists.
`AISB_BUILD_OUTPUT=full` streams podman's raw transcript instead; `=quiet` shows only the
announcements. None of it goes to stdout: `podman build` writes its progress there, and
this script's stdout is the image ref the run is then started with.
### The base is pinned by digest
A tag is a moving pointer: `FROM ubuntu:24.04` means "whatever Canonical points at
@@ -274,7 +302,8 @@ ai-sandbox ps | clean [--all] [--volumes[=GLOB]] | inspect | gate up|status|logs
```
State lives under `~/.local/state/ai-sandbox` (session dirs, `log` of every run
with no secret values, build logs). Config in `~/.config/ai-sandbox`.
with no secret values, and `build-*.log` — the full transcript of each image build,
which is what to read when a build fails). Config in `~/.config/ai-sandbox`.
`/home/sandbox` is a named volume (`aisb-home`) so npm and tool caches survive
between runs. It outlives the image, so after changing the image you may be looking