Fix concurrent session resumes with clone-on-write branches - #697
Closed
yxlyx wants to merge 2 commits into
Closed
Conversation
Concurrent resumes previously shared one durable session identity, so autosaves and shutdown writes could overwrite another continuation. Add clone-on-write resume targets across line, scripted, ACP, and fullscreen TUI paths, claim destination names atomically, and keep provider-native history plus session metadata attached to the selected branch.\n\nRecord the identity contract in ADR 0042 and cover source immutability, branch isolation, ownership stability, cache identity, and destination races with an offline process regression.\n\nCo-Authored-By: Codegraff <blackfloofie@codegraff.com>
Resolve the ADR-number collision by moving the session branching decision to ADR 0048, and retain both the restored scripted-REPL conversation sync and main's usage footer.\n\nCo-Authored-By: Codegraff <blackfloofie@codegraff.com>
Owner
|
Folded into release/v0.0.282 (#696). ADR remapped 0042 → 0049 (0042 is TUI claims). Closing as superseded. |
Collaborator
Author
|
Superseded because GitHub kept this PR pinned to the pre-fix SHA after its head branch was auto-deleted and recreated. Reopening against the current conflict-free head. |
cursor Bot
pushed a commit
that referenced
this pull request
Aug 31, 2026
yxlyx: --resume SOURCE --branch DEST across REPL/TUI/ACP. ADR number will be remapped off 0042 (TUI claims) to the next free slot. # Conflicts: # docs/adr/README.md # src/main.zig # src/session_run.zig
cursor Bot
pushed a commit
that referenced
this pull request
Aug 31, 2026
Record the ADR remaps (0049 / 0050) and the extra #694 lifecycle hardening. Still no tag.
cursor Bot
pushed a commit
that referenced
this pull request
Aug 31, 2026
…lose #697 added one Agent field and tripped the ceiling. Move the worker-line row test into agent_tests.zig. The grok-spec loopback was closing the listen socket while accept still ran (BADF); wake, await, then deinit.
cursor Bot
pushed a commit
that referenced
this pull request
Aug 31, 2026
Same SuperGrok seat, jobs=1. Graff stays unique vs grok and OpenCode on pass/wall/calls/tokens/list$/RSS. Calls still 52.
This was referenced Aug 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #689.
What changed
--resume SOURCE --branch DESTINATIONand/resume SOURCE --branch DESTINATIONacross the default line session, scripted/TTY REPL, fullscreen TUI, ACP startup, and one-shot runtime paths.Why
Problem / failure mode
Two processes resuming the same named session continued writing the same
.session.json, so autosaves and shutdown writes could silently replace one continuation with the other. The fullscreen TUI also did not start from the restored provider-native conversation or reliably return its final state to the root session, which made branching only the line REPL insufficient.Reason for this approach
Clone-on-write gives each continuation an explicit durable identity while preserving the source as a stable common ancestor. A filesystem-exclusive destination claim closes the check-then-create race, and sharing one restore implementation across frontends keeps branch ownership, goal/todo state, compaction, transcripts, and final saves consistent.
Constraints and trade-offs
Branches deliberately do not merge automatically: provider-native tool/reasoning envelopes and compaction boundaries cannot be safely combined by concatenating message arrays. Peer cursor/inbox state is copied once, while git worktree isolation remains a separate user choice. Existing plain
/resume SOURCEkeeps its same-tip compatibility behavior and therefore remains unsuitable for concurrent continuation.Rejected alternatives
A process-lifetime lock on the source would prevent corruption by rejecting the second user, but it would not support the requested concurrent work. Last-writer-wins merging was rejected because it preserves neither branch and can create invalid provider history.
Verification
python3 scripts/test-session-branching.py ./zig-out/bin/graff/resume SOURCE --branch DESTPTY regressionscripts/eval-tier1.sh(1,754 unit tests passed, 1 skipped; 460/460 TUI tests; all 17 PTY guard probes; build/reachability/SDK/invariants green)