fix(embed): re-clone console per build — stop shipping a frozen embed

The console-clone+build layer was keyed only on static text ('git clone
--branch main'), so on the persistent ARC dind BuildKit cache EVERY cloud
build re-embedded the SAME stale console snapshot. New console work — the
native Tracker module, and everything since the cache was first warmed —
silently never shipped: console.hanzo.ai/tracker rendered an old surface
with zero /v1/tracker calls even on a freshly-deployed image.

Fix (values, not places): release.yml resolves hanzoai/console main HEAD
(git ls-remote) at build time and threads it through --build-arg CONSOLE_REF;
the Dockerfile fetches that exact ref (init+fetch+checkout, sha- or branch-
capable). A changed sha moves the layer cache key, so each build embeds the
live console commit — deterministically pinned, never frozen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
zeekay
2026-07-09 16:45:56 -07:00
co-authored by Claude Opus 4.8
parent a1551bf593
commit c97af12f4f
2 changed files with 34 additions and 1 deletions
+21
View File
@@ -120,6 +120,19 @@ jobs:
echo "sha_short=$(git rev-parse --short "$GITHUB_SHA")" >> "$GITHUB_OUTPUT"
echo "Next release: v${version} (git_max='${git_max:-none}' container_max='${cont_max:-none}')"
# Resolve the console commit to embed = hanzoai/console main HEAD, RIGHT NOW.
# Threaded into the build as --build-arg CONSOLE_REF so the console clone+build
# layer's cache key moves with console HEAD (otherwise a static `main` freezes
# the embed on a persistent BuildKit and new console work never ships). Fail
# loud if it can't be resolved — a blank ref would silently re-freeze the embed.
console_sha="$(git ls-remote "https://x-access-token:${GH_PAT}@github.com/hanzoai/console.git" main | cut -f1)"
if [ -z "${console_sha}" ]; then
echo "::error::could not resolve hanzoai/console main HEAD — refusing to build a stale embed"
exit 1
fi
echo "console_ref=${console_sha}" >> "$GITHUB_OUTPUT"
echo "Embedding console @ ${console_sha}"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
@@ -159,6 +172,10 @@ jobs:
load: true
tags: cloud:smoke
labels: ${{ steps.meta.outputs.labels }}
# Pin the console commit to embed (main HEAD, resolved above). Moves the
# clone+build cache key with console HEAD so the embed is never frozen.
build-args: |
CONSOLE_REF=${{ steps.ver.outputs.console_ref }}
# gh_token: BuildKit secret the Dockerfile consumes to fetch private
# cross-org Go modules (hanzoai/*, luxfi/*) over authenticated git.
secrets: |
@@ -245,6 +262,10 @@ jobs:
ghcr.io/hanzoai/cloud:sha-${{ steps.ver.outputs.sha_short }}
ghcr.io/hanzoai/cloud:latest
labels: ${{ steps.meta.outputs.labels }}
# SAME pinned console as the smoke build → every layer is a cache hit and the
# pushed image is byte-identical to the one the smoke test proved.
build-args: |
CONSOLE_REF=${{ steps.ver.outputs.console_ref }}
secrets: |
gh_token=${{ secrets.GH_PAT }}
+13 -1
View File
@@ -29,6 +29,16 @@
# (pure-Go dev image with no Node console), which is NEVER set for prod.
FROM public.ecr.aws/docker/library/node:24-alpine@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd AS console
ARG CONSOLE_REPO=https://github.com/hanzoai/console.git
# CONSOLE_REF pins the exact console commit this image embeds. release.yml resolves
# it to console main's HEAD sha at build time (`git ls-remote`) and passes it here.
# WHY a sha, not the bare branch name: the clone+build layer's BuildKit cache key is
# derived from the RUN text + build args. With a static `main` it NEVER changes, so
# on a persistent BuildKit (the ARC dind cache volume) every cloud build re-embeds
# the SAME frozen console snapshot — new console work (Tracker, …) silently never
# ships. Threading the sha through CONSOLE_REF moves the cache key with console HEAD:
# a changed sha invalidates the layer → fresh fetch of exactly that commit. A bare
# `main` (local/dev builds with no build-arg) still fetches fine — fetch-by-ref below
# resolves a branch name OR a sha, so this is one path for both.
ARG CONSOLE_REF=main
RUN apk add --no-cache git
WORKDIR /console
@@ -45,7 +55,9 @@ RUN --mount=type=secret,id=gh_token \
if [ -s /run/secrets/gh_token ]; then \
git config --global url."https://x-access-token:$(cat /run/secrets/gh_token)@github.com/".insteadOf "https://github.com/"; \
fi && \
git clone --depth 1 --branch "${CONSOLE_REF}" "${CONSOLE_REPO}" . && \
echo ">> embedding console @ ${CONSOLE_REF}" && \
git init -q . && git remote add origin "${CONSOLE_REPO}" && \
git fetch --depth 1 origin "${CONSOLE_REF}" && git checkout -q FETCH_HEAD && \
npm install --no-audit --no-fund --fetch-retries=5 --fetch-retry-mintimeout=20000 --fetch-timeout=120000
# FAIL-HARD. build:embed MUST emit a REAL bundle — a non-empty out/index.html AND
# an out/_next/ chunk dir — and /out then carries it into the Go embed path. If the