release() pushes stale local source branch -> non-ff rejection blocks all deploys #3

Closed
opened 2026-07-10 20:36:04 +00:00 by kavi · 0 comments
Owner

Root cause of the 2026-07-10 muralla deploy blocker

release() (server.js ~L657-662) pushes the local source branch without first syncing it to origin:

await run(`git -C ${repoDir} fetch ${remote}`);   // updates remote-tracking only
await run(`git -C ${repoDir} checkout ${sourceBranch}`);
await run(`git -C ${repoDir} push ${remote} ${sourceBranch}`);  // local main may be BEHIND origin

When the engine clone (/root/apps/<app>) has a stale local main (behind origin/main — e.g. because merges happened via PRs on Forgejo, never in this clone), git push origin main is rejected non-fast-forward and release() 500s at push_source, blocking every deploy. This is exactly what stalled muralla for ~36 commits. (It was misdiagnosed in the handoff as a known_hosts perms issue; the real cause is the stale local ref.)

Fix

After fetch, fast-forward the local source branch to origin before pushing:

await run(`git -C ${repoDir} fetch ${remote}`);
await run(`git -C ${repoDir} checkout ${sourceBranch}`);
await run(`git -C ${repoDir} merge --ff-only ${remote}/${sourceBranch}`); // <-- add: no-op if ahead/equal, ff if behind, errors on true divergence
await run(`git -C ${repoDir} push ${remote} ${sourceBranch}`);

--ff-only is correct in all cases: behind → fast-forwards (push becomes no-op); ahead → no-op (push sends local commits); genuinely diverged → errors loudly (a real problem worth surfacing). Same guard belongs on the deploy_branch checkout path.

Notes

  • CROWN JEWEL: prepare a reviewed PR only; human merges + operates the control-plane rollout (P-ROLLOUT).
  • Workaround used on 2026-07-10: manually git -C /root/apps/muralla merge --ff-only origin/main before triggering /release. The deploy then succeeded end-to-end.
## Root cause of the 2026-07-10 muralla deploy blocker `release()` (server.js ~L657-662) pushes the **local** source branch without first syncing it to origin: ```js await run(`git -C ${repoDir} fetch ${remote}`); // updates remote-tracking only await run(`git -C ${repoDir} checkout ${sourceBranch}`); await run(`git -C ${repoDir} push ${remote} ${sourceBranch}`); // local main may be BEHIND origin ``` When the engine clone (`/root/apps/<app>`) has a **stale local `main`** (behind `origin/main` — e.g. because merges happened via PRs on Forgejo, never in this clone), `git push origin main` is rejected **non-fast-forward** and `release()` 500s at `push_source`, blocking every deploy. This is exactly what stalled muralla for ~36 commits. (It was misdiagnosed in the handoff as a `known_hosts` perms issue; the real cause is the stale local ref.) ## Fix After `fetch`, fast-forward the local source branch to origin before pushing: ```js await run(`git -C ${repoDir} fetch ${remote}`); await run(`git -C ${repoDir} checkout ${sourceBranch}`); await run(`git -C ${repoDir} merge --ff-only ${remote}/${sourceBranch}`); // <-- add: no-op if ahead/equal, ff if behind, errors on true divergence await run(`git -C ${repoDir} push ${remote} ${sourceBranch}`); ``` `--ff-only` is correct in all cases: behind → fast-forwards (push becomes no-op); ahead → no-op (push sends local commits); genuinely diverged → errors loudly (a real problem worth surfacing). Same guard belongs on the deploy_branch checkout path. ## Notes - CROWN JEWEL: prepare a reviewed PR only; human merges + operates the control-plane rollout (P-ROLLOUT). - Workaround used on 2026-07-10: manually `git -C /root/apps/muralla merge --ff-only origin/main` before triggering `/release`. The deploy then succeeded end-to-end.
kavi closed this issue 2026-07-12 07:20:37 +00:00
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#3
No description provided.