LearnNewsExamplesServices
Frontmatter
id10773
titleHealthcheck observability: providers.neoEmbedding (SQLite-side, symmetric to providers.embedding)
stateClosed
labels
enhancementaiarchitecture
assigneesneo-gpt
createdAtMay 5, 2026, 8:43 PM
updatedAtMay 15, 2026, 2:46 PM
githubUrlhttps://github.com/neomjs/neo/issues/10773
authorneo-opus-4-7
commentsCount1
parentIssue10721
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 6, 2026, 10:13 AM

Healthcheck observability: providers.neoEmbedding (SQLite-side, symmetric to providers.embedding)

Closedenhancementaiarchitecture
neo-opus-4-7
neo-opus-4-7 commented on May 5, 2026, 8:43 PM

Context

Follow-up to PR #10767 (feat(memory-core): surface active embedding provider in healthcheck (#10723)). Surfaced in @neo-gemini-3-1-pro's review (commentId IC_kwDODSospM8AAAABBTBnRg) as a non-blocking architectural observation.

PR #10767 surfaces aiConfig.chromaEmbeddingProvider state under providers.embedding. The Memory Core also has a SQLite-side embedding path controlled by aiConfig.neoEmbeddingProvider (env var NEO_EMBEDDING_PROVIDER), used for native-edge-graph operations on the SQLite engine. Currently the healthcheck does NOT surface the SQLite-side provider state.

The Problem

Operators can intentionally diverge NEO_EMBEDDING_PROVIDER from NEO_CHROMA_EMBEDDING_PROVIDER (different providers for different storage engines). When this happens:

  • A misconfigured NEO_EMBEDDING_PROVIDER (e.g. unset → silent default to gemini, while operator believes a local provider is wired) is undetectable from the healthcheck surface.
  • Operators have no way to verify which SQLite-side provider was actually selected at boot.
  • Even when both providers SHOULD match (most shared deployments), operators can't confirm the match without inspecting logs / re-running config through node -e.

The PR #10767 docs already note this asymmetry in SharedDeployment.md ("A sibling override NEO_EMBEDDING_PROVIDER controls the SQLite-side embedding path; in most shared deployments it should match NEO_CHROMA_EMBEDDING_PROVIDER for consistency, but it can diverge when the SQLite and ChromaDB engines use different providers intentionally") — but doesn't surface it in healthcheck.

The Architectural Reality

  • ai/mcp/server/memory-core/services/HealthService.mjs#buildEmbeddingProviderBlock (added in PR #10767) — currently reads cfg.chromaEmbeddingProvider only
  • aiConfig.neoEmbeddingProvider — the SQLite-side provider config (parallel field to chromaEmbeddingProvider)
  • learn/agentos/SharedDeployment.md "Healthcheck Verification" — currently documents providers.embedding shape with single-provider field

The Fix

Two equivalent shapes worth considering:

Option A (parallel, structurally explicit): add a sibling providers.neoEmbedding block:

"providers": {
    "embedding": { "active": "...", "host": "...", "model": "...", "dimensions": ... },
    "neoEmbedding": { "active": "...", "host": "...", "model": "...", "dimensions": ... }
}

Option B (single block with chroma + neo subfields): restructure providers.embedding to surface both:

"providers": {
    "embedding": {
        "chroma": { "active": "...", "host": "...", "model": "...", "dimensions": ... },
        "neo":    { "active": "...", "host": "...", "model": "...", "dimensions": ... }
    }
}

Option B is cleaner conceptually (both are embedding providers, just for different engines). Option A is closer to the current shape (less restructuring; backward-compatible if any consumer already reads providers.embedding).

Recommendation: Option B (clean restructure now while consumers are still few — only this session's #10770 follow-up references the shape; no public API consumers yet).

Acceptance Criteria

  • buildEmbeddingProviderBlock (or successor function) reads BOTH chromaEmbeddingProvider AND neoEmbeddingProvider; healthcheck surfaces both
  • Mismatch case (the two providers differ) is observable — operators can see at-a-glance whether the two are aligned
  • Unit tests extended: cover same-provider + diverged-provider scenarios
  • learn/agentos/SharedDeployment.md Healthcheck Verification subsection updated to show the new shape
  • Backward-compatibility note in PR body if Option A is taken; restructure-justification if Option B

Contract Ledger (T3)

Per parent epic #10721 AC2 (Contract Completeness Gate). Matrix added 2026-05-06 in response to @neo-gpt's hand-back (suggested row encoded verbatim with editorial adjustments to pin the recommended option).

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
providers.embedding healthcheck payload (Option B restructure) #10773, #10721 AC2 + AC4, PR #10767 providers.embedding shipped shape, SharedDeployment.md ## Healthcheck Verification subsection Restructure providers.embedding to expose both Chroma-side (chroma.{active, host, model, dimensions}) and SQLite-side (neo.{active, host, model, dimensions}) provider selections. Surface an at-a-glance aligned/mismatch signal (e.g. aligned: bool derived from chroma.active === neo.active). Unrecognized provider values remain observable as non-secret error payloads inside their respective subfield (do not throw during healthcheck). Missing optional provider-specific host/model fields return null rather than throwing. If neoEmbeddingProvider env var is unset, neo.active defaults to 'gemini' matching the documented runtime fallback. Update learn/agentos/SharedDeployment.md ## Healthcheck Verification subsection — replace the flat providers.embedding JSON sample with the restructured chroma + neo subfields shape; add restructure-justification note in PR body covering "no public consumers exist yet, only this session's #10770 sibling work." Cross-check that #10770's providers.auth shape stays unaffected (sibling key, not nested). test/playwright/unit/ai/mcp/server/memory-core/services/HealthService.spec.mjs extended with: (1) same-provider case (chroma === neo === 'openAiCompatible', aligned: true), (2) diverged-provider case (chroma === 'gemini', neo === 'openAiCompatible', aligned: false), (3) neoEmbeddingProvider unset → defaults to 'gemini', (4) backward-compatibility check that the new shape reads correctly via existing wiring. Targeted run: npx playwright test test/playwright/unit/ai/mcp/server/memory-core/services/HealthService.spec.mjs --reporter=line.

Out of Scope

  • Provider-provider compatibility validation (e.g. dimensions match across both engines) — separate concern; this ticket is observability only
  • Adding new provider types — this only surfaces existing config, not new functionality
  • Healthcheck providers.auth (separate follow-up #10770)

Related

  • Adjacent shipped: PR #10767 (the current providers.embedding block)
  • Adjacent follow-up: #10770 (providers.auth healthcheck observability — sibling shape for the auth dimension)
  • Pattern precedents: #10176 buildIdentityBlock, #10127 buildTopologyBlock, #10723 buildEmbeddingProviderBlock (chroma side)
  • Parent epic: #10721 (Shared deployment MVP completeness gaps) — this is post-trial-readiness polish, not blocking trial

Origin Session ID: 23b9cbcd-4938-4a46-b21a-0d48dd12e7e7

Retrieval Hint: query_raw_memories(query="healthcheck providers neoEmbedding SQLite-side symmetric chromaEmbeddingProvider 10767 10723 observability sibling")

tobiu referenced in commit e72915f - "feat(memory-core): surface sqlite embedding provider in healthcheck (#10773) (#10799) on May 6, 2026, 10:13 AM
tobiu closed this issue on May 6, 2026, 10:13 AM