- ship: no interactive override of the untested-commit guard; the tag targets
the pinned commit the artifacts were built from (never the branch head); a
tagged-but-incomplete train is found and resumed instead of vanishing from
open-train detection; a fully shipped train reports as such
- start: a failed edge→rc advance fails the command loudly (both start and
the advance are idempotent) instead of opening a train against stale rc
- rc trigger: bootstraps the server's rc worktree on first use, so a host set
up before the rc branch existed can run its first RC build
- advance-channel: fast-ring packages are excluded from edge→rc (the stable
build replicated by parity is authoritative for rc — same filename, other
bytes); differing destination bytes abort instead of warn; a package whose
signature copy was interrupted gets its .sig restored on resume
- the release lock now also covers direct promote/update/clean/remove/sync
invocations, not just release/advance/upload-prebuilt
- helpers/paths.sh: validate_mirror/require_valid_mirror for the edge|rc|stable
set, and REPO_ROOT (OMARCHY_REPO_ROOT override) so a secondary checkout like
the rc branch worktree publishes into the same channel tree as the primary
- validate --mirror everywhere it previously accepted any string (sync-repo,
promote-build, update-repo, clean-repo, remove-package) and widen the
edge|stable checks in build, deploy, push-build, auto-release
- build/Dockerfile: rc builds compile against rc-mirror.omarchy.org
The dev packages are versioned off the quattro tip, so rebuilding the
same upstream commit yields the same filename. Promotion treated any
pre-existing filename as fatal, which wedged the release loop whenever a
run promoted but died before update-repo rebuilt the database: the stale
database kept advertising the older hash, so every later run rebuilt the
identical package and failed here again, retaining the state file each
time.
Compare the bytes instead. Identical packages are skipped and the run
continues, so the following update-repo step fixes the database and the
loop unsticks itself. Differing content under a published filename still
aborts. Signatures are judged by the package they sign, since gpg stamps
a timestamp into every signature and a re-signed package never matches.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>