Merge pull request #2490 from open-gsd/docs/2481-adr-1239-effort-axis

feat(#2481): add a negotiated effortSurface axis and wire invocation-time effort
This commit is contained in:
Tom Boucher
2026-07-21 20:14:27 -04:00
committed by GitHub
51 changed files with 863 additions and 100 deletions

View File

@@ -610,6 +610,7 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
let fastModeOverride;
let attempt;
let failureClass;
let host;
const positionals = [];
// #2296: the valid classes come from the classifier's own frozen enum, so
// this validator can never drift from what `agent classify-failure` emits.
@@ -675,6 +676,13 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
i++;
continue;
}
if (a === '--host') {
const val = execArgs[i + 1];
if (val === undefined || val.startsWith('--')) error('Missing value for --host', ERROR_REASON.USAGE);
host = val;
i++;
continue;
}
if (a === '--raw') continue;
if (a.startsWith('-')) error(`Unknown flag for resolve-execution: ${a}`, ERROR_REASON.USAGE);
positionals.push(a);
@@ -687,6 +695,7 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
fastModeOverride,
attempt,
failureClass,
host,
});
}

View File

@@ -182,7 +182,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "go"
"runtime": "go",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reviewerCli": true,
@@ -379,7 +380,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
}
}
},
@@ -509,7 +511,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "argv"
},
"hostBehaviors": {
"attributionSource": "settings-json-commit",
@@ -679,7 +682,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "/gsd-update --reapply",
@@ -856,7 +860,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reportCommandsDir": true
@@ -936,7 +941,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "argv"
},
"hostBehaviors": {
"reapplyCommand": "$gsd-update --reapply",
@@ -1031,7 +1037,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "undocumented"
"runtime": "undocumented",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "/gsd-update --reapply",
@@ -1140,7 +1147,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "gsd-update --reapply (mention the skill name)",
@@ -1490,7 +1498,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "python"
"runtime": "python",
"effortSurface": "undocumented"
}
}
},
@@ -1636,7 +1645,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "bun"
"runtime": "bun",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "/gsd-update --reapply",
@@ -1729,7 +1739,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "python"
"runtime": "python",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "/skill:gsd-update --reapply",
@@ -2050,7 +2061,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "bun"
"runtime": "bun",
"effortSurface": "argv"
},
"hostBehaviors": {
"reapplyCommand": "/gsd-update --reapply",
@@ -2173,7 +2185,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "session-log-append",
"transport": "native-extension",
"runtime": "bun"
"runtime": "bun",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"nativePlugin": {
@@ -2350,7 +2363,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"skillPriorityFrontmatter": true,
@@ -2699,7 +2713,8 @@ const capabilities = {
"hookBus": "engine",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"skipSharedHooksInstall": true,
@@ -2849,7 +2864,8 @@ const capabilities = {
"hookBus": "engine",
"stateIO": "sandboxed-storage",
"transport": "mcp",
"runtime": "sandboxed-web"
"runtime": "sandboxed-web",
"effortSurface": "undocumented"
}
}
},
@@ -2928,7 +2944,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "undocumented"
"runtime": "undocumented",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"skipSharedHooksInstall": true,
@@ -3036,7 +3053,8 @@ const capabilities = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "electron"
"runtime": "electron",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"skipSharedHooksInstall": true
@@ -4062,7 +4080,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "go"
"runtime": "go",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reviewerCli": true,
@@ -4176,7 +4195,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
}
}
},
@@ -4260,7 +4280,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "argv"
},
"hostBehaviors": {
"attributionSource": "settings-json-commit",
@@ -4342,7 +4363,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "/gsd-update --reapply",
@@ -4458,7 +4480,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reportCommandsDir": true
@@ -4538,7 +4561,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "argv"
},
"hostBehaviors": {
"reapplyCommand": "$gsd-update --reapply",
@@ -4633,7 +4657,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "undocumented"
"runtime": "undocumented",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "/gsd-update --reapply",
@@ -4742,7 +4767,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "gsd-update --reapply (mention the skill name)",
@@ -4849,7 +4875,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "python"
"runtime": "python",
"effortSurface": "undocumented"
}
}
},
@@ -4943,7 +4970,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "bun"
"runtime": "bun",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "/gsd-update --reapply",
@@ -5036,7 +5064,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "python"
"runtime": "python",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"reapplyCommand": "/skill:gsd-update --reapply",
@@ -5133,7 +5162,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "bun"
"runtime": "bun",
"effortSurface": "argv"
},
"hostBehaviors": {
"reapplyCommand": "/gsd-update --reapply",
@@ -5202,7 +5232,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "session-log-append",
"transport": "native-extension",
"runtime": "bun"
"runtime": "bun",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"nativePlugin": {
@@ -5302,7 +5333,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"skillPriorityFrontmatter": true,
@@ -5401,7 +5433,8 @@ const runtimes = {
"hookBus": "engine",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "node"
"runtime": "node",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"skipSharedHooksInstall": true,
@@ -5456,7 +5489,8 @@ const runtimes = {
"hookBus": "engine",
"stateIO": "sandboxed-storage",
"transport": "mcp",
"runtime": "sandboxed-web"
"runtime": "sandboxed-web",
"effortSurface": "undocumented"
}
}
},
@@ -5535,7 +5569,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "undocumented"
"runtime": "undocumented",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"skipSharedHooksInstall": true,
@@ -5643,7 +5678,8 @@ const runtimes = {
"hookBus": "host",
"stateIO": "filesystem",
"transport": "mcp",
"runtime": "electron"
"runtime": "electron",
"effortSurface": "undocumented"
},
"hostBehaviors": {
"skipSharedHooksInstall": true

View File

@@ -736,6 +736,8 @@ const VALID_STATE_IO = new Set(['filesystem', 'sandboxed-storage', 'ses
const VALID_TRANSPORTS = new Set(['mcp', 'native-extension']);
const VALID_HOST_RUNTIMES = new Set(['node', 'bun', 'sandboxed-web', 'python', 'go', 'rust', 'electron', 'other']);
const VALID_SUBAGENT_TOOLKITS = new Set(['full', 'read-only']);
// ADR-1239 amendment (#2481): how reasoning effort reaches the host.
const VALID_EFFORT_SURFACES = new Set(['argv', 'none']);
// GATE A: installSurface → allowed hooksSurface values (DEFECT.GENERATIVE-FIX: parity invariant)
// Derived from the actual pairings in the 16 real runtime descriptors.
@@ -1204,6 +1206,24 @@ function validateRuntimeBody(cap) {
);
}
// effortSurface (axis) — ADR-1239 amendment (#2481).
// OPTIONAL, unlike the Phase-A axes. It was added after descriptors already
// existed, so requiring it would invalidate every descriptor written before it —
// including third-party ones, breaking the "purely additive" property ADR-1239
// promises for external descriptors. An omitted axis is legitimate: negotiation
// degrades it to the safe floor ('none') and warns, exactly as for any
// undeclared axis. Only a PRESENT value is checked against the vocabulary.
if (hi.effortSurface === undefined) {
// absent — nothing to validate; negotiateHostCapabilities fails it closed.
} else if (hi.effortSurface === '__proto__' || hi.effortSurface === 'constructor' || hi.effortSurface === 'prototype') {
errors.push('runtime.hostIntegration.effortSurface "' + hi.effortSurface + '" is a reserved name');
} else if (hi.effortSurface !== 'undocumented' && !VALID_EFFORT_SURFACES.has(hi.effortSurface)) {
errors.push(
'runtime.hostIntegration.effortSurface must be one of: ' + [...VALID_EFFORT_SURFACES].join(', ') +
' (or "undocumented") (got: ' + JSON.stringify(hi.effortSurface) + ')',
);
}
// dispatch — required object
if (typeof hi.dispatch !== 'object' || hi.dispatch === null || Array.isArray(hi.dispatch)) {
errors.push('runtime.hostIntegration.dispatch must be an object');
@@ -2309,6 +2329,7 @@ module.exports = {
transport: [...VALID_TRANSPORTS],
runtime: [...VALID_HOST_RUNTIMES],
subagentToolkit: [...VALID_SUBAGENT_TOOLKITS],
effortSurface: [...VALID_EFFORT_SURFACES],
},
INSTALL_SURFACE_TO_ALLOWED_HOOKS_SURFACES,
GEMINI_AGENT_EVENTS,

View File

@@ -250,6 +250,12 @@ OPENCODE_MODEL=$(gsd_run query config-get review.models.opencode 2>/dev/null | j
# pinned model that 404s server-side); otherwise agy uses its persisted default.
AGY_MODEL=$(gsd_run query config-get review.models.agy 2>/dev/null | jq -r '.' 2>/dev/null || true)
# Reasoning effort per reviewer (#2481). Empty unless the host's effortSurface
# axis is `argv`. Pass --attempt N to walk ADR-443's escalation ladder.
CLAUDE_EFFORT_ARGS=$(gsd_run query resolve-execution gsd-plan-checker --host claude 2>/dev/null | jq -r '.effort_argv_string // ""' 2>/dev/null || true)
CODEX_EFFORT_ARGS=$(gsd_run query resolve-execution gsd-plan-checker --host codex 2>/dev/null | jq -r '.effort_argv_string // ""' 2>/dev/null || true)
OPENCODE_EFFORT_ARGS=$(gsd_run query resolve-execution gsd-plan-checker --host opencode 2>/dev/null | jq -r '.effort_argv_string // ""' 2>/dev/null || true)
# #1115: `--dangerously-bypass-hook-trust` only exists on codex-cli >= 0.137.0.
# Capability-probe it so older installs don't fail with "unexpected argument"
# (which, with stderr suppressed, produced a silent empty review). The codex
@@ -281,9 +287,9 @@ fi
**Claude (separate session):**
```bash
if [ -n "$CLAUDE_MODEL" ] && [ "$CLAUDE_MODEL" != "null" ]; then
cat {run_dir}/gsd-review-prompt.md | claude --model "$CLAUDE_MODEL" -p - 2>/dev/null > {run_dir}/gsd-review-claude.md
cat {run_dir}/gsd-review-prompt.md | claude --model "$CLAUDE_MODEL" $CLAUDE_EFFORT_ARGS -p - 2>/dev/null > {run_dir}/gsd-review-claude.md
else
cat {run_dir}/gsd-review-prompt.md | claude -p - 2>/dev/null > {run_dir}/gsd-review-claude.md
cat {run_dir}/gsd-review-prompt.md | claude $CLAUDE_EFFORT_ARGS -p - 2>/dev/null > {run_dir}/gsd-review-claude.md
fi
```
@@ -298,9 +304,9 @@ fi
# stdout redirect would append that noise to a non-empty file — slipping past the
# `[ ! -s … ]` empty-output guard as a silently polluted review.
if [ -n "$CODEX_MODEL" ] && [ "$CODEX_MODEL" != "null" ]; then
cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --model "$CODEX_MODEL" --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null
cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --model "$CODEX_MODEL" $CODEX_EFFORT_ARGS --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null
else
cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null
cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral $CODEX_BYPASS_FLAG $CODEX_EFFORT_ARGS --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null
fi
if [ ! -s {run_dir}/gsd-review-codex.md ]; then
echo "Codex review failed or returned empty output. stderr:" > {run_dir}/gsd-review-codex.md
@@ -345,7 +351,7 @@ if [ -n "$OPENCODE_MODEL" ] && [ "$OPENCODE_MODEL" != "null" ]; then
else
set --
fi
cat {run_dir}/gsd-review-prompt.md | opencode run "$@" --format json - 2>{run_dir}/gsd-review-opencode.err > {run_dir}/gsd-review-opencode.json
cat {run_dir}/gsd-review-prompt.md | opencode run "$@" $OPENCODE_EFFORT_ARGS --format json - 2>{run_dir}/gsd-review-opencode.err > {run_dir}/gsd-review-opencode.json
# Reconstruct the review from the assistant text parts into a variable and test
# its CONTENT, not the file size: an empty extraction still prints a trailing
# newline that would fool a `[ -s file ]` check into skipping the stub.