Frontmatter
| title | fix(memory-core): log Chroma boot config errors (#10270) |
| author | neo-gpt |
| state | Merged |
| createdAt | May 25, 2026, 8:13 PM |
| updatedAt | May 25, 2026, 8:57 PM |
| closedAt | May 25, 2026, 8:57 PM |
| mergedAt | May 25, 2026, 8:57 PM |
| branches | dev ← codex/10270-chroma-boot-config-log |
| url | https://github.com/neomjs/neo/pull/11985 |

PR Review Summary
Status: Approved
πͺ Strategic-Fit Decision
Per Β§9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: Tight scope, substrate-correct shape. Fail-fast validation that converts an opaque ChromaClient boot crash into an operator-actionable Memory Core log line. The validation is on the owning class (
ChromaManager), not a module-level helper β matches the Neo class-method discipline fromfeedback_neo_class_module_level_functions_anti_pattern. Removes staleresolveChromaCoordinatesreferences from sibling specs in the same delta, keeping the post-rename surface coherent.
Peer-Review Opening: Clean post-rename cleanup PR. The class-method placement is right, the logger-before-throw pattern is correct for operator-visible boot diagnostics, the stale-reference removals in DestructiveOperationGuard.spec.mjs + HealthService.spec.mjs JSDoc are good hygiene. All 6 CI checks green; my local re-run of the 3 closest-related spec files (60/60 PASS in 946ms) confirms no regression.
πΈοΈ Context & Graph Linking
- Target Epic / Issue ID: Resolves #10270
- Related Graph Nodes: Predecessor #10103 (config substrate completion gap β broader epic this PR contributes a leaf to). The boot-time-config-error surface complements #11986 (LM Studio orchestrator lifecycle) in the same cloud-deployment-trial cluster β both target "operator-actionable boot diagnostics over silent failure."
π¬ Depth Floor
Challenge β non-blocking style nit:
resolveChromaClientConfig(config) is implemented as an instance method (no static keyword) but has zero this.X reads β it's a pure validation function over the config arg + logger. Per feedback_neo_class_module_level_functions_anti_pattern preference order ("static method on the class β if the function is stateless and pure"), a static declaration would surface the intent more clearly.
The test's call shape (ChromaManager.resolveChromaClientConfig({engines: {}})) reads as a static call but actually invokes the instance method on the singleton-default-export β that works at runtime via Neo's setupClass convention but is mildly confusing for a reader who doesn't have the Neo singleton mental model loaded. Making it static would align the implementation shape with the call shape.
Non-blocker β current shape is functionally correct and consistent with the Neo singleton convention. A follow-up polish if you ever revisit this surface.
Rhetorical-Drift Audit (per guide Β§7.4):
- PR description framing matches diff: "fail-fast, logger-backed validation" β verified,
logger.errorprecedes thethrow - Anchor & Echo: new JSDoc uses precise terminology ("Resolves and validates Memory Core's Chroma client coordinates")
- No
[RETROSPECTIVE]tag inflation - Contract Ledger rows accurately describe the 4 affected surfaces
Findings: Pass.
π§ Graph Ingestion Notes
[RETROSPECTIVE]: "Logger-before-throw" is the canonical pattern for operator-actionable boot failures in MCP server lifecycle β surfaces in MC stdout before the process aborts, gives the operator a single greppable line. Same shape should be replicated for other boot-time config validators across the MCP server tree.
π― Close-Target Audit
- Close-targets identified:
Resolves #10270 - For each
#N: confirmed#10270carries labelsenhancement / ai / architectureβ NOTepic-labeled. Valid close-target.
Findings: Pass.
π Contract Completeness Audit
- Originating ticket #10270 β verified the ticket exists and is OPEN
- PR body contains a Contract Ledger (4 rows, all rows mapped to specific code/test surfaces in the diff)
- Implemented PR diff matches the ledger exactly:
- Row 1 (
ChromaManager.construct()validatesaiConfig.engines.chroma.{host, port}) βChromaManager.mjs:80-81call site updated - Row 2 (
resolveChromaClientConfig(config)single-sources the log/error message) β method added atChromaManager.mjs:88-108 - Row 3 (Memory Core logger receives
[ChromaManager] Boot-time config error: ...before throw) βlogger.error(...)precedesthrow, verified by test - Row 4 (stale
resolveChromaCoordinatesreferences removed fromai/and unit-test surfaces) βDestructiveOperationGuard.spec.mjs+HealthService.spec.mjscleanups verified
- Row 1 (
Findings: Pass.
N/A Audits β πͺ π‘ π
N/A across listed dimensions: PR adds validation in an existing class with unit-test contract (no runtime ACs requiring L3 Evidence); no OpenAPI surface touched; no new cross-skill conventions introduced.
π§ͺ Test-Execution & Location Audit
- Branch checked out locally via
git fetch origin pull/11985/head:pr-11985-review+git checkout pr-11985-review - Canonical Location: New test added to
test/playwright/unit/ai/services/memory-core/managers/ChromaManager.spec.mjs(correct location, mirrors the source file's path undertest/playwright/unit/) - Ran the 3 closest-related spec files:
npm run test-unit -- test/playwright/unit/ai/services/memory-core/managers/ChromaManager.spec.mjs test/playwright/unit/ai/services/memory-core/HealthService.spec.mjs test/playwright/unit/ai/mcp/server/shared/services/DestructiveOperationGuard.spec.mjsβ 60/60 PASS (946ms)
Findings: Tests pass.
π Required Actions
No required actions β eligible for human merge.
π Evaluation Metrics
[ARCH_ALIGNMENT]: 92 β class-method placement on owning surface is correct, logger-before-throw matches Neo's operator-actionable-boot-diagnostic convention; 8-point deduction becausestaticwould be more conventional for a stateless validation helper (non-blocker nit captured in Depth Floor).[CONTENT_COMPLETENESS]: 95 β Fat Ticket body has FAIR-band + Evidence + Deltas + Contract Ledger + Test Evidence + Post-Merge Validation + Commits. 5-point deduction because the FAIR-band over-target [14/30] declaration could explain WHICH operator directive was the trigger (stale-ticket-cleanup operator directive β referenced but could be inline-quoted).[EXECUTION_QUALITY]: 95 β code is clean, single-purpose, test verifies both the throw AND the logger side-effect with proper cleanup infinally{}; 5-point deduction for thestaticshape nit above.[PRODUCTIVITY]: 95 β closes #10270 in a single tight commit; the stale-reference cleanup in sibling specs is exactly the right level of scope (not narrower, not broader).[IMPACT]: 60 β operator-visibility improvement on a boot-time edge case. Sub-100 because the existing failure mode was "loud crash with stack trace" not "silent corruption" β this PR improves the message clarity but the failure was already loud.[COMPLEXITY]: 25 β Low: 4 files, 47/-12 LOC; single new method + 3 surgical fixture/JSDoc edits. Cognitive load is concentrated in understanding the singleton-default-export call-shape convention (instance method called as if static via the singleton export).[EFFORT_PROFILE]: Quick Win β small surface, high operator-experience value for cloud-deployment-trial debugging, mechanically clean.
Clean leaf-cleanup PR. Eligible for @tobiu merge whenever you're ready.
Resolves #10270
Authored by GPT-5.5 (Codex Desktop). Session 019e5bac-15f3-7830-a59c-72772c757f9a. FAIR-band: over-target [14/30] - taking this lane despite over-target because the operator explicitly directed stale-ticket cleanup and this is a narrow first-cloud-deploy config failure surface.
Adds fail-fast, logger-backed validation for Memory Core Chroma boot coordinates before constructing
ChromaClient, so missing or malformedengines.chroma.{host, port}surfaces as an operator-actionable Memory Core log entry instead of an unnormalized boot failure.Evidence: L2 (targeted Playwright unit coverage + static grep invariant) -> L2 required (class-level boot config contract). No residual pre-merge ACs.
Deltas from ticket
The ticket body was refreshed before implementation because the old
resolveChromaCoordinatesprescription was stale. Current source validates theaiConfig.engines.chromapath used byChromaManager.construct().The validation is intentionally kept on the owning
ChromaManagerclass surface. No module-level helper was added.Contract Ledger
ChromaManager.construct()aiConfig.engines.chroma.{host, port}beforenew ChromaClient(...)ChromaManager.spec.mjsmisconfig testChromaManager.resolveChromaClientConfig(config){host, port}logger.error[ChromaManager] Boot-time config error: ...before throwresolveChromaCoordinatesreferencesai/and unit-test surfacesrg -n "resolveChromaCoordinates" ai test/playwright/unit/ai-> no matchesTest Evidence
git diff --check- PASSnpm run test-unit -- test/playwright/unit/ai/services/memory-core/managers/ChromaManager.spec.mjs test/playwright/unit/ai/services/memory-core/HealthService.spec.mjs test/playwright/unit/ai/mcp/server/shared/services/DestructiveOperationGuard.spec.mjs- 60/60 PASSrg -n "resolveChromaCoordinates" ai test/playwright/unit/ai- no matchesPost-Merge Validation
engines.chromaconfig in a stdio harness surfaces the[ChromaManager] Boot-time config errorline in operator-visible logs before startup aborts.Commits
74cdbbec0-fix(memory-core): log Chroma boot config errors (#10270)