Fix concurrent session resumes with clone-on-write branches - #698
Closed
yxlyx wants to merge 5 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>
The Linux debug executable crossed the 128 MiB learning-program ceiling after session branching was linked, causing the hosted zero-configuration bootstrap e2e to fail before it could pin the current binary. Keep the safety bound but raise it to 160 MiB so supported debug builds remain valid learning evaluators.\n\nCo-Authored-By: Codegraff <blackfloofie@codegraff.com>
Durable compaction handoffs name and ; substring matching interpreted their prefix as JavaScript and could inject an unrelated fifth model turn. Match source suffixes at a boundary while explicitly supporting JSX/TSX.\n\nAlso make the Codex compaction probe parse both chat strings and normalized Responses blocks, and wait for prompt-first startup settings before counting transport turns.\n\nCo-Authored-By: Codegraff <blackfloofie@codegraff.com>
Responses history may carry user content as either a chat string or normalized input_text blocks. Parse both forms so the compaction probe validates request meaning rather than racing normalization, and let prompt-first startup apply persisted auxiliary-call settings before transport counting begins. Co-Authored-By: Codegraff <blackfloofie@codegraff.com>
cursor Bot
pushed a commit
that referenced
this pull request
Aug 31, 2026
Debug learn-pin ceiling, source-nudge suffix boundaries, and Codex compaction wire parsing from the reopened session-branch head.
Owner
|
Folded into
Closing as superseded. ADR stays 0049 on 282. |
Owner
|
Closing as duplicate of #697, already folded onto #696 (v0.0.282, ADR 0049). Same head: clone-on-write |
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..session.json/.transcript.jsonlhandoffs from being mistaken for JavaScript by the named-source nudge, which had injected an unrelated post-compaction model turn.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 regressionpython3 tests/learn_bootstrap_e2e.py --graff zig-out/bin/graffscripts/eval-tier1.sh(1,754 unit tests passed, 1 skipped; 460/460 TUI tests; all 17 PTY guard probes; build/reachability/SDK/invariants green)