Closes#74587. AI-assisted, fully tested.
The previous deprecation warning ("set config.modelFallback explicitly
if you want a fallback model") read naturally as runtime failover —
model A errors → switch to model B. The actual semantics in
`getModelRef` are different: `modelFallback` is the **last candidate
in the chain-resolution walk**, consulted only when `config.model`,
the current run's model, AND the agent's configured default have all
resolved to nothing. There is no error-recovery / retry-with-different-model
path.
The mismatch wastes real debug time. The issue filer reports ~1 hour of
cycles before reading source revealed the gap; users without source
access can debug for much longer assuming runtime failover exists.
## Fix
Rewrite the warning string to:
1. State the deprecation (preserved).
2. Describe `modelFallback`'s actual semantics — chain-resolution
last-resort, gated on the three earlier candidates resolving to
nothing.
3. Explicitly disclaim the wrong mental model — "it is NOT a runtime
failover that substitutes a different model when the resolved model
errors out" — so a quick read can't lead the operator astray.
No behavior change, only operator-facing copy. Surrounding code paths
(`getModelRef`, `hasDeprecatedModelFallbackPolicy`, the warn caller in
`register()`) are untouched.
## Tests
`extensions/active-memory/index.test.ts` extends the existing
deprecation-warning assertion to pin both the positive copy
(`chain-resolution`, `last-resort`) and the negative disclaimer
(`NOT a runtime failover`), so a future "let's reword this" change
that reintroduces the failover-implying language fails the test
instead of silently regressing.
`pnpm test extensions/active-memory/index.test.ts` — 94 passed.
`pnpm exec oxfmt --check` — clean. `pnpm exec oxlint` — 0 warnings,
0 errors.
## AI-assisted PR
- [x] Mark as AI-assisted (Claude). Lightly tested via the targeted
Vitest extension shard; not exercised against a live Ollama / AM
rollout because the change is a log-string update, not behavior.
- [x] Confirm I understand what the code does: yes — `getModelRef`
walks four candidates (`config.model`, `currentRunModel`,
`configuredDefaultModel`, `config.modelFallback`) and returns the
first non-null parse; `modelFallback` is purely a default-when-empty
selector, not a runtime failover.