sync_repo_root: fail loud when a pull --autostash is left unrestored (silently reverts concurrent sessions' uncommitted work)
Highlight text on any card (body, plan, or an event) to anchor a comment, or leave a whole-task comment here. Mention @claude to summon a reply.
No comments yet.
Goal
Make sync_repo_root.py's pull --rebase=merges --autostash recovery fail LOUD when its autostash is not restored, so a concurrent session's uncommitted work at the shared repo root can never be silently reverted into an orphaned stash.
Problem
git pull --rebase=merges --autostash at the shared repo root stashes the working tree, rebases, and is supposed to pop the stash back. When the pop does not happen, the working tree is left at HEAD, the work survives only as an unlabelled autostash entry in git stash list, and NOTHING tells the session that owned those edits. The next thing that session does — re-render a figure, re-run a script — silently uses the reverted (HEAD) version.
Observed 2026-08-07 during a #2054 user-chat inline round:
- reflog
HEAD@{11:02:00} pull --rebase=merges --autostash origin main: Fast-forward - an uncommitted rewrite of
scripts/issue2054_framing_character_transfer_figs.pyreverted to its 08:05 committed version; the deletedframing_transfer_provenance.*triple came back - the subsequent re-render then ran the OLD script and regenerated the superseded figure — the failure was only caught because the output filenames were wrong
git stash listcurrently holds FOUR unpopped bareautostashentries, plus two hand-labelled rescues from prior incidents ("rescued autostash from corrupt rebase state", 2026-08-07; "rescued autostash from stale .git/rebase-merge husk", Jul 2). So this has already happened repeatedly and has been hand-recovered at least twice.
The repo root is shared across ~15 concurrent sessions, all of which pull frequently, so any session holding uncommitted edits for more than a few minutes is exposed.
Proposed fix (implementation is the session's call)
- In
scripts/sync_repo_root.py, after thepull --rebase=merges --autostash, comparegit stash listbefore/after. If a newautostashentry survived the pull, that is an UNRESTORED autostash: fail loud — print the stash ref, the file list (git stash show --name-only), and the exactgit stash pop <ref>recovery command; exit non-zero rather than reporting success. - Label the stash so it is attributable: pre-stash explicitly with a message naming the session/issue instead of relying on the bare
autostashlabel, so an orphan can be traced to its owner. - Add a startup/tick check that WARNs when bare
autostashentries are present (the four currently sitting there are unattributable — nobody knows whose work they hold). - Reconcile the existing four orphaned entries: inspect each, surface the diffs, and let the user decide drop-vs-restore. Do NOT drop them automatically.
Non-goal
Not proposing to stop using --autostash (it is the right default) and not proposing any repo-root reset --hard / restore path. The gap is purely the SILENT-success reporting.
Workaround in the meantime
Write the content to a scratch path, then install-and-commit atomically in ONE shell call (cp + git add + git commit --only -- <paths>), so no dirty window exists for a concurrent pull to swallow. This is what recovered the #2054 round.