v1.3.34.3 -- Deploy automation rebuild + version display¶
Closes the eleventh strike in the upstream-behaviour pattern: the v1.3.34.1 + v1.3.34.2 fix releases shipped Go source code that never reached the running container because make deploy-prod was a silent no-op rebuild for any release that didn't manually rebuild + retag the panel image. v1.3.34.3 ships the explicit-retag flow + a panel-visible version surface so this class of failure is detectable from the UI in seconds.
Why¶
docker-compose.override.yml in ~/argos-prod (operator-managed, sync-excluded) had two lines that combined to a footgun:
services:
argos:
image: argos-prod-argos:v1.3.33 # hard-pinned image tag
build: !reset # disable build for this svc
make deploy-prod ran docker compose build argos, which the override silently turned into a no-op (zero output, exit 0). Then docker compose up -d --force-recreate re-created the panel container reusing the 16-hour-old v1.3.33 image. Net result: every "deploy" since v1.3.33 was a container restart, not a binary update.
Detection cost was very high because v1.3.34 froze argosVersion (correctly — doc-only release) and v1.3.34.1 froze it again (incorrectly — code change), so argos --version reported 1.3.33 for all three releases. There was no discriminator the operator could check to confirm the new binary was running.
This release ships two bundled fixes that close the gap and make it operator-visible.
What ships¶
FIX 1 — /api/system/version endpoint + panel display¶
Backend (backend/internal/api/system.go):
- New
GET /api/system/versionhandler, sibling to the existing/api/system/health. Admin-authenticated. Returns: commitandbuilt_atare omitempty — when the binary was built without ldflags injection (e.g. localgo build ./...), they're empty strings server-side and drop out of the JSON response client-side. The dev path shows"version": "1.3.34.3"only.- Two unit tests cover the populated path and the empty-optionals path.
Build-flag injection (backend/Dockerfile):
ARG ARGOS_VERSION=
ARG ARGOS_COMMIT=
ARG ARGOS_BUILT_AT=
RUN CGO_ENABLED=0 GOOS=linux go build \
-trimpath \
-ldflags="-s -w \
${ARGOS_VERSION:+-X main.argosVersion=${ARGOS_VERSION}} \
${ARGOS_COMMIT:+-X main.argosCommit=${ARGOS_COMMIT}} \
${ARGOS_BUILT_AT:+-X main.argosBuiltAt=${ARGOS_BUILT_AT}}" \
-o /out/argos \
./cmd/argos
Shell ${VAR:+value} expansion is the safety net: if the build-arg is unset (e.g. docker build . without args), the ldflag is dropped entirely so the source-tree fallback in main.go wins. Only an explicit non-empty arg overrides.
argosBuiltAt added to main.go, threaded through server.Config → api.Handlers so the handler can render it.
Frontend (frontend/src/components/Layout.tsx + pages/System.tsx):
- Header VersionPill between the logo and the status pills. Subtle
v1.3.34.3text in monospace, slate-700 border. Hover tooltip showscommit f4ccffb • built 2026-04-27T11:34:15Z. Click routes to/system. - System page Build card: the leftmost card on the diagnostics grid. Shows
version,commit(when available), andbuiltas a relative timestamp via the existingRelativeTimecomponent. When the binary was built without ldflags (dev path), an amber notice replaces the missing fields: "built without ldflags (commit/built_at unavailable)". - Both surfaces fed by the same one-shot
api.systemVersion()fetch on Layout/System mount. Build-static — no periodic refetch.
FIX 2 — make build-prod-image explicit-retag flow¶
Makefile:
- New target
build-prod-image: - Reads
argosVersionfrombackend/cmd/argos/main.go(single source of truth) viagrep -oE. - Resolves
git rev-parse --short HEADand the current UTC timestamp. - Runs
docker build --build-arg ARGOS_VERSION=$VER --build-arg ARGOS_COMMIT=$COMMIT --build-arg ARGOS_BUILT_AT=$BUILT -t argos-prod-argos:$VER -f backend/Dockerfile . sed-rewrites theimage:line in~/argos-prod/docker-compose.override.ymlto point at the new tag.deploy-prodrewired:sync-prod(--yes)build-prod-image(replaces the silent no-op build)docker compose up -d --force-recreate --no-deps argosverify-deploy(auto, with 6s health-stabilisation sleep)- New target
verify-deploy: asserts the deployed binary's version string matchesargosVersioninmain.go. Readsdocker exec argos-prod-panel /argos --help. IfARGOS_SESSION_TOKENis set, also hits the panel's/api/system/versionendpoint and asserts the wire response matches. Exits 1 on mismatch with a clear FAIL line. The loud failure is the entire point — silent no-ops are how v1.3.34.1 + v1.3.34.2 reached the operator without taking effect.
build: !reset stays in the override file by design: it prevents implicit retags via docker compose up --build from producing moving-target images. Documented in docs/operations/deployment.md under "The explicit-retag flow".
EFFECT smoke — scripts/smoke/deploy-rebuild.sh¶
A new destructive smoke (refuses to run without --yes) that exercises the full deploy-rebuild flow against the live prod stack:
- Captures the current
argosVersion. - Patches
main.gowith<version>-smokesentinel. - Runs
make deploy-prod. - Asserts:
- Image
argos-prod-argos:<sentinel>exists locally. - Override file's
image:line was rewritten. - Running container uses the new image.
/argos --helpreports the sentinel./api/system/versionreports the sentinel (when session token is provided).- Restores
main.goand re-runsdeploy-prodto leave the stack on the original tag.
Self-executed against the live stack pre-tag (this release). PASS: original v1.3.34.2 → sentinel v1.3.34.3-smoke → restore to v1.3.34.3 → all assertions green. Binary inspection confirms ldflags-injected 1.3.34.3, f4ccffb, and 2026-04-27T11:34:15Z strings all reach the running binary.
Documentation¶
docs/operations/deployment.md:
- New "The explicit-retag flow (v1.3.34.3+)" subsection documenting the new Makefile chain, why
build: !resetstays, the source-of-truth contract forargosVersion, and theverify-deployfailure-mode coverage. - Updated Makefile target listing to include
build-prod-imageandverify-deploy.
scripts/check-no-personal-data.sh clean.
Files changed¶
backend/cmd/argos/main.go(argosBuiltAtvar; bumpedargosVersionto1.3.34.3; wired into Handlers)backend/internal/api/handlers.go(ArgosCommit+ArgosBuiltAtfields)backend/internal/api/system.go(SystemVersionhandler + type)backend/internal/api/system_test.go(new, 2 tests)backend/internal/server/server.go(route registration + Config plumbing)backend/Dockerfile(build-arg ldflags injection)frontend/src/api/client.ts(SystemVersiontype +systemVersion()method)frontend/src/components/Layout.tsx(headerVersionPill)frontend/src/pages/System.tsx(Build card)frontend/package.json(version1.3.34.3)Makefile(build-prod-image,verify-deploy,deploy-prodrewired)scripts/smoke/deploy-rebuild.sh(new)docs/features/notifications.md(no change in this release)docs/operations/deployment.md(explicit-retag flow)docs/release-notes/v1.3.34.3.md(this file)CHANGELOG.md,mkdocs.yml
Upgrade¶
cd ~/argos-edge
git pull
make sync-prod
make deploy-prod # now actually rebuilds + retags
# + verifies the deployed version
After deploy-prod finishes successfully, the operator-visible verification is one glance at the panel header: the version pill reads v1.3.34.3. Hover for commit + built_at; click for the full Build card on /system.
For operators with a Telegram channel that has been silently failing on every notification since v1.3.21: this release does not change the v1.3.34.1+v1.3.34.2 fix logic itself — those fixes were correct. v1.3.34.3 just makes them actually deploy. After upgrade, the Telegram fix should take effect on the next notification event without any further action.
Eleventh-strike entry¶
memory/project_four_strike_upstream_pattern.md becomes eleven with this release. The new strike's lesson:
Silent no-ops in deploy automation are worse than loud failures. Always pair a deploy step with a verify-EFFECT step that exits 1 on mismatch. AND deploy state should be visible from the user surface (panel UI / API endpoint), not require container shell access. AND never freeze argosVersion when Go source changes — only freeze for tag-without-rebuild releases (precedent: v1.3.27.1).
Future fix releases that touch Go source: bump argosVersion, verify the new value reaches the deployed binary, never trust "I ran make deploy-prod, the deploy must be done."