Skip to content

on OpenCode, execute-phase runs parallel-wave executors unisolated in the project root, and nothing fails closed #5259

Description

@stiefenm
  • Found: 2026-10-08, Cowright Plan 01-06 smoke (headless and TUI), triaged in Plan 01-07 (gaps G-01,
    G-02)
  • Environment: GSD Core 1.16.0 (--opencode --global), OpenCode 1.18.35, Linux; brain model
    mistral-large-latest, executor model mistral-small-latest

Summary

On OpenCode, gsd-tools query dispatch-isolation --json reports orchestrator-worktree: the
orchestrator 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 orchestrating
model skipped the isolation gate and dispatched gsd-executor through OpenCode's task tool, so
the 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.lock to get past
each 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 an
executor that is not on a per-agent branch. Both executors still committed on master. On Claude
Code the PreToolUse isolation guard (#3045) would catch a mismatched dispatch, but on OpenCode
the hook bridge does not run hook scripts (#4849), so no guard enforced it.

Minimal repro

  1. A project with one phase holding two independent plans in wave 1, parallelization: true.
  2. GSD Core 1.16.0 installed with --opencode --global; any non-Claude model as session model.
  3. In the OpenCode TUI: /gsd-execute-phase 1.
  4. git worktree list stays at one entry, no session runs under .claude/worktrees/, and both
    plans' commits land on the current branch, interleaved.

Expected

Either the wave runs in orchestrator worktrees as dispatch-isolation reports, or GSD fails closed:
an executor that finds itself outside a per-agent worktree on a runtime whose isolation is
orchestrator-worktree refuses to commit, and execute-phase does not start a second executor on a
shared tree.

Actual

Executors run in parallel on the shared tree and mix their commits; the phase continues.

Suggested fix

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's
    external_directory ask was auto-rejected)
  • docs/smoke/runs/2026-10-07/evidence.json (d13.worktree_dispatch, d13.parallel_wave)

Activity

  1. trek-e commented on Oct 9, 2026

    @trek-e
    Collaborator

    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 --json on opencode returns orchestrator-worktree; no gsd-tools verb both creates the worktree and spawns the executor (worktree.create only runs git worktree add and 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: the orchestrator-worktree fan-out is enforced only by the model following prose, in gsd-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 covers none/unresolved verdicts, not a model dispatching through the host task tool. <worktree_branch_check> (gsd-core/references/worktree-branch-check.md, embedded at gsd-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:84 hooksSurface:"none"; hook bridge .opencode/plugins/gsd-core.js:264 is the open confirmed-bug #4849) and keys on harness-worktree. This is a documented contract, not a declared gap: gsd-core/references/dispatch-isolation-gate.md:66 and docs/CONFIGURATION.md:574 state 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.lock contention, empty commits.
    Coupled (must not miss): #5260, #5254, #4849, #3045 (closed), PR #4964, PR #5126; tests executor-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.

  2. trek-e commented on Oct 9, 2026

    @trek-e
    Collaborator

    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-isolation verdict for orchestrator-worktree runtimes; execute-phase wave dispatch; the executor's branch/worktree check; worktree create/record verbs.
    Acceptance criteria:

  3. added
    bugSomething isn't working
    and removed
    needs-triageNew issue awaiting maintainer review
    on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingconfirmed-bugVerified reproducible bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions