Context
Operator live observation after the harness/orchestrator restart: only the embedding model remained resident (text-embedding-qwen3-embedding-8b, Idle TTL 60 min, Parallel 4). The configured intent is not "keep whichever model was most recently used"; it is to keep the active provider role set resident: one chat model and one embedding model. If the currently unused role is ejected, the next request pays a cold load and the recovery daemon never closes the loop.
Live latest-open sweep: checked latest 20 open issues at 2026-06-24T11:22:18Z; no equivalent found. Closest related issues are #13700 (LM Studio chat parallel-slot memory), #13879 (Ollama stale resident reporting), and #13852 (native Ollama lifecycle/context). A2A in-flight sweep over latest 30 messages at 2026-06-24T11:22:18Z found no competing claim.
Release classification: deployment immune-system hardening under the recovery epic; boardless until the operator explicitly marks it release-blocking.
The Problem
The provider readiness helpers can already describe and warm the configured role set, but the diagnostics/recovery boundary treats a missing configured model as config drift. That means "embedding resident, chat missing" escalates instead of first restoring the missing role. On a memory-constrained host this causes avoidable reload latency and can look like aggressive model switching/ejection.
The failure class affects both local LM Studio and cloud/native Ollama. The fix must cover both providers through the active provider readiness path, not add a local-only workaround.
The Architectural Reality
ai/config.template.mjs defines ollama.requireParallelModels and openAiCompatible.requireParallelModels as the distinct resident-model count, default 2. This is separate from LM Studio --parallel, which is a per-model slot/KV-cache multiplier.
buildLmsPreloadConfig() and buildOllamaReadinessConfig() already derive the active chat/embedding role set from AiConfig selectors.
ensureLmsModelsLoaded() can load missing LM Studio role models and narrowly clean stale/suffixed same-model residents.
ensureOllamaModelsReady() can warm missing native Ollama chat/embedding roles through /api/chat and /api/embed with configured keep_alive and context.
ContainerHealthDiagnosisService currently maps missing-required-model to config drift/escalate, and RecoveryActuatorService only supports restart/redeploy/page, so there is no warm-before-escalate repair path.
The Fix
Add a provider-residency repair path that preserves the full active role set before escalation:
- Classify missing active role models as a recoverable provider-role residency gap first, not immediate config drift.
- Route the first repair through the active provider readiness helper: LM Studio via
ensureLmsModelsLoaded(), native Ollama via ensureOllamaModelsReady().
- Add hysteresis/cooldown so repeated probes do not churn models or spam warm attempts.
- Keep duplicate cleanup narrow: unload only stale/suffixed same-model residents after the exact configured model is sufficient. Never unload the configured chat model merely because embedding is active, or vice versa.
- Escalate only after repair fails or provider capacity prevents co-residency, with operator-actionable guidance for LM Studio loaded-model cap or Ollama max-loaded-models/memory budget.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
| Provider-residency diagnosis reason |
ADR 0025 diagnostics model |
Missing active role is recoverable provider-role residency before config-drift escalation |
Escalate if repair fails/persists |
JSDoc on diagnosis helper |
Unit coverage for missing chat and missing embedding |
| Recovery controller/actuator path |
ADR 0026 controller-agnostic recovery envelope |
Apply one bounded warm repair, then re-observe |
Page/escalate with diagnosis after cooldown/attempt cap |
Service JSDoc + PR body |
Unit coverage for cooldown and failure escalation |
| LM Studio role-set repair |
providerReadinessHelper.mjs |
Restore full required model set while preserving the other role |
Degraded result if load/cap fails |
Existing helper JSDoc updates |
Unit tests for chat-missing/embedding-resident and inverse |
| Native Ollama role-set repair |
providerReadinessHelper.mjs |
Warm missing roles through /api/chat or /api/embed with configured keep_alive/context |
Degraded result with capacity warning |
Existing helper JSDoc updates |
Unit tests for both role directions |
| Optional embedding parallel config |
ADR 0019 AiConfig SSOT |
If added, define localModels.embedding.parallel as a leaf; consumers read at use site |
Leave LM Studio default if not added |
Config comments |
Config/helper test if implemented |
Decision Record impact
Aligned-with ADR 0019, ADR 0025, and ADR 0026. This work reads AiConfig leaves at the use site, keeps diagnostics separate from actuator authority, and applies one bounded lifecycle/config repair before escalation.
Acceptance Criteria
Out of Scope
- No public MCP surface.
- No arbitrary model unload endpoint.
- No change to the meaning of
requireParallelModels.
- No phase-2 downscaling/homeostatic controller; Discussion
#13873 remains the v2 home.
- No provider-specific cloud deployment secrets or client-specific config.
Avoided Traps
- Reject "eject the currently unused role" as the policy. The configured active role set must stay resident.
- Reject "never unload anything" as the opposite overcorrection. Same-model duplicate/stale cleanup remains valid.
- Reject restart/redeploy as the first response to a missing role. Warm, re-observe, then escalate if the provider cannot hold the configured set.
Related
Related: #13874, #13860, #13700, #13879, #13852
Origin Session ID: cd2b88d7-8134-4ef8-a10f-0b1e80c03db4
Handoff Retrieval Hints: provider role-set residency repair missing chat embedding resident LM Studio Ollama recovery daemon, requireParallelModels distinct models vs parallel slots, missing-required-model config drift recovery warm before escalation
Context
Operator live observation after the harness/orchestrator restart: only the embedding model remained resident (
text-embedding-qwen3-embedding-8b, Idle TTL 60 min, Parallel 4). The configured intent is not "keep whichever model was most recently used"; it is to keep the active provider role set resident: one chat model and one embedding model. If the currently unused role is ejected, the next request pays a cold load and the recovery daemon never closes the loop.Live latest-open sweep: checked latest 20 open issues at 2026-06-24T11:22:18Z; no equivalent found. Closest related issues are
#13700(LM Studio chat parallel-slot memory),#13879(Ollama stale resident reporting), and#13852(native Ollama lifecycle/context). A2A in-flight sweep over latest 30 messages at 2026-06-24T11:22:18Z found no competing claim.Release classification: deployment immune-system hardening under the recovery epic; boardless until the operator explicitly marks it release-blocking.
The Problem
The provider readiness helpers can already describe and warm the configured role set, but the diagnostics/recovery boundary treats a missing configured model as config drift. That means "embedding resident, chat missing" escalates instead of first restoring the missing role. On a memory-constrained host this causes avoidable reload latency and can look like aggressive model switching/ejection.
The failure class affects both local LM Studio and cloud/native Ollama. The fix must cover both providers through the active provider readiness path, not add a local-only workaround.
The Architectural Reality
ai/config.template.mjsdefinesollama.requireParallelModelsandopenAiCompatible.requireParallelModelsas the distinct resident-model count, default 2. This is separate from LM Studio--parallel, which is a per-model slot/KV-cache multiplier.buildLmsPreloadConfig()andbuildOllamaReadinessConfig()already derive the active chat/embedding role set from AiConfig selectors.ensureLmsModelsLoaded()can load missing LM Studio role models and narrowly clean stale/suffixed same-model residents.ensureOllamaModelsReady()can warm missing native Ollama chat/embedding roles through/api/chatand/api/embedwith configuredkeep_aliveand context.ContainerHealthDiagnosisServicecurrently mapsmissing-required-modelto config drift/escalate, andRecoveryActuatorServiceonly supports restart/redeploy/page, so there is no warm-before-escalate repair path.The Fix
Add a provider-residency repair path that preserves the full active role set before escalation:
ensureLmsModelsLoaded(), native Ollama viaensureOllamaModelsReady().Contract Ledger Matrix
providerReadinessHelper.mjsproviderReadinessHelper.mjs/api/chator/api/embedwith configured keep_alive/contextlocalModels.embedding.parallelas a leaf; consumers read at use siteDecision Record impact
Aligned-with ADR 0019, ADR 0025, and ADR 0026. This work reads AiConfig leaves at the use site, keeps diagnostics separate from actuator authority, and applies one bounded lifecycle/config repair before escalation.
Acceptance Criteria
Out of Scope
requireParallelModels.#13873remains the v2 home.Avoided Traps
Related
Related: #13874, #13860, #13700, #13879, #13852
Origin Session ID: cd2b88d7-8134-4ef8-a10f-0b1e80c03db4
Handoff Retrieval Hints:
provider role-set residency repair missing chat embedding resident LM Studio Ollama recovery daemon,requireParallelModels distinct models vs parallel slots,missing-required-model config drift recovery warm before escalation