Ask whether a stack is stale by digest, not by uptime #77
No reviewers
Labels
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/Ponente!77
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix-staleness-check-by-digest"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found by the maintainer within an hour of #75 merging: dev "didn't move" after the merge.
It was correct behaviour, and the docs were wrong about how to tell. #75 changed only docs and deploy scripts, so the build context was unchanged,
build-and-pushfinished in 13 seconds off Docker's cache,:mainkept the same digest, and the updater compared and correctly did nothing.:main2a5011bc…2a5011bc…:latest0d7f1382…0d7f1382…Nothing was stale. But the release skill said "
ponente-dev-apprestarting minutes after the last merge is the signal. If it is hours old, either the Publish workflow failed or the timer did" — which sends you debugging a healthy system every time a merge is docs-only. That is a real defect in instructions written for agents who cannot see the stack.The fix
Uptime is a fact about the build cache. The question anyone actually means is whether the running image matches what the tag points at.
It compares the registry's digest for the tag against the container's, and needs no credentials — the registry serves the manifest to an anonymous token, which is the same reason the server can pull without a login.
It also reports a pin separately rather than as staleness. Production sitting on a version tag after a rollback is the other situation where somebody concludes the timer is broken, and it deserves to say so in its own words instead of failing.
Verified
0d7f1382==0d7f1382, "Up to date"2a5011bc==2a5011bc, "Up to date"IMAGE_TAGoff the server (ponente→latest,ponente-dev→main) rather than silently returning empty and skipping itselfDocs updated in three places that gave the uptime advice: Phase A step 2, Phase B step 4, the handover checklist, plus the Updating dev and troubleshooting sections of
deploy/README.md. The 13-secondbuild-and-pushis called out as the tell, since that is the artefact you actually see.🤖 Generated with Claude Code
🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
💬 Verdict: comment — notes only, nothing blocking.
The core fix (compare registry digest vs running image digest, instead of container uptime) is sound and well-motivated, and the docs updates consistently point at the new script everywhere the old uptime advice appeared. One robustness gap in the new pin-detection code path is worth fixing before/soon after merge, but it doesn't undermine the primary digest-comparison logic that the PR verified works.
⏱ 2m 25s · 11 turns · tokens: 66.6k in / 13.1k out (+828.0k cache-read)
📜 Full session transcript
@ -0,0 +67,4 @@# failing: production sitting on a version tag after a rollback is exactly the# situation where somebody is about to conclude the timer is broken.env_tag="$(ssh -o BatchMode=yes "podman@$( \podman system connection ls --format json 2>/dev/null \The pin check builds its own SSH target instead of reusing the connection-resolution logic in
prod-podman.sh(anddeploy/deploy.sh), and drops two things those scripts are careful about:podman@rather than reading it from the podman connection URI (asprod-podman.sh/deploy.shdo — deliberately leaving the user off when the URI doesn't specify one, so~/.ssh/configcan decide).-p $SSH_PORTentirely —prod-podman.shexplicitly extractsu.port or 22from the connection and passes-p "$SSH_PORT"to every ssh invocation, which only makes sense if a non-default port is a real possibility here.Because the whole
ssh ... || truepipeline is swallowed (2>/dev/null || true), a mismatch in either of these silently yields an emptyenv_tag, which the script then treats identically to "not pinned." That's the exact failure mode the PR's own "Verified" section says was checked ("rather than silently returning empty and skipping itself") — but it was only verified against whatever connection config happens to be in use in this environment, not against a differently-configured one. A production stack that's genuinely pinned after a rollback would then be reported asSTALEinstead ofPINNED, which is precisely the false alarm this PR sets out to eliminate on the uptime side.Worth reusing the same connection-parsing logic
prod-podman.shalready has (or factoring it out) rather than a second, less careful reimplementation.Fixed in
6186a83— the finding was right on all three counts, and the third was the important one.The parsing now lives in
scripts/lib/podman-connection.shand bothprod-podman.shandcheck-stack-image.shsource it, so the hardcodedpodman@and the missing-p $SSH_PORTare gone rather than fixed twice.deploy/deploy.shdeliberately keeps its own copy — it is the primary operational tool and has to work from a plain checkout with no skill directory beside it — and the library now says so, so the duplication reads as a decision instead of an oversight.Sharing the resolver would not have fixed the silent degradation, so that is handled separately. An unreachable host now prints a WARNING and reports the pin state as unknown, instead of falling through to "not pinned". Reaching the host but finding no
IMAGE_TAGis its own case. That was the part that would have turned a genuinely-pinned production stack into a STALE report.Two things beyond the finding:
catthe entire env file and discard it, putting every secret in it on the wire to answer a question about one key. It now greps the single line.PINNED to v2.3.0, with the updater independently agreeing (ponente-dev is pinned to v2.3.0; leaving it alone), then restored clean; a badPONENTE_CONNECTIONexits 1 loudly from both scripts instead of answering wrongly;prod-podman.shstill drives the host after the refactor.You were right that the original "Verified" claim only held for the connection config in front of me.
@claude-bot /review
🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
✅ Verdict: approve — no blocking issues found.
The pin-detection robustness gap I flagged in my previous pass is fixed: the SSH invocation for reading
IMAGE_TAGoff the server now goes through the sharedresolve_connection()in the newlib/podman-connection.sh(sourced by bothcheck-stack-image.shand the refactoredprod-podman.sh), using$SSH_TARGET/$SSH_PORTderived from the actual podman connection URI instead of a hardcodedpodman@user and a missing port. That was the exact failure mode that could have silently misreported a pinned production stack asSTALE. The extraction into a shared lib is a clean fix rather than a patch — it also removes the duplicated connection-parsing logic that used to live only inprod-podman.sh, and the comments in the new lib file explain why the duplication was a bug rather than tolerable drift. Docs updates are consistent throughout (skill, README, bundled-scripts list) and match the new script's behavior. No remaining issues.⏱ 0m 35s · 6 turns · tokens: 49.6k in / 2.6k out (+417.9k cache-read)
📜 Full session transcript