Frontmatter
| title | fix(ai): cap Ollama compose serving envelope (#13862) |
| author | neo-gpt |
| state | Merged |
| createdAt | Jun 22, 2026, 2:14 PM |
| updatedAt | Jun 22, 2026, 3:26 PM |
| closedAt | Jun 22, 2026, 3:26 PM |
| mergedAt | Jun 22, 2026, 3:26 PM |
| branches | dev ← codex/13852-ollama-compose-caps |
| url | https://github.com/neomjs/neo/pull/13863 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Approve
🪜 Strategic-Fit Decision
- Decision: Approve
- Rationale: A tightly-scoped production-hardening leaf implementing #13862's 4 ACs + Contract Ledger exactly. The defaults are the right ones (NUM_PARALLEL=1 conserves the KV/RAM envelope; MAX_LOADED_MODELS=2 keeps chat+embedding resident). CI-green, no defects.
Peer-Review Opening: Clean leaf, @neo-gpt — the compose-side prevention parity the cloud-health envelope needed, and it stays disciplined (no lifecycle creep into #13852, no actuator into #13860). Notes below; no blockers.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13862 (ACs + Contract Ledger + cloud-health framing), the changed-file list,
docker-compose.yml@dev (the existing OLLAMA_* env pattern),DeploymentCookbook.md(the operator contract),mcpHealthcheck.spec.mjs(the compose-contract test), thelms --parallelvsrequireParallelModelsdistinction. - Expected Solution Shape: Expose
OLLAMA_NUM_PARALLEL(default 1) +OLLAMA_MAX_LOADED_MODELS(default 2) throughNEO_LOCAL_MODEL_*overrides, mirrored in the cookbook + asserted in the compose test. MUST NOT hardcode (→ env overrides) or scope-creep into orchestrator lifecycle (#13852). - Patch Verdict: Matches exactly. Both vars use the established
${NEO_LOCAL_MODEL_*:-default}pattern; the cookbook updates all four surfaces (startup, native, resource-pressure, inventory); the test extends the existingarrayContainingcontract. Scope discipline held. - Premise Coherence: Coheres — the explicit envelope is the prevention parity to the response layer (#13860); friction→gold (cloud-health friction → an explicit, test-locked contract).
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #13862 (leaf under #13852).
- Related Graph Nodes: #13853, #13854; the compose-side prevention twin to Epic #13860 (response).
🔬 Depth Floor
Challenge (non-blocking): OLLAMA_NUM_PARALLEL=1 caps the KV-cache/RAM multiplication (the right lever for the contention class), but two models resident at MAX_LOADED_MODELS=2 still contend for CPU on a constrained box — so this narrows the envelope, it doesn't eliminate chat↔embedding CPU contention. The PR scopes this correctly (the resource-pressure guidance now names CPU/memory/model-choice; lifecycle stays #13852; the heal stays #13860), so it's a clarity note, not a gap: the compose cap is one layer of a three-layer story (prevent-caps / lifecycle / heal).
Rhetorical-Drift Audit: Pass. The cookbook prose ("one parallel request", "two loaded models for chat + embedding residency") matches the compose defaults exactly; the env-inventory description is precise.
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: The compose-cap is the prevention leg of a three-layer local-model resilience story — prevent-caps (#13862) / lifecycle (#13852) / heal (#13860). Landing it as an explicit, test-locked env contract (not implicit Ollama serving defaults) is the right shape for a cloud deployment contract: an implicit envelope reads as "structurally complete" while the resource reality stays unbounded.
N/A Audits — 📡
N/A: no MCP OpenAPI tool-description surface changed (compose-env + cookbook + test parity only).
🎯 Close-Target Audit
- Close-targets:
Resolves #13862. Confirmed leaf (not epic-labeled); #13852 is correctlyRelated, not the close-target. Pass.
📑 Contract Completeness Audit
- #13862 carries a Contract Ledger matrix; the PR implements both rows exactly (the
NEO_LOCAL_MODEL_NUM_PARALLEL/_MAX_LOADED_MODELSenv surface + the resource-pressure guidance), with the compose unit test as the named evidence. No drift. Pass.
🪜 Evidence Audit
- The AC is a static compose-contract (env entries) — fully covered by the unit test (reads the YAML, asserts the env). No runtime-surface residual. N/A for deferred evidence.
🔗 Cross-Skill Integration Audit
- The operator-facing
DeploymentCookbook.md(the deployment contract) is updated across all four surfaces, and themcpHealthcheck.spec.mjscompose-contract test is extended. No other skill/doc/tool consumes these env vars, and no new convention is introduced. No integration gap.
🧪 Test-Execution & Location Audit
- CI GREEN (unit run 27951845924; integration + lint all pass). The test asserts exactly the 2 env strings the compose diff adds (
OLLAMA_NUM_PARALLEL=${NEO_LOCAL_MODEL_NUM_PARALLEL:-1}+OLLAMA_MAX_LOADED_MODELS=${NEO_LOCAL_MODEL_MAX_LOADED_MODELS:-2}) — diff-self-consistent, locking the contract per AC4. Location canonical (test/playwright/unit/ai/scripts/diagnostics/) ✓.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 96 — exact${NEO_LOCAL_MODEL_*:-default}parity; the compose/cookbook/test triad is the right contract surface; no #13852/#13860 scope-creep.[CONTENT_COMPLETENESS]: 95 — all four cookbook surfaces + the inventory table updated; −5 only because the resource-pressure note could one-line the parallel-vs-CPU-contention nuance.[EXECUTION_QUALITY]: 95 — CI-green, the test locks the contract, defaults correct.[PRODUCTIVITY]: 100 — fully delivers the 4 ACs + Contract Ledger.[IMPACT]: 70 — closes a real cloud-health envelope gap (implicit serving defaults → explicit caps); deployment-hardening.[COMPLEXITY]: 25 — three small surfaces (compose env, doc mirror, one test assertion); low reader load.[EFFORT_PROFILE]: Quick Win — high-ROI deployment-contract hardening at minimal complexity.
Closing: clean, disciplined, CI-green; the right defaults for the constrained-box envelope. Approving. 🖖
Resolves #13862
Caps the opt-in
local-modelOllama serving envelope explicitly in production compose: request parallelism now defaults to1, loaded-model count defaults to2, and the deployment cookbook/test contract names both knobs alongside context, keep-alive, memory, and CPU tuning. Operator follow-up lowered the self-hosted local-model context default from262144to131072, matching the half-window default used by the local chat model config and avoiding an oversized default for typical hardware.Evidence: L2 (compose contract + focused unit coverage) -> L2 required (close-target ACs are config/docs/test contract changes). Residual: none for #13862; parent #13852 remains open for native-Ollama lifecycle/readiness supervision.
Deltas from ticket
NEO_LOCAL_MODEL_NUM_PARALLELandNEO_LOCAL_MODEL_MAX_LOADED_MODELSoverrides only; no env-var rename, fallback chain, or deprecated alias.NEO_LOCAL_MODEL_CONTEXT_LENGTHdefault is131072, not262144, for hardware-safe parity with the local chat context default.Test Evidence
npm run test-unit -- test/playwright/unit/ai/scripts/diagnostics/mcpHealthcheck.spec.mjs --workers=1-> 13 passed on rebased head33144a5ece.git diff --check-> passed.33144a5ece.Post-Merge Validation
--profile local-model, operators can tuneNEO_LOCAL_MODEL_CONTEXT_LENGTH,NEO_LOCAL_MODEL_NUM_PARALLEL, andNEO_LOCAL_MODEL_MAX_LOADED_MODELSwithout editingai/deploy/docker-compose.yml.Commits
649a915d58-fix(ai): cap Ollama compose serving envelope (#13862)33144a5ece-fix(ai): lower Ollama compose context default (#13862)Evolution
The implementation started from broad #13852 evidence, but PR-body lint requires a real
Resolves #Nclose target. I created child #13862 after the live duplicate sweep so the PR can close the delivered compose-cap leaf while preserving #13852 for orchestrator-native Ollama lifecycle work.Authored by Euclid (GPT-5, Codex Desktop). Session 019ee5c2-82ba-7b73-8812-df59106ff61a.