fix(#1151): drive codex sandbox_mode emission from runtime descriptor sandboxTier axis (#1152)

* fix(#1151): drive codex sandbox_mode emission from runtime descriptor sandboxTier axis

The sandboxTier runtime-capability axis was cosmetic: declared and validated
on all 16 descriptors but read by nothing. The codex per-agent sandbox_mode
line was emitted unconditionally from the hardcoded CODEX_AGENT_SANDBOX map, so
the descriptor field drove no behaviour (ADR-857 audit finding F10; the
"rides along in 5e/5g" promise in ADR-1016 §8 never landed).

Make the axis load-bearing:
- resolveInstallPlan projects sandboxTier as a 7th InstallPlan axis and fails
  loud (throws) on a missing/invalid value rather than coercing to 'none'.
- installCodexConfig / generateCodexAgentToml gate sandbox_mode emission on
  sandboxTier !== 'none'.
- The per-agent CODEX_AGENT_SANDBOX map is kept: it is GSD agent policy, not a
  runtime-descriptor property (different layer). Full removal of that map is
  tracked under #1138 (phase-6 descriptor-residue removal).

For codex (sandboxTier === 'codex-agent-sandbox') the emitted TOML is
byte-identical to before; for 'none' runtimes sandbox_mode is omitted.
Adds leaf, projection, and installCodexConfig threading-seam regression tests;
updates the enh-1082 InstallPlan golden master with sandboxTier for all 16
runtimes. Confirmed hypothesis: schema-first vocabulary closure outran consumer
wiring, with no conformance gate to catch the orphaned axis.

Closes #1151
Refs #857, #1138

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(#1151): stamp changeset with PR number 1152

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:
Tom Boucher
2026-06-13 00:06:52 -04:00
committed by GitHub
parent 607813f5d0
commit 0c0a8966ba
7 changed files with 145 additions and 7 deletions

View File

@@ -30,6 +30,9 @@
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { runtimes } = require('./capability-registry.cjs') as { runtimes: Record<string, { runtime: Record<string, unknown> | undefined }> };
/** Valid sandboxTier enum values — mirrors the gen-capability-registry validator vocabulary. */
const VALID_SANDBOX_TIERS = new Set(['none', 'codex-agent-sandbox']);
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
@@ -71,6 +74,8 @@ interface InstallPlan extends RuntimeConfigIntent {
extendedHookEvents: string[];
/** Which surface owns the hook registration for this runtime. */
hooksSurface: HooksSurface;
/** Runtime sandbox tier ('none' | 'codex-agent-sandbox'); gates per-agent sandbox_mode emission. */
sandboxTier: string;
}
// ---------------------------------------------------------------------------
@@ -130,6 +135,10 @@ function resolveInstallPlan(runtime: string): InstallPlan {
const desc = runtimes[runtime]?.runtime;
if (!desc) throw new TypeError(`Unknown runtime for install plan: ${runtime}`);
const configIntent = resolveRuntimeConfigIntent(runtime);
const sandboxTier = desc['sandboxTier'];
if (typeof sandboxTier !== 'string' || !VALID_SANDBOX_TIERS.has(sandboxTier)) {
throw new TypeError(`Runtime '${runtime}' has a missing or invalid sandboxTier descriptor axis: ${JSON.stringify(sandboxTier)}`);
}
return {
runtime,
installSurface: configIntent.installSurface,
@@ -140,6 +149,7 @@ function resolveInstallPlan(runtime: string): InstallPlan {
hooksSurface: desc['hooksSurface'] != null
? desc['hooksSurface'] as HooksSurface
: ((runtime === 'opencode' || runtime === 'kilo') ? 'none' : 'settings-json'),
sandboxTier,
};
}