* fix(#2598): declare OpenCode subagent dispatch synchronous, not background capabilities/opencode/capability.json advertised dispatch.background: true and dispatch.backgroundDispatch: true. negotiateHostCapabilities and every degradationFor / shouldFlattenDispatch consumer trusts these per-field values, so declaring a capability the host lacks OVERSTATES it — the opposite of the fail-closed posture the negotiation is built for. The issue's own citations needed checking before acting: the host-integration matrix (ADR-1239's designated deployment source-of-truth) documented `true` with NEWER evidence than the issue cited, and explicitly marked the issue's sst/opencode#5887 reference as a stale snapshot superseded by #2087. git log confirms #2087 deliberately flipped these from false to true, citing OpenCode v1.15.0/v1.17 as "background subagents enabled by default in all modes". Applying the issue as filed would, on that evidence, have REGRESSED a deliberate update. So the claim was verified against current upstream rather than either document. `packages/opencode/src/effect/runtime-flags.ts` on `dev` today reads: experimentalBackgroundSubagents: enabledByExperimental("OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS") `enabledByExperimental` falls back to the `experimental` flag and `bool()` defaults to false — the parameter is hidden from the model unless an operator opts in by env var. Upstream #29638 is still OPEN and confirms the session loop `tasks.pop()`s one subtask at a time. #2087's "default-on in all modes" reading does not hold against current dev. The issue's CONCLUSION is therefore right even though part of its evidence was superseded: concurrent dispatch cannot be relied on, so both fields are false. The matrix rows are corrected with the verified citation rather than reverted to the old #5887 quote, so the record shows why the value is false TODAY rather than re-asserting evidence that was legitimately superseded. Neighbouring sub-fields are untouched and pinned by test: namedDispatch, subagentToolkit, and isolation:'orchestrator-worktree' (which works via `opencode run --dir` at the OS process level and is unaffected — #2584 does not depend on this value either way). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TCwhbMuY37DzRMCfzTABJ * fix(#2598): re-pin the dispatch contract tests to synchronous OpenCode dispatch gsd-test on the descriptor change came back FAILED (5 unique, both node versions). The failures were not incidental — they were deliberate contract-pin tests encoding #2087's decision, one named literally "background UPGRADE": tests/host-integration-descriptors.test.cjs - EXPECTED_FLATTEN[opencode] === false (background-eligible) - the derived background-eligible set pin tests/opencode-imperative-reference.test.cjs - "descriptor declares background dispatch true/true (v1.15/v1.17 upgrade)" - "background UPGRADE changes shouldFlattenDispatch: false now" So this is a recorded decision being reversed, not drift being corrected, and it is reversed on evidence: current upstream `dev` gates the capability behind OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS (default false) and upstream #29638 (OPEN) confirms the session loop still handles one subtask at a time. The issue is filed by the maintainer and explicitly directs "update golden-parity / validator fixtures as needed", which sanctions re-pinning. Behavioral consequence, verified: shouldFlattenDispatch(opencode) now returns TRUE, so GSD serializes opencode dispatch instead of trusting concurrency it cannot get. That is the correct fail-closed direction and is safe today — no shipped GSD flow drives OpenCode background waves (per the issue), and isolation:'orchestrator-worktree' is unaffected because it works at the OS process level via `opencode run --dir`, not via the native subagent. Each re-pinned test now asserts the retracted contract in the opposite direction — feeding the #2087 axes back in must still yield "would not flatten" — so a silent re-flip of either field is caught rather than merely un-asserted. lint:ci exit 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TCwhbMuY37DzRMCfzTABJ * chore(#2598): backfill changeset pr number (#2682) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,9 +6,10 @@
|
||||
*
|
||||
* Proves opencode is driven through the PUBLIC Host-Integration Interface (the
|
||||
* imperative adapter), that its negotiated axes classify + negotiate correctly,
|
||||
* that negotiation fails CLOSED on a corrupted descriptor, that the Context7-
|
||||
* verified dispatch UPGRADE (background subagents, v1.15/v1.17) changes
|
||||
* `shouldFlattenDispatch`, and that the migration retired the hardcoded
|
||||
* that negotiation fails CLOSED on a corrupted descriptor, that opencode's
|
||||
* SYNCHRONOUS dispatch force-flattens (#2598 retracts #2087's background
|
||||
* "upgrade" — the capability is behind an opt-in flag, not default-on), and that
|
||||
* the migration retired the hardcoded
|
||||
* `runtime === 'opencode'` / `isOpencode` branches (folded into descriptor-driven
|
||||
* `runtime.hostBehaviors` + the combined-family engine install path).
|
||||
*/
|
||||
@@ -48,21 +49,34 @@ test('opencode axes classify as the programmatic-cli reference profile', () => {
|
||||
assert.equal(profileOf(OC_AXES), 'programmatic-cli');
|
||||
});
|
||||
|
||||
// -- AC4: the Context7-verified UPGRADE (background dispatch) -----------------
|
||||
// -- AC4: dispatch is synchronous — the #2087 "upgrade" is retracted (#2598) --
|
||||
|
||||
test('opencode descriptor declares background dispatch true/true (v1.15/v1.17 upgrade)', () => {
|
||||
assert.equal(OC_AXES.dispatch.background, true, 'background subagents (v1.15 param, v1.17 default-on)');
|
||||
assert.equal(OC_AXES.dispatch.backgroundDispatch, true);
|
||||
test('opencode descriptor declares background dispatch false/false (#2598)', () => {
|
||||
// #2087 set these true, reading OpenCode v1.15/v1.17 as "background subagents
|
||||
// enabled by default in all modes". That reading does not hold against current
|
||||
// upstream `dev`, where the capability is opt-in:
|
||||
// experimentalBackgroundSubagents: enabledByExperimental("OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS")
|
||||
// `enabledByExperimental` falls back to the `experimental` flag and `bool()`
|
||||
// defaults false, so the Task tool's `background` parameter is hidden from the
|
||||
// model unless an operator opts in. Upstream #29638 (OPEN) confirms the session
|
||||
// loop still `tasks.pop()`s one subtask at a time.
|
||||
assert.equal(OC_AXES.dispatch.background, false,
|
||||
'background subagents are behind an opt-in experimental flag, not default-on');
|
||||
assert.equal(OC_AXES.dispatch.backgroundDispatch, false,
|
||||
'concurrent dispatch cannot be relied on, so it must not be declared');
|
||||
});
|
||||
|
||||
test('background UPGRADE changes shouldFlattenDispatch: false now (may background), true for the old axes', () => {
|
||||
// Post-upgrade: opencode may run subagents concurrently → NOT force-flattened.
|
||||
assert.equal(shouldFlattenDispatch(OC_AXES.dispatch), false,
|
||||
'with background:true+backgroundDispatch:true, GSD must NOT force-flatten opencode dispatch');
|
||||
// Pin the behavioral change: the pre-#2087 axes DID force-flatten.
|
||||
const preUpgrade = { ...OC_AXES.dispatch, background: false, backgroundDispatch: 'undocumented' };
|
||||
assert.equal(shouldFlattenDispatch(preUpgrade), true,
|
||||
'pre-upgrade (background:false) opencode was force-flattened — this is the behavioral change #2087 lands');
|
||||
test('synchronous dispatch force-flattens; the retracted axes would not have', () => {
|
||||
// Declaring a capability the host lacks is the failure mode #2598 closes:
|
||||
// negotiation is built to fail CLOSED, so an unavailable concurrency
|
||||
// capability must serialize rather than be trusted.
|
||||
assert.equal(shouldFlattenDispatch(OC_AXES.dispatch), true,
|
||||
'with background:false, GSD must force-flatten opencode dispatch (fail closed)');
|
||||
// Pin the retracted contract so a silent re-flip is caught: had the #2087
|
||||
// values been accurate, dispatch would NOT have been flattened.
|
||||
const retracted = { ...OC_AXES.dispatch, background: true, backgroundDispatch: true };
|
||||
assert.equal(shouldFlattenDispatch(retracted), false,
|
||||
'the #2087 axes did not flatten — that is exactly the overstatement #2598 retracts');
|
||||
});
|
||||
|
||||
test('opencode extension-event surface includes the #2087 additions (permission + session.error)', () => {
|
||||
|
||||
Reference in New Issue
Block a user