dispatch: two isolation modes - main vs worktree+branch - invert the surface-to-isolation mapping #145
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
dispatch: two isolation modes (main / worktree+branch), invert the surface->isolation mapping
Builds on
coilysiren/coily#270 (surface split), coilysiren/coily#144 (consult as 4th positional surface). This issue is orthogonal to #144 - it changes isolation, not the surface set - but the two interact (see "Interaction with #144").
Today
Only the
interactivesurface uses a git worktree (cli-guard dispatch/interactive.go, one worktree per issue at<WorktreeRoot>/<repo>/issue-<N>on branchdispatch/issue-<N>, reaped on merge). The detached surfacesheadlessandcascadeshare the canonical checkout (runDetached->repoPath,dispatch/dispatch.go).Problem
That mapping is backwards on the axis that actually matters, which is concurrency, not churn velocity. Two
claude -pprocesses sharing one working tree and index corrupt each other: index locks, half-applied edits, branch thrash. The surfaces most likely to run multiple concurrent workers in the same repo are exactly the detached ones:cascadefans out into multiple concurrent sub-workers, and a migration lands several in one repo at once. Worst case for a shared checkout, and today it runs them all in the bare tree. Latent correctness bug, not just churn.headlesscan be fanned out in parallel ("open one for me" x5); today they race inrepoPath.interactive/consultare paced by operator attention - effectively serial, and a double-dispatch is human-noticeable.Model
The isolation design space is a 2x2 (branch axis x worktree axis), but only two cells are coherent:
The other two cells are dead: non-default-branch-without-worktree pays branch ceremony for no isolation benefit, and worktree-on-the-default-branch is something git forbids (a branch cannot be checked out in two worktrees at once).
Change
Invert the surface -> isolation mapping along the fast/slow (concurrency) line:
interactive,consult(supervised, serial, trusted) -> main. Drop the worktree and the auto-merge dance these do today. Supervised work is what-you-see-is-what-ships.headless,cascade(detached, parallel, lights-out) -> worktree + branch. Each worker gets its own isolated dir, so concurrent workers in one repo stop racing.Landing policy is a separate knob
Auto-merge-when-green vs hold-as-a-PR is NOT a third isolation mode. Once a run is on its own branch, what happens to that branch (fast-forward to main, or sit as a PR for review) is a per-surface policy decision that rides on top of "worktree + branch." Keep it independent: e.g. cascade leaves can auto-land their slice while headless can hold a PR, without that distinction leaking back into the isolation question. Settle the per-surface landing policy as part of this work but do not model it as a worktree mode.
Open questions
main-mode surfaces: an abandoned half-done supervised session leavesmaindirty. Acceptable (operator is watching), or does main-mode still want an in-place branch? Lean: acceptable, operator is right there.interactive/consultinto a repo that already has a live dispatch session, since main-mode has no isolation to fall back on.Implementation surface
dispatch/: move worktree resolution offinteractiveand onto the detached path;runDetached(dispatch.go) gains worktree placement,interactive.goloses it (or routes throughmain). Reaping (reap.go) follows the detached surfaces. Tests acrossinteractive_test.go,cascade_test.go.Acceptance
coily dispatch headless/cascaderun in a per-issue worktree+branch; two concurrent headless dispatches into one repo do not share a working tree.coily dispatch interactive/consultrun directly in the canonical checkout on the default branch, no worktree created.dispatch: two isolation modes main / worktree+branch , invert surface- isolation mappingto dispatch: two isolation modes - main vs worktree+branch - invert the surface-to-isolation mappingLanded on GitHub
mainasf6e9ba5(consumer bump) + cli-guard02f4153/ cli-guard#35 (the dispatch logic).The surface-to-isolation mapping is now inverted:
headless,cascade(detached, parallel) run in a per-issue git worktree+branch and land by merging intomainwhen green - concurrent workers in one repo no longer share a working tree/index.interactive,consult(supervised, serial) run directly on the default branch in the canonical checkout - no worktree, no auto-merge dance.Landing policy: detached workers merge their branch into main when green; supervised work commits to main directly.
--no-worktreeis dropped (main mode is the only interactive placement).All acceptance criteria met; cli-guard + coily tests, vet, lint, and pre-commit hooks green.
Closing manually rather than via the commit trailer: the coily GitHub and Forgejo remotes have forked (Forgejo has ~8 commits of work GitHub lacks - fj alias, forgejo actions-log reader, formula v2.45/2.46 bumps, lockdown syncs - and GitHub has the consult surface + this work), so the
closes #145trailer pushed to GitHub never reached this Forgejo issue. Mirror divergence filed as a follow-up; it needs human reconciliation and was out of scope to fix from a dispatch worker without force-pushing.