fix(#2297): scope resolve_model_ids:"omit" to the resolving runtime (#2332)

* fix(#2297): scope resolve_model_ids:"omit" to the resolving runtime

The installer writes resolve_model_ids:"omit" for non-alias runtimes into the
machine-wide ~/.gsd/defaults.json (#1156); any runtime read it back, so install
order silently flipped Claude's adaptive tier aliases (executor->sonnet,
planner->opus) to '' in no-project sessions.

Resolution is now scoped to the runtime actually resolving, identified by a new
per-install <install>/gsd-core/.gsd-runtime marker (installer writes it beside
VERSION). The "omit" branch returns '' only when the PROJECT explicitly set omit
(honored for all runtimes, #2517 finding #4) OR the active runtime lacks native
aliases. Claude ignores a global-defaults-only omit and keeps its aliases; the
active runtime is canonicalized (GSD_RUNTIME -> config.runtime -> marker ->
claude) so alias/case spellings can't defeat the check; explicit project
omit is workstream/project-scope aware; explicit true still materializes IDs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(#2297): backfill PR number 2332 into changeset

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-07-16 13:33:36 -04:00
committed by GitHub
parent 1bb724048a
commit 9ad2bab4be
40 changed files with 582 additions and 4 deletions

View File

@@ -10880,6 +10880,22 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
failures.push('VERSION');
}
// #2297: write a per-install runtime marker co-located with VERSION at
// <install>/gsd-core/.gsd-runtime. It gives resolveModelInternal a reliable
// "which runtime owns THIS install" signal in a no-project session (config.runtime
// is null and GSD_RUNTIME is not exported), so the shared ~/.gsd/defaults.json
// resolve_model_ids:"omit" policy (written below for non-alias runtimes only)
// applies ONLY when a non-alias runtime is actually resolving — a Claude session
// reads its own marker and keeps its tier aliases instead of inheriting another
// runtime's install-order-dependent "omit". See src/model-resolver.cts.
const runtimeMarkerDest = path.join(targetDir, 'gsd-core', '.gsd-runtime');
fs.writeFileSync(runtimeMarkerDest, `${runtime}\n`);
if (verifyFileInstalled(runtimeMarkerDest, '.gsd-runtime')) {
console.log(` ${green}✓${reset} Wrote runtime marker (.gsd-runtime: ${runtime})`);
} else {
failures.push('.gsd-runtime');
}
// Reusable: copy hooks/dist/ + hooks/lib/ into destRootDir, writing the
// CommonJS package.json marker alongside them. Used below for the generic
// configDir install path (guarded by hostBehaviors.skipSharedHooksInstall),