Repository navigation
on OpenCode, execute-phase runs parallel-wave executors unisolated in the project root, and nothing fails closed #5259
Description
Activity
- addedneeds-triageNew issue awaiting maintainer reviewNew issue awaiting maintainer review
on Oct 8, 2026 This was generated by AI during triage.
Diagnosis
Reproduced: partially, in-repo. The OpenCode session evidence (
docs/smoke/runs/...) is reporter-supplied and not in this repo, so the interleaved-commit incident itself is not independently reproduced. What was verified here:dispatch-isolation --jsonon opencode returnsorchestrator-worktree; nogsd-toolsverb both creates the worktree and spawns the executor (worktree.createonly runsgit worktree addand records the manifest; the spawn is a bash block the orchestrating model must run); no code path refuses an executor commit outside a per-agent worktree.
Root cause: theorchestrator-worktreefan-out is enforced only by the model following prose, ingsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md:~295-355(orchestrator-worktree section). The fail-closed logic at the top of that file only coversnone/unresolved verdicts, not a model dispatching through the hosttasktool.<worktree_branch_check>(gsd-core/references/worktree-branch-check.md, embedded atgsd-core/workflows/execute-phase.md:667) is prompt text the executor must choose to run, and is dropped from the orchestrator-spawn prompt. The #3045 isolation guard does not run on OpenCode (capabilities/opencode/capability.json:84hooksSurface:"none"; hook bridge.opencode/plugins/gsd-core.js:264is the open confirmed-bug #4849) and keys onharness-worktree. This is a documented contract, not a declared gap:gsd-core/references/dispatch-isolation-gate.md:66anddocs/CONFIGURATION.md:574state GSD creates the worktree and spawns each executor, with fail-closed as "the invariant".
Introduced by: long-standing; orchestrator-worktree backend landed in 6ad30f7 (2026-07-25, #2635).
Blast radius: High. Every orchestrator-worktree runtime (codex, opencode, kimi, kimi-code) at execute-phase wave dispatch; interleaved commits,index.lockcontention, empty commits.
Coupled (must not miss): #5260, #5254, #4849, #3045 (closed), PR #4964, PR #5126; testsexecutor-isolation-prompt-contract,gsd-agent-isolation-guard,worktree-base-ref.
Regression test: on an orchestrator-worktree runtime, an executor running in the project root on the default branch during a parallel-eligible wave is refused at commit (no commit created), and a second executor is not started on a shared tree.Agent Brief
Category: bug
Summary: On orchestrator-worktree runtimes, a wave dispatched without per-agent worktrees runs unisolated instead of failing closed.
Current behavior: The isolation verdict is reported, but creating worktrees and spawning executors depends on the orchestrating model following instructions. If it dispatches via the host subagent tool, parallel executors share the project root and commit on the default branch; nothing refuses, and the phase continues.
Desired behavior: Isolation for these runtimes is enforced by GSD, not by model compliance. A wave never runs parallel executors on a shared tree: an executor outside a per-agent worktree is refused before it can commit, and where isolation cannot be established the wave degrades to sequential or halts with a clear message.
Key interfaces:dispatch-isolationverdict for orchestrator-worktree runtimes; execute-phase wave dispatch; the executor's branch/worktree check; worktree create/record verbs.
Acceptance criteria:- An executor started in the project root on the default branch during a parallel-eligible wave on an orchestrator-worktree runtime creates no commit and exits non-zero with a message naming the isolation violation.
- A wave on such a runtime where per-agent worktrees were not created does not run two executors concurrently on one tree.
- The enforcement does not depend on hook execution (works when hooks do not run on the host).
- Behavior on harness-worktree runtimes and with
use_worktrees=falseis unchanged.
Out of scope: fixing the OpenCode hook bridge (fix(plugin): opencode hook bridge spawns process.execPath — hooks silently no-op and leak ~14MB to /tmp per spawn #4849), OpenCode--modelargv (the OpenCode orchestrator-worktree argv carries no--model, so worktree executors run on the session model #5260), the sentinel overwrite (bug(isolation-guard): write-on-read overwrites the forced dispatch-isolation sentinel (v1.16.0 variant of #3737) #5254), and the documented sequential degrade for subagent-tool-only sites (quick, diagnose-issues).
- addedbugSomething isn't workingSomething isn't workingconfirmed-bugVerified reproducible bugVerified reproducible bugand removedneeds-triageNew issue awaiting maintainer reviewNew issue awaiting maintainer review
on Oct 9, 2026
G-02)
--opencode --global), OpenCode 1.18.35, Linux; brain modelmistral-large-latest, executor model mistral-small-latest
Summary
On OpenCode,
gsd-tools query dispatch-isolation --jsonreportsorchestrator-worktree: theorchestrator should create a git worktree per plan and start each executor as its own
opencode run --dir <wt> ...process. In both smoke runs that never happened. The orchestratingmodel skipped the isolation gate and dispatched
gsd-executorthrough OpenCode'stasktool, sothe executors ran as subagents in the project root. In the TUI run the two executors of one wave
overlapped for about four minutes on one working tree. Both removed
.git/index.lockto get pasteach other, and the first plan's commit picked up the second plan's files, leaving the second
plan's commit empty. The executor prompt carried
<worktree_branch_check>, which should stop anexecutor that is not on a per-agent branch. Both executors still committed on
master. On ClaudeCode the
PreToolUseisolation guard (#3045) would catch a mismatched dispatch, but on OpenCodethe hook bridge does not run hook scripts (#4849), so no guard enforced it.
Minimal repro
parallelization: true.--opencode --global; any non-Claude model as session model./gsd-execute-phase 1.git worktree liststays at one entry, no session runs under.claude/worktrees/, and bothplans' commits land on the current branch, interleaved.
Expected
Either the wave runs in orchestrator worktrees as
dispatch-isolationreports, or GSD fails closed:an executor that finds itself outside a per-agent worktree on a runtime whose isolation is
orchestrator-worktreerefuses to commit, and execute-phase does not start a second executor on ashared tree.
Actual
Executors run in parallel on the shared tree and mix their commits; the phase continues.
Suggested fix
example as one
gsd-toolsverb that creates the worktree and spawns the process.<worktree_branch_check>ingsd-tools(a commit verb that refuses on the wrong branch)instead of only in prompt text.
sequential execution rather than unguarded parallel execution.
Cowright workaround
None yet. The sandbox evidence is kept; the gap is pilot-critical for Cowright (D-15).
Evidence
docs/smoke/runs/2026-10-07/tui.json(items[execute-phase].second_try)docs/smoke/runs/2026-10-07/headless.json(steps[execute-phase]: the task-tool executor'sexternal_directoryask was auto-rejected)docs/smoke/runs/2026-10-07/evidence.json(d13.worktree_dispatch,d13.parallel_wave)