Repository navigation
lanes-edit.sh: the RECOVERY "re-run lanes-edit.sh commit" cannot publish an edit that is already committed — on a clean tree commit returns before the push #194
Description
What happens
commit_push can't push when a peer's uncommitted file blocks pull --rebase (the dirty_elsewhere branch). After six attempts it exits 3 and prints this (lanes-edit.sh:2087-2090 at f87fd5a6):
RECOVERY: their author commits those files (a handoff: handoff(<lane>@<workstation>): <what>),
then re-run: LANES_LANE=<lane> lanes-edit.sh commit "<what you wrote>" — your edit is already
a local commit here: git -C $LANES_REPO log --oneline origin/$LANES_BRANCH..HEAD
could not push origin/main: behind the remote, and a peer's uncommitted file blocks the rebase. Nothing was lost — your commit is local.
refuse_dirty_checkout gives the same advice at :1800-1801.
The re-run can't publish anything. The edit is already a local commit, so once the peer commits its file the register is clean. commit → commit_push then stages nothing and returns 0 before it reaches the push loop (:2022-2025):
if git -C "$LANES_REPO" -c "$CP_EXACT" diff --cached --quiet -- "${CP_PATHS[@]}"; then
note "nothing staged for ${CP_PATHS[*]} — no commit made"
return 0
fiSo the printed recovery exits 0 and pushes nothing. The stranded commit stays local until some later write from that checkout happens to carry it: the dangling commit the comment block at :2120-2148 describes. (This was established by reading the code at f87fd5a6, not by running the re-run. With a clean register the path is unambiguous.)
Observed, 2026-10-09 (lane opsXfactory-3, Eagle)
After an account swap, lane-start wrote five lanes' stamps into the shared runtime kit /workspace/projects/brett-wip-runtime-opsxfactory-team03a-20261008.
- What was stranded. Lane opsXfactory-3's handoff stamp
f680442fcand its row-state commitd51123aa2stayed local, along with two other lanes' stamps. Two peers' unstaged handoff stamps blocked them, and the helper printed the RECOVERY above. - The peers' part. One peer committed its file in the kit (
2e1e79e11). The other restored its own path and published from a private clone. That left the kit clean, so the printed re-run would have been a no-op. - The next real write would have failed too.
d51123aa2changes lane opsXfactory-3's row (lanes/LANES.md:123). Meanwhile origin had changed the ADJACENT row, lane opsXfactory-1's (:124), and git merges edits to adjacent lines as one conflict. A dry-run rebase in a private clone confirmedCONFLICT (content): Merge conflict in lanes/LANES.mdond51123aa2. - The conflict recovery would have lost a peer's work. The recovery printed for that conflict (
:2149-2157) ends ingit reset --hard origin/$LANES_BRANCH. In the shared kit that would also have dropped the peer's unpushed2e1e79e11: its content was not on origin, andgit cherryprinted+for it. - What published it. Brett Heap's word was: "Do not reset, stash, or overwrite peer work."
- Take the helper's own lock (
mkdir lanes/.lanes-edit.lockplus a pid file). git rebase --no-autostash origin/main.- At the stop on the lane's own row commit:
git checkout --ours -- lanes/LANES.md, then re-apply only that row's exact old→new line (refused unless upstream still held the old line), thengit rebase --continue. - Release the lock, then make one real helper write (
log NOTED). Itspull --rebaseand push carried the queue.
- Take the helper's own lock (
- Result on brett-wip origin:
63a64ac7f,90cc4a61b, the peer's11ed5e874and NOTED1dbd72f65, one copy each. The two stamps already on origin dropped out, one by patch-id and one as empty.
Proposed remedy
- Make the recovery real. Preferred: when nothing is staged but
origin/$LANES_BRANCH..HEADis non-empty,commit(or a newpublishsubcommand) goes on to the push loop. That keeps the lock, the dirty-elsewhere guard and the retries. At minimum, change both RECOVERY texts to name a command that actually pushes. - Row-edit conflicts. Suppose the rebase stops on a commit whose only
LANES.mdchange is one row, and the conflict is with a different row's edit. The resolution is then mechanical: take upstream and re-apply that one old→new row line, refusing if upstream's copy of the row is no longer the old line. That is the row analogue of lanes-edit.sh: the Rule 6 line is appended at the end of LANES.md, so two lanes writing at once conflict on rebase and the lander must run the four-step RECOVERY by hand — resolve an append-only conflict as the union #145's append-only union. - At minimum, warn. The conflict RECOVERY should say that
reset --harddrops every unpushed local commit in the checkout, including peers' commits in a shared kit. It should also rungit cherryfor each such commit, not only the caller's own.
Related: #145 (append-only Rule 6 lines conflicting on rebase) and #127 (the direct-push path when another tracked file is dirty).
Lane: opsXfactory-3
Activity
brettheap commentedon Oct 11, 2026
CLAIMED — lane openRepoTools-4, session e545e636-93fd-4b80-81b1-48177346b887@Eagle, 2026-10-11T16:30:29Z, for #194
Logged in
lanes/log/openRepoTools-4.mdat5a6a3758e44f64799b7d9a246e14c8be1ab9d9af.The three reads (lane-collision-protocol Rule 1):
commit_push publishes the local commits a write with nothing staged f…
Exit-code tables: say the #194 refusal pushes none of them, not "noth…
#194: a publish the pull empties exits 0 and says so; pin the fence's…
brettheap commentedon Oct 19, 2026
RELEASED — lane openRepoTools-4, session e545e636-93fd-4b80-81b1-48177346b887@Eagle, 2026-10-19T11:59:04Z, for #194 — #194 is closed by PR #214 (9b94a59); lane 4's claim ends
The read-back that stops a doubled log line has a case: a push git ca…
The publish act's refusal over a stack origin has moved past fills th…
S3's list and reset recoveries and the publish act's list line name `…