feat(#2584): Phase 3 — scheduler consumer + isolation adapters (#2635)

Final phase of #2584 (ADR-1239 Codex-binding amendment). execute-phase now negotiates dispatch.isolation and dispatches through the matching adapter, so a wave's independent plans run concurrently on six runtimes instead of one — with no runtime=== branch in the scheduler.

harness-worktree passes the host's declared isolation flag (claude, cursor); orchestrator-worktree creates the worktree via the Phase-2 verb and spawns the executor into it with the resolved argv/cwd (codex, opencode, kimi, kimi-code); none stays sequential. Undeclared/unknown/unresolvable isolation degrades to none — never an unisolated parallel run.

Fixes two shipped Phase-2 descriptors that per-host research found would fail at spawn: kimi lacked its headless flag (would launch the interactive TUI and hang the orchestrator), and kimi-code named a non-existent binary (Kimi Code installs as 'kimi'). Adds the worktree-path root confinement Phase 2 deferred here, and leading-dash guards on the resolver's prompt/cwd matching the existing git-argument guard.

Closes #2627

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-07-25 01:50:20 -04:00
committed by GitHub
parent 461c744c31
commit 6ad30f74b6
62 changed files with 1105 additions and 205 deletions

View File

@@ -1182,7 +1182,12 @@ test('property: _stampNonClaudeRuntimeDefaults is idempotent (#1521)', () => {
test('execute-phase.md, quick.md, and diagnose-issues.md guards are generalized to != "claude" (not Codex-specific) (#1521)', () => {
// allow-test-rule: emitted workflow runtime-resolution shell block is the runtime contract surface (#1521)
const GUARD_WORKFLOWS = ['execute-phase.md', 'quick.md', 'diagnose-issues.md'];
// #2584 Phase 3 (#2627): execute-phase.md graduated PAST the `!= "claude"`
// guard — worktree isolation there is now keyed on the negotiated
// `dispatch.isolation` capability, so no runtime name appears in its guard at
// all. quick.md and diagnose-issues.md still use the #1521 generalized form
// (they do not negotiate isolation), so they keep asserting it.
const GUARD_WORKFLOWS = ['quick.md', 'diagnose-issues.md'];
for (const wf of GUARD_WORKFLOWS) {
const src = fs.readFileSync(
path.join(__dirname, '..', 'gsd-core', 'workflows', wf),
@@ -1197,6 +1202,20 @@ test('execute-phase.md, quick.md, and diagnose-issues.md guards are generalized
`${wf}: found Codex-specific guard — should have been generalized to != "claude"`,
);
}
// execute-phase.md: the guard must be capability-keyed, with NO runtime name.
const executePhase = fs.readFileSync(
path.join(__dirname, '..', 'gsd-core', 'workflows', 'execute-phase.md'),
'utf8',
);
assert.ok(
!/\[\s*"\$RUNTIME"\s*(?:!=|=)\s*"[a-z-]+"\s*\]\s*&&\s*\[\s*"\$USE_WORKTREES"/.test(executePhase),
'execute-phase.md: worktree isolation must branch on dispatch.isolation, not on a runtime name (#2584)',
);
assert.ok(
executePhase.includes('Resolve ISOLATION'),
'execute-phase.md: must resolve the negotiated ISOLATION capability',
);
});
// ---------------------------------------------------------------------------