* feat(#1708): typed documentation-sourced #853 dispatch-flatten Graduate the #853 orchestrator-backgrounding decision from a scattered RUNTIME==='codex' prose check to a typed, documentation-sourced engine decision. Adds a backgroundDispatch dispatch sub-axis (sourced per host: codex+cursor documented true, 9 documented false, 5 undocumented), shouldFlattenDispatch(dispatch) (inline UNLESS background && backgroundDispatch, fail-closed), and a gsd_run query dispatch-should-flatten the plan/execute workflows call. Cursor is newly background-eligible per its docs (inline->background) — a documentation-justified behavior change. No RUNTIME-name residue for this decision. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(#1708): backgroundDispatch citations in matrix + CONTEXT note Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#1708): address review findings on typed dispatch-flatten Code/adversarial review: convert the manager.md/autonomous.md Compound Action preamble from hardcoded 'On Codex' to FLATTEN-based branching (the handlers already use the query; the preamble contradicted them and was wrong for cursor); make shouldFlattenDispatch null-safe + type-honest (accepts raw 'undocumented' registry values); make backgroundDispatch a required descriptor field (matching its siblings, all 16 carry it); strengthen the config.runtime behavioral test; update the bug-853 prose-pin test + comment. Security review clean; Codex confirmed no fail-open. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#1708): backfill backgroundDispatch in role:runtime test fixtures Making backgroundDispatch a required descriptor field broke role:runtime fixtures in capability-manifest-version/capability-registry/host-integration-descriptors tests that build a dispatch object without it (caught by full gsd-test, not scoped npm test). Backfill backgroundDispatch:false into the well-formed fixtures; the deliberately-malformed 'required-field' test fixture is left malformed by design. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#1708): update fix-1521 dispatch-gating assertion to the FLATTEN gate fix-1521 pinned the codex-specific run_in_background prose that #1708 graduated to the typed dispatch-should-flatten/FLATTEN gate. Update its assertions to verify FLATTEN=false gating (not a runtime name) + that the old RUNTIME===codex gate is gone. Caught by full gsd-test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(#1708): add changeset for typed dispatch-flatten Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#1708): remove stray temp PR-body file Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#1708): add issue ref to bug-853 allow-test-rule annotations ADR-456 requires every allow-test-rule exemption to carry a see #NNN reference; the source-text-is-the-product annotations added when migrating the prose assertions lacked it (lint-tests CI gate). Add (see #1708). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1238,6 +1238,56 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
||||
break;
|
||||
}
|
||||
|
||||
case 'dispatch-should-flatten': {
|
||||
// #1708 / #853: typed query replacing the `RUNTIME === 'codex'` prose rule.
|
||||
//
|
||||
// Resolves the current runtime (GSD_RUNTIME > config.runtime > 'claude'),
|
||||
// looks up registry.runtimes[id].runtime.hostIntegration.dispatch, and
|
||||
// calls shouldFlattenDispatch(dispatch) from host-integration.cjs.
|
||||
//
|
||||
// Fail-closed: any unknown runtime, missing dispatch, or thrown error
|
||||
// yields `true` (inline — the always-safe default).
|
||||
//
|
||||
// Output:
|
||||
// --raw → prints exactly `true` or `false`
|
||||
// --json → prints { runtime, shouldFlatten, dispatch }
|
||||
// default → same as --raw
|
||||
try {
|
||||
// Resolve runtime using the same precedence as `config-get runtime`.
|
||||
const { resolveRuntime } = require('./lib/runtime-slash.cjs');
|
||||
const runtimeId = resolveRuntime(cwd);
|
||||
|
||||
// Look up dispatch from the capability registry.
|
||||
const registry = require('./lib/capability-registry.cjs');
|
||||
const runtimeEntry = registry.runtimes != null
|
||||
? registry.runtimes[runtimeId]
|
||||
: null;
|
||||
const dispatch = runtimeEntry?.runtime?.hostIntegration?.dispatch ?? null;
|
||||
|
||||
// Call shouldFlattenDispatch from host-integration.cjs.
|
||||
const hostIntegration = require('./lib/host-integration.cjs');
|
||||
const shouldFlat = dispatch !== null
|
||||
? hostIntegration.shouldFlattenDispatch(dispatch)
|
||||
: true; // fail-closed: unknown runtime → inline
|
||||
|
||||
const jsonIdx = args.indexOf('--json');
|
||||
if (jsonIdx !== -1) {
|
||||
output({
|
||||
runtime: runtimeId,
|
||||
shouldFlatten: shouldFlat,
|
||||
dispatch: dispatch,
|
||||
}, raw);
|
||||
} else {
|
||||
// --raw or default: print exactly true or false
|
||||
process.stdout.write(shouldFlat ? 'true' : 'false');
|
||||
}
|
||||
} catch {
|
||||
// Fail-closed on any error: inline is always safe.
|
||||
process.stdout.write('true');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'config-new-project': {
|
||||
// Phase 6 (#3575): dispatch via SDK executeForCjs when available.
|
||||
const handled = _dispatchNonFamily({
|
||||
|
||||
@@ -126,7 +126,8 @@ const capabilities = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": true,
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -248,7 +249,8 @@ const capabilities = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -330,7 +332,8 @@ const capabilities = {
|
||||
"nested": true,
|
||||
"maxDepth": 5,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -389,7 +392,8 @@ const capabilities = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "read-only"
|
||||
"subagentToolkit": "read-only",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "active",
|
||||
"hookBus": "host",
|
||||
@@ -535,7 +539,8 @@ const capabilities = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -604,7 +609,8 @@ const capabilities = {
|
||||
"nested": true,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": true
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -673,7 +679,8 @@ const capabilities = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -758,7 +765,8 @@ const capabilities = {
|
||||
"nested": true,
|
||||
"maxDepth": 2,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": true
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -950,7 +958,8 @@ const capabilities = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": "undocumented",
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -1060,7 +1069,8 @@ const capabilities = {
|
||||
"nested": true,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "read-only"
|
||||
"subagentToolkit": "read-only",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "active",
|
||||
"hookBus": "host",
|
||||
@@ -1203,7 +1213,8 @@ const capabilities = {
|
||||
"nested": true,
|
||||
"maxDepth": -1,
|
||||
"background": true,
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "active",
|
||||
"hookBus": "host",
|
||||
@@ -1275,7 +1286,8 @@ const capabilities = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -1585,7 +1597,8 @@ const capabilities = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": false,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "active",
|
||||
"hookBus": "host",
|
||||
@@ -1789,7 +1802,8 @@ const capabilities = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -2107,7 +2121,8 @@ const capabilities = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": true,
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "engine",
|
||||
@@ -2262,7 +2277,8 @@ const capabilities = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": "undocumented",
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3062,7 +3078,8 @@ const runtimes = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": true,
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3147,7 +3164,8 @@ const runtimes = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3229,7 +3247,8 @@ const runtimes = {
|
||||
"nested": true,
|
||||
"maxDepth": 5,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3288,7 +3307,8 @@ const runtimes = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "read-only"
|
||||
"subagentToolkit": "read-only",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "active",
|
||||
"hookBus": "host",
|
||||
@@ -3373,7 +3393,8 @@ const runtimes = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3442,7 +3463,8 @@ const runtimes = {
|
||||
"nested": true,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": true
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3511,7 +3533,8 @@ const runtimes = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3596,7 +3619,8 @@ const runtimes = {
|
||||
"nested": true,
|
||||
"maxDepth": 2,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": true
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3669,7 +3693,8 @@ const runtimes = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": "undocumented",
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3738,7 +3763,8 @@ const runtimes = {
|
||||
"nested": true,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "read-only"
|
||||
"subagentToolkit": "read-only",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "active",
|
||||
"hookBus": "host",
|
||||
@@ -3829,7 +3855,8 @@ const runtimes = {
|
||||
"nested": true,
|
||||
"maxDepth": -1,
|
||||
"background": true,
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "active",
|
||||
"hookBus": "host",
|
||||
@@ -3901,7 +3928,8 @@ const runtimes = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -3987,7 +4015,8 @@ const runtimes = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": false,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "active",
|
||||
"hookBus": "host",
|
||||
@@ -4060,7 +4089,8 @@ const runtimes = {
|
||||
"nested": false,
|
||||
"maxDepth": 1,
|
||||
"background": true,
|
||||
"subagentToolkit": "full"
|
||||
"subagentToolkit": "full",
|
||||
"backgroundDispatch": false
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
@@ -4128,7 +4158,8 @@ const runtimes = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": true,
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "engine",
|
||||
@@ -4188,7 +4219,8 @@ const runtimes = {
|
||||
"nested": "undocumented",
|
||||
"maxDepth": "undocumented",
|
||||
"background": "undocumented",
|
||||
"subagentToolkit": "undocumented"
|
||||
"subagentToolkit": "undocumented",
|
||||
"backgroundDispatch": "undocumented"
|
||||
},
|
||||
"modelMode": "passive",
|
||||
"hookBus": "host",
|
||||
|
||||
@@ -1188,6 +1188,18 @@ function validateRuntimeBody(cap) {
|
||||
'runtime.hostIntegration.dispatch.maxDepth must be an integer >= -1 or "undocumented" (got: ' + JSON.stringify(d.maxDepth) + ')',
|
||||
);
|
||||
}
|
||||
|
||||
// backgroundDispatch — REQUIRED (all 16 runtime descriptors carry it, matching the sibling fields
|
||||
// namedDispatch/nested/background/subagentToolkit/maxDepth which are all required).
|
||||
if (!Object.prototype.hasOwnProperty.call(d, 'backgroundDispatch')) {
|
||||
errors.push(
|
||||
'runtime.hostIntegration.dispatch.backgroundDispatch is required (must be a boolean or "undocumented")',
|
||||
);
|
||||
} else if (typeof d.backgroundDispatch !== 'boolean' && d.backgroundDispatch !== 'undocumented') {
|
||||
errors.push(
|
||||
'runtime.hostIntegration.dispatch.backgroundDispatch must be a boolean or "undocumented" (got: ' + JSON.stringify(d.backgroundDispatch) + ')',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user