The separate Gitea push webhook to Portainer fired in parallel with this build workflow on the same push event, so it could redeploy before the new image finished pushing — Portainer would then pull the still-current :latest tag and silently keep running old code. Removed that webhook; redeploy now only happens as this workflow's last step, after the image push actually completes.