Stamp the container image so a rollout can be read back - #432
Merged
Conversation
The deploy pipeline has no container probe. It passes --containers-rollout and prints the value in the job summary, so "the workflow went green" has been the only evidence that a rebuilt image is serving - which is exactly what the container-side readback criterion rules out. The criterion existed; the instrument did not. container/Dockerfile ARG GIT_SHA -> ENV BUILD_SHA container/src/server.ts /health reports `build` render-production-config.mjs sets containers[].image_vars.GIT_SHA from GITHUB_SHA worker/src/index.ts GET /api/admin/container/build reads it back The stamp is self-controlling, which is the point of it. The image running in production has no code that emits a `build` key at all, so the key appearing proves the image was rebuilt and is serving, and the key being absent means the old image is still up - it can never mean "the probe did not reach the container". The next rollout is therefore its own before/after control, with no extra deploy needed to establish a baseline. Baked in at build time rather than injected at runtime: a runtime value could only answer "this is some build made after the instrument landed", while a build-time value answers which build. `image_vars` is wrangler's build-arg channel - its own types say "available to the image at build-time only" - and it is present in 4.105.0, the version the lockfile resolves and the deploy uses. The ARG sits after every expensive layer, deliberately. GIT_SHA changes on every deploy and an ARG invalidates everything below it; declared beside the other ARGs it would rebuild the Rust minidump-stackwalk, the apt layer, the Android SDK and `npm ci` on every deploy. Placed after `COPY src` it invalidates two trivial lines, and `COPY src` above it already changes whenever the source does. No stamp is written when GITHUB_SHA is unset, rather than falling back to a placeholder: a stamp that always carries some value cannot separate "built by a deploy" from "built by hand", and separating those is the whole purpose. The readback route is admin-gated. The exact deployed commit narrows a public repository to one revision for anyone asking which known issues apply, and this is run by operators, not clients. It returns `build: null` plus `stamped: false` rather than omitting the key, so a failed read cannot be mistaken for an unstamped image. Not verified here: the image build itself. There is no Docker on this machine, so the Dockerfile change is unbuilt - the two added lines are trivial syntax, but that is an argument, not a test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
TennyZhuang
force-pushed
the
feat/container-build-stamp
branch
from
August 9, 2026 10:43
03f8406 to
7719ea4
Compare
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.
Implements the instrument for task #97's container-side readback criterion.
The gap
The deploy passes
--containers-rolloutand prints the value in the job summary.There is no container probe anywhere in the pipeline, so "the workflow went green"
has been the only evidence that a rebuilt image is serving — which is precisely
what the container readback criterion rules out. The criterion existed; the
instrument did not.
Shape
container/DockerfileARG GIT_SHA→ENV BUILD_SHAcontainer/src/server.ts/healthreportsbuildworker/scripts/render-production-config.mjscontainers[].image_vars.GIT_SHAfromGITHUB_SHAworker/src/index.tsGET /api/admin/container/buildreads it back.github/workflows/deploy-hands-server.ymlGITHUB_SHAexplicitlyWhy it is self-controlling
The image running in production contains no code that emits a
buildkey.So the next rollout is its own before/after control — no extra deploy is needed
to establish a baseline, and no deploy is being requested by this PR.
Decisions worth reviewing
Build-time, not runtime. A runtime value could only answer "some build made after
the instrument landed"; a build-time value answers which build.
image_varsiswrangler's build-arg channel — its own types say "available to the image at build-time
only" — and it exists in 4.105.0, the version the lockfile resolves and the deploy
uses. (Checked against 4.105.0 specifically: an unreferenced 4.118.0 also sits in the
pnpm store, and reading types from that one would have proven nothing about the deploy.)
ARG placement is load-bearing.
GIT_SHAchanges every deploy and anARGinvalidates every layer below it. Declared beside the other ARGs it would rebuild the
Rust minidump-stackwalk, the apt layer, the Android SDK and
npm cion every deploy.Placed after
COPY srcit invalidates two trivial lines, andCOPY srcalready changeswhenever the source does.
No placeholder when unstamped. With
GITHUB_SHAunset the renderer omitsimage_varsentirely. A stamp that always carries some value cannot separate "built bya deploy" from "built by hand".
Readback is admin-gated. The exact deployed commit narrows a public repository to
one revision for anyone asking which known issues apply, and this is run by operators.
It returns
build: nullwithstamped: falserather than omitting the key, so a failedread cannot be misread as an unstamped image.
Verification
tsc --noEmit: 0 errors, against a 0-error baseline on clean main(the checked-out
worker-configuration.d.tswas stale and failed identically on main;regenerated before comparing, so this is a like-for-like result)
npm run build(tsc --noEmit): 0 errors, baseline 0environment:still boundimage_varsblock, and theno-SHA render contains 0 occurrences of
image_vars/GIT_SHANot verified: the image build. No Docker on the machine I work from, so the
Dockerfile change is unbuilt. The two added lines are trivial syntax, but that is an
argument, not a test — worth a reviewer's eye.
Rollout
Rides the next natural container rollout. This PR requests no deploy.