Sync handoff + state across machines via refs/cdd/<branch>#53
Merged
Conversation
The handoff (<branch>.md) and state record (<branch>.state.json) were out-of-tree, per-user files stranded on the machine that created them. cdd-worktree-resume recreated only the code branch. Carry the two files across machines through a per-task git ref. - cdd-state (seed + set): bundle whichever of the two files exist into a git tree under stable in-tree names (handoff.md/state.json), wrap it in a parentless commit, and force-push to refs/cdd/<branch> on origin. Plumbing only (hash-object/mktree/commit-tree) so the live worktree is never touched; fixed cdd/cdd@local identity so it never depends on user git config. Sits under the existing jq guard. Advisory/best-effort: any failure warns and returns 0, never failing the state write. - cdd-worktree-resume: before it finishes, fetch refs/cdd/<branch> and materialize both files into ~/.cdd/handoffs/<repo>/. Handoff is immutable so it is written only when locally absent; state follows most-advanced-stage-wins (compare .stage enum indices), falling back to write-only-if-absent without jq. Byte-exact extraction. No ref -> resumes exactly as before, with an honest message. - cdd-worktree-done: best-effort delete of refs/cdd/<branch> on origin when it deletes the branch, so the namespace does not accumulate. No slash-command changes (the push funnels through cdd-state). New smoke scripts/ref-sync-assert.sh covers the round-trip, byte-for-byte materialize, both directions of the heuristic, and the no-ref path; wired into CI and CLAUDE.md. Process doc SS2.8/SS2.13, shell-helpers.md, roadmap, and README updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-task ref sync leaves cdd-worktree-done as the only reaper of the handoff, state record, and refs/cdd/<branch>, so they leak when done never runs, its ref delete fails offline, or a multi-machine resume leaves materialized copies on every machine but the one where done ran. cdd-worktree-gc [--force] sweeps them, reaping ONLY tasks whose PR has merged — a merged PR is the sole trustworthy "done" signal, since a scoped-but-unstarted task's handoff and ref exist before its branch does and so can't be told apart by branch/ref presence. Enumerates local handoffs plus refs/cdd/* so any machine can reap leaked refs and its own orphaned locals; dry-run unless --force; needs gh for PR state. scripts/gc-assert.sh (stubbed gh, local bare origin) + CI step; process doc §2.8, shell-helpers.md, roadmap, README, CLAUDE.md reconciled. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
Completes multi-machine resume (issue #22): the handoff (
<branch>.md) and state record (<branch>.state.json) now sync across machines via a per-task refrefs/cdd/<branch>onorigin.cdd-state, onseed/set): bundles the two files into a git tree (stable in-tree nameshandoff.md/state.json), wraps it in a parentless commit under a fixedcdd/cdd@localidentity, and force-pushes (latest-wins). Plumbing only — never touches the index or working tree. No slash-command changes: the push funnels through the state helper.cdd-worktree-resume, before it finishes): fetches the ref and materializes both files into~/.cdd/handoffs/<repo>/. Handoff is immutable after seed (written only when absent locally); state record follows most-advanced-stage-wins.cdd-worktree-done): best-effort deletes the remote ref when the branch is deleted.origin/ offline / missingjq/ no ref all warn-and-continue, so a resume with no ref behaves exactly as before.git noteswas rejected because it anchors metadata to a commit and must chase the moving branch tip; the branch-keyed ref does not.Testing
scripts/ref-sync-assert.sh(wired intotemplate-smoke.yml) drives a local bareoriginwith two separate-$HOMEclones as machines A/B and asserts: push on seed/set, byte-for-byte handoff materialize + advanced state, most-advanced-wins in both directions, immutable-handoff preservation, and the clean no-ref path — with a stubbedclaudeguarding it is never launched.Docs
Process doc §2.8/§2.13,
doc/architecture/shell-helpers.md(new "Task-ref sync" section), README, CLAUDE.md build section, and roadmap all reconciled.Closes #22
🤖 Generated with Claude Code