release(): add per-app mutex — concurrent releases can interleave on the shared engine clone #8

Open
opened 2026-07-11 09:52:35 +00:00 by kavi · 0 comments
Owner

Found by the two-lineage crown-jewel review (Fable + Terra), 2026-07-11. Pre-existing gap, not introduced by #4 — so it does not block #4, but both reviewers want it as a fast-follow.

Problem

release() runs on a single shared engine clone on sol-prod and does fetch → checkout <source> → merge/push → checkout <deploy> → merge --ff-only → push. There is no per-app mutex around this sequence. Two release-app <same-app> invocations (or a release racing coordinator-tick) can interleave their checkouts/merges on the one working tree and corrupt branch state or push a wrong tree.

The --ff-only fix in #4 makes a bad push fail loudly instead of silently, which narrows the blast radius — but it does not serialize concurrent releases.

Fix

Wrap the per-app critical section of release() in a per-app advisory lock (e.g. flock on /tmp/kua-deploy-release-<app>.lock, or an in-process async mutex keyed by app). Second concurrent release for the same app should queue or fail fast with a clear "release already in progress" error, never interleave. Different apps may still release in parallel.

Acceptance

  • Two concurrent release() calls for the same app serialize (second waits or errors clearly); a test proves no interleaving.
  • Two calls for different apps still run concurrently.
  • Prepared as a reviewed PR only — crown-jewel repo, human merges + operates rollout.
**Found by the two-lineage crown-jewel review (Fable + Terra), 2026-07-11.** Pre-existing gap, *not* introduced by #4 — so it does not block #4, but both reviewers want it as a fast-follow. ## Problem `release()` runs on a **single shared engine clone** on sol-prod and does `fetch → checkout <source> → merge/push → checkout <deploy> → merge --ff-only → push`. There is **no per-app mutex** around this sequence. Two `release-app <same-app>` invocations (or a release racing coordinator-tick) can interleave their checkouts/merges on the one working tree and corrupt branch state or push a wrong tree. The `--ff-only` fix in #4 makes a *bad* push fail loudly instead of silently, which narrows the blast radius — but it does not serialize concurrent releases. ## Fix Wrap the per-app critical section of `release()` in a **per-app advisory lock** (e.g. `flock` on `/tmp/kua-deploy-release-<app>.lock`, or an in-process async mutex keyed by app). Second concurrent release for the same app should **queue or fail fast with a clear "release already in progress" error**, never interleave. Different apps may still release in parallel. ## Acceptance - Two concurrent `release()` calls for the *same* app serialize (second waits or errors clearly); a test proves no interleaving. - Two calls for *different* apps still run concurrently. - Prepared as a **reviewed PR only** — crown-jewel repo, human merges + operates rollout.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kavi/kua-deploy#8
No description provided.