`docker login` was refused with a bare `unauthorized`. The root cause is not a typo in the credentials but a difference in what a Gitea package is: it belongs to a user or org **owner**, not to a repository, so the ephemeral repo-scoped Actions token carries no authority over it and the registry rejects it outright. GHCR accepted GITHUB_TOKEN and GitLab issues working per-job credentials in $CI_REGISTRY_PASSWORD; Gitea deliberately does neither, so this needs a real access token with the package scope, supplied as REGISTRY_TOKEN. The username moves from github.actor to github.repository_owner for the same reason. The image is pushed into the owner's namespace and the token belongs to that owner, while actor is merely whoever triggered the run — a different person on a dispatch, the wrong account on a fork. Added a preflight check on the secret, because the failure it replaces said nothing about what to do. It also settles a question the evidence left open: the reports of this problem describe login succeeding and the *push* failing, while ours failed at login, which is consistent with the token being rejected but equally with its never having been set. The check distinguishes the two the next time it happens. No test pins this. The three workflow assertions in test/refresh.test.ts exist because those defects are silent; this one turns CI red on the spot, which is the condition that made them worth writing. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>