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

@@ -150,7 +150,7 @@ The migration is staged the way phases 3–4 were (registry-only → consume inc
6. **5f — extract `hooksSurface` into its own module, then drive it** ← descriptor. `hooks-surface` is the one axis still scattered across `install.js`; its module extraction is a prerequisite, exactly as ADR-3660 was for `artifactLayout`. **5f-completion (done):** `installSurface` drives the config-writing adapter in `runtime-config-adapter-registry` (#1055, retiring the hand-kept `REGISTRY` table); `extendedHookEvents` drives per-event hook registration in `applySettingsJsonHooks` (#1076, retiring the three hardcoded per-event guards); `hooksSurface === 'none'` is now load-bearing for the hook-skip path (replacing `isOpencode/isKilo` flags). `writesSharedSettings` and `permissionWriter` complete the adapter-selection and permissions-writer parameterisation (all four axes added to `validateRuntimeBody`).
7. **5g — materialize the `InstallPlan`** (ADR-58) — **DONE**: the install-level descriptor axes (`installSurface`, `writesSharedSettings`, `finishPermissionWriter`, `hookEvents`, `extendedHookEvents`, `hooksSurface`) are collected into one typed `InstallPlan` value by the exported `resolveInstallPlan(runtime)` in `runtime-config-adapter-registry`. `install()` and `finishInstall()` in `bin/install.js` now route through it. The spatial axes (`configHome`, `artifactLayout`, `commandStyle`) remain behind their self-resolving adapter modules (`runtime-homes` / `runtime-artifact-layout` / `runtime-slash`) as the execution adapters — consistent with the "adapters execute" pattern. Phase 5 is fully materialized.
Each rung is its own approved-enhancement + PR + equivalence proof (`sandbox-tier`, codex-only, is tiny and rides along in 5e/5g). **Irreducible first-party code, named not hidden:** the artifact converter *functions* remain first-party code, selected by the descriptor's closed `ConverterName` — the descriptor never embeds them.
Each rung is its own approved-enhancement + PR + equivalence proof. (`sandbox-tier`, codex-only, was scoped to ride along in 5e/5g, but neither rung delivered the drive — the InstallPlan capstone shipped with six axes and `sandboxTier` was not among them. It is now wired directly: `resolveInstallPlan` projects `sandboxTier`, and `installCodexConfig` gates per-agent `sandbox_mode` emission on `sandboxTier !== 'none'`. The per-agent mode table `CODEX_AGENT_SANDBOX` remains GSD agent policy — not a runtime-descriptor property — so it is intentionally NOT retired here; full removal of that registration-tax map is tracked under #1138 (phase-6 descriptor-residue removal). The gate is behaviourally a no-op while codex is the only runtime with a non-`none` tier.) **Irreducible first-party code, named not hidden:** the artifact converter *functions* remain first-party code, selected by the descriptor's closed `ConverterName` — the descriptor never embeds them.
### 9. Two axes: the descriptor dogfoods the *runtime* interface only