.known-couplings/docker-image-base-vs-trigger-package.md
The base image of the published ponylang/ponyc:nightly and :release Docker images (FROM alpine:X in .dockerfiles/nightly/Dockerfile and .dockerfiles/release/Dockerfile) is coupled to two other places that must name the same Alpine version X: the if package-name gates in .github/workflows/build-nightly-image.yml and .github/workflows/build-release-image.yml (ponyc-*-unknown-linux-alpineX.tar.gz), and the dispatch names in the manual-recovery scripts .ci-scripts/misc/trigger-nightly-tasks.bash and .ci-scripts/misc/trigger-release-tasks.bash.
When a nightly/release alpineX package finishes syncing to Cloudsmith, Cloudsmith fires a cloudsmith-package-synchronised event; the workflow gate uses that specific alpineX package name as the sentinel that fires the image build. The image is then built FROM alpine:X, and ponyup inside the container detects the base's Alpine version and downloads the matching ponyc package. If the gate (or a manual dispatch) names a different Alpine version than the base, the build fires off a package that doesn't correspond to what ponyup will fetch: ponyup either can't find its package, or the build races ahead of the package it needs finishing its sync. This bit us before — PR #4804 moved the gate 3.21->3.23 but left the Dockerfiles at 3.21, and PR #4887 had to follow up to move the base; until then ponyup detected alpine3.21 and failed to find the package on Cloudsmith. The macOS/Windows gates in .ci-scripts/misc/trigger-nightly-tasks.bash and the release-matrix/builder references elsewhere (e.g. release.yml, nightlies.yml, .ci-dockerfiles/alpine3.23-builder/) are a separate concern — those track which Alpine platforms are supported, not which one the distributed images are based on, so they do not move with this coupling.
Run: no automated check catches a gate-vs-base version mismatch — it only surfaces during a real nightly/release image build. pr-docker-image-validation.yml (triggered by .dockerfiles/** changes) builds both Dockerfiles and runs ponyup, so it catches a base whose package isn't published, but it does not exercise the workflow gates or the trigger scripts. When bumping the base, move the workflow gates and the trigger-script dispatch names with it by hand.