Context
Measured on an external plane 2026-08-11 07:44Z, and reproduced in source. Their provider residency reports:
"requiredModels": ["gemma4:26b", "qwen3-embedding"],
"availableModels": ["qwen3-embedding:latest", "gemma4:26b"],
"missingModels": ["qwen3-embedding"],
"extraModels": ["qwen3-embedding:latest"],
"ready": false
The embedding model is loaded. Ollama stores it as qwen3-embedding:latest; our config asks for qwen3-embedding. Ollama itself resolves an untagged name to :latest, so every embed request works — this is not a dispatch failure.
The Problem
providerReadinessHelper.mjs:1337 and :1841:
const getMissing = available => requiredModels.filter(model => !available.includes(model));
Exact string comparison, no tag normalisation. 'qwen3-embedding' !== 'qwen3-embedding:latest', so a resident model is reported missing permanently — the condition cannot clear, because warming the model produces the same :latest id that already failed to match.
That false negative is not inert. It drives an actuator:
missingModels.length > 0
→ getProviderResidencyReasonCode() → 'missing-required-model' (ContainerHealthDiagnosisService:1392)
→ isProviderRoleResidencyRecoverable() (:1436)
→ recoveryClass 'provider-role-residency', actionClass warmProvider,
confidence 0.85, reason 'provider-role-residency-warm' (:1071-1080)A self-sustaining warm loop. Diagnose missing → warm the provider → model loads under :latest → still "missing" → diagnose again. The gate can never be satisfied, so the loop has no exit.
Why this is Ollama-specific
Ollama canonicalises to name:tag and reports :latest for an untagged pull. LM Studio ids do not gain a suffix, so the same config matches exactly there. That is consistent with the operator's observation that our own plane shows this only when run on Ollama — reproduced locally for ~2h on Monday — and never on LM Studio.
Why it looks like an ingestion problem and is not
On the observed plane, simultaneously:
model container : 395% CPU (cap is cpus:4.0 — this is a CEILING reading, not a work measure)
knowledge (KB) : 0.1% CPU, 60.4M
ingestion : ZERO attempts — all 4 repos backoff-suppressed, sweep "starved"
host : 64 cores, 93% idle
Four cores of continuous provider work while the KB is idle and ingestion has never once attempted. The burn is not the embed path. #16780's framing — burning with nothing asking it to — is satisfied by this mechanism.
Not asserted: that this is the sole cause of the four-core lock. It is a mechanism that (a) exists in source, (b) cannot self-clear, (c) drives repeated provider work, and (d) is present on the observed plane right now. The discriminator is whether warm actions appear in their heal ledger at cadence.
The Fix
Normalise the tag on both sides of the comparison before matching — name and name:latest are the same model to Ollama, and must be to us. Both getMissing sites, plus extraModels (which currently reports the same model as extra while calling it missing, in one payload).
Do not fix by requiring tags in config: NEO_OLLAMA_EMBEDDING_MODEL=qwen3-embedding is valid Ollama and every existing deployment uses it.
Acceptance Criteria
Avoided Traps
- Do not normalise by stripping all tags.
qwen3-embedding:8b and qwen3-embedding:4b are different models with different vector dimensions; collapsing them would silently accept the wrong embedder and corrupt a corpus. Only untagged ↔ :latest.
- Do not treat this as a reporting-only fix. The false negative reaches an actuator; a cosmetic repair to the warning string leaves the loop running.
Context
Measured on an external plane 2026-08-11 07:44Z, and reproduced in source. Their provider residency reports:
"requiredModels": ["gemma4:26b", "qwen3-embedding"], "availableModels": ["qwen3-embedding:latest", "gemma4:26b"], "missingModels": ["qwen3-embedding"], "extraModels": ["qwen3-embedding:latest"], "ready": falseThe embedding model is loaded. Ollama stores it as
qwen3-embedding:latest; our config asks forqwen3-embedding. Ollama itself resolves an untagged name to:latest, so every embed request works — this is not a dispatch failure.The Problem
providerReadinessHelper.mjs:1337and:1841:const getMissing = available => requiredModels.filter(model => !available.includes(model));Exact string comparison, no tag normalisation.
'qwen3-embedding' !== 'qwen3-embedding:latest', so a resident model is reported missing permanently — the condition cannot clear, because warming the model produces the same:latestid that already failed to match.That false negative is not inert. It drives an actuator:
missingModels.length > 0 → getProviderResidencyReasonCode() → 'missing-required-model' (ContainerHealthDiagnosisService:1392) → isProviderRoleResidencyRecoverable() (:1436) → recoveryClass 'provider-role-residency', actionClass warmProvider, confidence 0.85, reason 'provider-role-residency-warm' (:1071-1080)A self-sustaining warm loop. Diagnose missing → warm the provider → model loads under
:latest→ still "missing" → diagnose again. The gate can never be satisfied, so the loop has no exit.Why this is Ollama-specific
Ollama canonicalises to
name:tagand reports:latestfor an untagged pull. LM Studio ids do not gain a suffix, so the same config matches exactly there. That is consistent with the operator's observation that our own plane shows this only when run on Ollama — reproduced locally for ~2h on Monday — and never on LM Studio.Why it looks like an ingestion problem and is not
On the observed plane, simultaneously:
Four cores of continuous provider work while the KB is idle and ingestion has never once attempted. The burn is not the embed path.
#16780's framing — burning with nothing asking it to — is satisfied by this mechanism.Not asserted: that this is the sole cause of the four-core lock. It is a mechanism that (a) exists in source, (b) cannot self-clear, (c) drives repeated provider work, and (d) is present on the observed plane right now. The discriminator is whether warm actions appear in their heal ledger at cadence.
The Fix
Normalise the tag on both sides of the comparison before matching —
nameandname:latestare the same model to Ollama, and must be to us. BothgetMissingsites, plusextraModels(which currently reports the same model as extra while calling it missing, in one payload).Do not fix by requiring tags in config:
NEO_OLLAMA_EMBEDDING_MODEL=qwen3-embeddingis valid Ollama and every existing deployment uses it.Acceptance Criteria
Xmatches an availableX:latest;missingModelsis empty andreadyis true. Fails against the current exact-match.readyis false. The fix must not make the check unfalsifiable.missingModelsandextraModelsin the same payload; that pair is self-contradictory and is what made the report unreadable.qwen3-embedding:8b) still requires that exact tag;:8bmust NOT match:latest. Only the untagged↔:latestequivalence is added.missing-required-modelis not emitted when the model is resident under its canonical tag, sowarmProvideris not scheduled against a satisfied requirement.Avoided Traps
qwen3-embedding:8bandqwen3-embedding:4bare different models with different vector dimensions; collapsing them would silently accept the wrong embedder and corrupt a corpus. Only untagged ↔:latest.