The claude-orchestration capability (#1143) shipped registered 'active' but fully inert: detectWorkflowBackend/emitWorkflowScript had no caller outside their own CLI router, and execute-phase.md declared an execute:wave:pre hook point that the workflow body never rendered — so claude_orchestration.enabled:true had zero effect on real runs. Approach B (maintainer-chosen): - execute-phase.md now renders the execute:wave:pre hook (gsd_run loop render-hooks execute:wave:pre) at a new step 2.75, immediately before each wave's Agent() dispatch — fixing the latent dead-hook gap for any pre-wave capability. - Move the claude-orchestration contribution execute:wave:post -> execute:wave:pre (a pre-wave backend selector belongs before dispatch, not after); rename fragments/execute-wave-post.md -> execute-wave-pre.md with prose instructing the orchestrator to call resolve-wave-dispatch before step 3. Unrelated wave:post contributions (ui.safety-gate, drift, external-job, mempalace) untouched. - New .cts seam resolveWaveDispatch(input) composes detectWorkflowBackend + emitWorkflowScript into one {backend:'inline'|'workflow', ...} result; exposed as gsd-tools claude-orchestration resolve-wave-dispatch. This is a real non-CLI-router, non-test caller of both functions. Fail-closed: any gate miss (disabled, non-Claude runtime, Workflow tool absent, SDK below floor, execution_backend:inline, malformed input) or an emit failure resolves to inline with a byte-identical result shape — no regression to the default-off execute-phase path. Regression tests (tests/fix-2285-*) cover happy-path activation + SDK-floor BVA, the fail-closed gate-miss table with detectWorkflowBackend parity, a fast-check composition property, capability.json contribution assertions, and a source-contract guard that execute:wave:pre is now actually rendered. Dependent registry-shape assertions updated in-scope. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,9 +34,13 @@ gate. It is blocked-on-nothing now that the ADR-857 capability system is release
|
||||
- **`role: feature`**, `runtimeCompat.supported: ["claude"]`, `tier: full`.
|
||||
- **`activationKey: claude_orchestration.enabled`** — default `false`. Nothing
|
||||
changes until you opt in.
|
||||
- Registers at two **wired** loop points: `execute:wave:post` (into the executor)
|
||||
- Registers at two **wired** loop points: `execute:wave:pre` (into the executor)
|
||||
and `plan:post` (into the planner). Both are `onError: skip` and gated by the
|
||||
`enabled` key.
|
||||
`enabled` key. The dispatch-backend selector fires at `execute:wave:pre` — the
|
||||
seam that runs immediately BEFORE a wave's agents are dispatched — because a
|
||||
selector fired *after* a wave already dispatched inline (the original
|
||||
`execute:wave:post` placement, [#2285]) is structurally too late to change how
|
||||
dispatch happens.
|
||||
|
||||
## How it decides whether to activate
|
||||
|
||||
@@ -62,14 +66,19 @@ Workflow backend activates only when *every* gate passes; any miss degrades to
|
||||
| GSD concept | Workflow primitive |
|
||||
|---|---|
|
||||
| Wave | `parallel()` stage barrier |
|
||||
| Plan | `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })` |
|
||||
| Plan (`use_worktree` not `false`) | `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })` |
|
||||
| Plan (`use_worktree: false`) | `agent(brief, { agentType: 'gsd-executor' })` (no isolation) |
|
||||
| `files_modified` overlap | forces the plans into separate sequential stages |
|
||||
| Phase run id | `resumeFromRunId("<id>")` |
|
||||
| Phase token cap | `budget(<tokens>)` |
|
||||
|
||||
Because the emitted script composes the **same** `gsd-executor` agent and
|
||||
**worktree isolation** the inline path uses, it produces the same `SUMMARY.md`
|
||||
artifacts and commits — the only difference is the execution vehicle.
|
||||
Because the emitted script composes the **same** `gsd-executor` agent the
|
||||
inline path uses, with worktree isolation applied **per plan** from the
|
||||
manifest's `use_worktree` field, it produces the same `SUMMARY.md` artifacts
|
||||
and commits — the only difference is the execution vehicle. `use_worktree`
|
||||
mirrors execute-phase.md step 2.5's per-plan submodule safety gate exactly: a
|
||||
plan that touches a submodule path is never forced into worktree isolation,
|
||||
whichever backend dispatches it ([#2772]).
|
||||
|
||||
## The fallback contract
|
||||
|
||||
@@ -92,3 +101,5 @@ own runtime gate continues to no-op on non-Claude runtimes.
|
||||
|
||||
[#853]: https://github.com/open-gsd/gsd-core/issues/853
|
||||
[#1143]: https://github.com/open-gsd/gsd-core/issues/1143
|
||||
[#2772]: https://github.com/open-gsd/gsd-core/issues/2772
|
||||
[#2285]: https://github.com/open-gsd/gsd-core/issues/2285
|
||||
|
||||
@@ -55,7 +55,7 @@ points.
|
||||
| `ai-integration` | feature | full | `>=1.6.0` | `plan:pre`, `verify:pre` | step, contribution, gate | first-party |
|
||||
| `assumption-delta` | feature | full | `>=1.6.0` | `plan:pre` | contribution | first-party |
|
||||
| `audit` | feature | full | `>=1.6.0` | — | — | first-party |
|
||||
| `claude-orchestration` | feature | full | `>=1.7.0` | `plan:post`, `execute:wave:post` | contribution | first-party |
|
||||
| `claude-orchestration` | feature | full | `>=1.7.0` | `plan:post`, `execute:wave:pre` | contribution | first-party |
|
||||
| `code-review` | feature | full | `>=1.6.0` | `execute:post` | step | first-party |
|
||||
| `drift` | feature | full | `>=1.6.0` | `plan:pre`, `execute:wave:post` | gate | first-party |
|
||||
| `external-job` | feature | full | `>=1.7.0` | `plan:post`, `execute:wave:post` | contribution | first-party |
|
||||
|
||||
Reference in New Issue
Block a user