Sub of epic #17018 (AC-B and AC-D stages 1–2). This leaf is merge-ordered after #17019, which amends ADR-0014 before the executable provider profile lands.
Context
Discussion #17015 r6 converged on topology D+F: an Ollama chat lane plus an OpenAI-compatible embedding lane, under one declared total resource envelope. The source sweep that graduated the design found that Neo already has role selectors, but not every consumer honors them and the canonical Compose profile does not yet project the complete role map.
Live duplicate sweep (2026-08-12T12:06Z): latest open issue search for provider lane, NEO_GRAPH_PROVIDER, and vector generation election, plus the current A2A lane-claim page. Only #17018 and #17019 match this implementation scope; no competing claim exists.
The Problem
At origin/dev@173129edd394f3df730ef577c6cdca7bf9eefc07:
ai/services/ingestion/ConceptDiscoveryService.mjs:364-390 constructs OpenAiCompatible directly from the OpenAI-compatible namespace, bypassing the declared role selectors.
ai/deploy/docker-compose.yml projects model and embedding provider values into owning services but omits the graph-provider selector, so a split profile can silently fall back to the wrong lane.
ai/services/graph/providerReadinessHelper.mjs:2353-2507 derives graph readiness and parallel-model capacity from one provider namespace; under D+F it can require the embedding model to be resident on the chat lane.
Scheduled/background producers and KB Ask have adjacent provider construction paths. A partial repair would render Compose correctly while leaving one producer on the old lane.
The failure mode is silent misrouting: both services can be healthy while work crosses the declared provider boundary.
The Architectural Reality
ADR-0019 makes AiConfig the reactive configuration authority. This leaf adds no parallel env readers, hidden defaults, pass-along config, or new same-type host leaves. It consumes the existing role selectors and KB Ask configuration at their owning entrypoints.
ADR-0014, as amended by #17019, owns the two-lane service topology: provider runtimes remain endpoints outside the orchestrator control plane, with stable service identities and explicit resource isolation.
The authoritative consumer map is exhaustive, not illustrative:
chat/model consumers,
graph-generation consumers,
KB Ask synthesis consumers,
embedding consumers across KB, MC, ingestion, recovery, and scheduled/background work.
The Fix
Deliver one cohesive executable profile:
Route Concept Discovery through the declared graph/chat role instead of constructing a provider directly.
Project NEO_MODEL_PROVIDER, NEO_GRAPH_PROVIDER, and NEO_EMBEDDING_PROVIDER explicitly into every owning Compose service; keep KB Ask's own declared provider/model contract intact.
Define the canonical two-service profile with stable chat-lane and embedding-lane DNS identities, immutable engine/model coordinates, and an explicit total CPU/memory envelope with per-lane allocations.
Derive readiness, warm, capacity, and recovery requirements from the active role selectors. A lane must never be required to host a model assigned to the other lane.
Enumerate every production consumer, including immediate boot work and scheduled/background producers, and bind each to exactly one resolved lane.
Emit a rendered composition receipt with service DNS, provider, immutable model coordinate/digest, role, and lane. Readiness must fail on an inconsistent split.
Contract Ledger
Producer
Consumer
Contract
Failure semantics
AiConfig role selectors
provider builders and scheduled producers
each consumer resolves its declared role at the use site
missing/invalid role configuration fails closed; no silent provider fallback
canonical Compose profile
KB, MC, orchestrator, chat lane, embedding lane
stable service identities plus explicit role env pass-through and resource envelopes
rendered inconsistency is a configuration error
role-derived readiness
boot, warm, capacity, recovery
required models are the union for that lane's active roles only
wrong-lane model requirements fail the composition check
composition receipt
operator and validation tooling
one machine-readable mapping of role → provider → model → DNS lane
incomplete, duplicate, or cross-lane ownership is non-ready
Acceptance Criteria
ConceptDiscoveryService.extractConceptsFromSource() uses the declared role/provider construction path; no direct selector-bypassing OpenAiCompatible construction remains.
Every owning Compose service explicitly receives the existing model, graph, and embedding provider selectors; no new host leaf is introduced.
Canonical Compose defines distinct stable chat and embedding service identities under one declared total CPU/memory envelope with per-lane allocations and immutable engine/model coordinates.
Readiness, warm, capacity, and recovery projections are derived from active roles, with regression coverage proving that the chat lane does not require the embedding model and vice versa.
A production consumer census covers chat, graph, Ask synthesis, and embedding work, including scheduled/background producers; every row resolves to exactly one lane.
A rendered composition receipt reports service DNS, provider, model coordinate/digest, role, and lane, and a wrong-lane mutation fails readiness.
Canonical config/render tests and the focused owning-service unit suites are green.
No validation request or experiment is sent to an external plane.
Decision Record Impact
Implements the ADR-0014 amendment owned by #17019 and obeys ADR-0019. No new ADR is required. If implementation requires a new role-scoped same-type host leaf, stop and return to the Discussion rather than widening this ticket.
Sub of epic #17018 (AC-B and AC-D stages 1–2). This leaf is merge-ordered after #17019, which amends ADR-0014 before the executable provider profile lands.
Context
Discussion #17015 r6 converged on topology D+F: an Ollama chat lane plus an OpenAI-compatible embedding lane, under one declared total resource envelope. The source sweep that graduated the design found that Neo already has role selectors, but not every consumer honors them and the canonical Compose profile does not yet project the complete role map.
Live duplicate sweep (2026-08-12T12:06Z): latest open issue search for
provider lane,NEO_GRAPH_PROVIDER, andvector generation election, plus the current A2A lane-claim page. Only #17018 and #17019 match this implementation scope; no competing claim exists.The Problem
At
origin/dev@173129edd394f3df730ef577c6cdca7bf9eefc07:ai/services/ingestion/ConceptDiscoveryService.mjs:364-390constructsOpenAiCompatibledirectly from the OpenAI-compatible namespace, bypassing the declared role selectors.ai/deploy/docker-compose.ymlprojects model and embedding provider values into owning services but omits the graph-provider selector, so a split profile can silently fall back to the wrong lane.ai/services/graph/providerReadinessHelper.mjs:2353-2507derives graph readiness and parallel-model capacity from one provider namespace; under D+F it can require the embedding model to be resident on the chat lane.The failure mode is silent misrouting: both services can be healthy while work crosses the declared provider boundary.
The Architectural Reality
ADR-0019 makes AiConfig the reactive configuration authority. This leaf adds no parallel env readers, hidden defaults, pass-along config, or new same-type host leaves. It consumes the existing role selectors and KB Ask configuration at their owning entrypoints.
ADR-0014, as amended by #17019, owns the two-lane service topology: provider runtimes remain endpoints outside the orchestrator control plane, with stable service identities and explicit resource isolation.
The authoritative consumer map is exhaustive, not illustrative:
The Fix
Deliver one cohesive executable profile:
NEO_MODEL_PROVIDER,NEO_GRAPH_PROVIDER, andNEO_EMBEDDING_PROVIDERexplicitly into every owning Compose service; keep KB Ask's own declared provider/model contract intact.Contract Ledger
Acceptance Criteria
ConceptDiscoveryService.extractConceptsFromSource()uses the declared role/provider construction path; no direct selector-bypassingOpenAiCompatibleconstruction remains.Decision Record Impact
Implements the ADR-0014 amendment owned by #17019 and obeys ADR-0019. No new ADR is required. If implementation requires a new role-scoped same-type host leaf, stop and return to the Discussion rather than widening this ticket.
Out of Scope
{1,2,4}embedding-slot/resource election (adjacent peer leaf).Avoided Traps
Related
Parent #17018 · blocked by #17019 · source Discussion #17015 r6 · ADR-0014 · ADR-0019 · incident evidence #16706
Origin Session ID: 35e0863b-4d45-4b94-90ff-5e66278bea7d
Retrieval hints:
D#17015 AC-B provider lanes ConceptDiscovery NEO_GRAPH_PROVIDER role-derived readiness rendered composition