LearnNewsExamplesServices
Frontmatter
id17390
titleFive modules pay a graph database open to import a config object
stateClosed
labels
bugairefactoringagent-os
assigneesneo-opus-ada
createdAtAug 19, 2026, 4:38 PM
updatedAtAug 19, 2026, 5:21 PM
githubUrlhttps://github.com/neomjs/neo/issues/17390
authorneo-opus-ada
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 19, 2026, 5:21 PM

Five modules pay a graph database open to import a config object

Closed Backlog/active-chunk-17 bugairefactoringagent-os
neo-opus-ada
neo-opus-ada commented on Aug 19, 2026, 4:38 PM

Context

Sub-slice of #17383, which established that importing ai/services.mjs opens .neo-ai-data/sqlite/memory-core-graph.sqlite — the file, initSchema(), WAL, 5 s busy timeout — for any process that imports it.

Triage of the 49 non-spec importers found 35 that genuinely use graph/KB/ingestion symbols and 14 that do not. Five of those 14 import exactly one thing: Memory_Config. A config object, at the cost of a database handle.

ai/daemons/kb-gc/KbGarbageCollectionService.mjs:6            import {Memory_Config as aiConfig} from '../../services.mjs';
ai/daemons/kb-reconciliation/KbReconciliationService.mjs:6   import {Memory_Config as aiConfig} from '../../services.mjs';
ai/daemons/kb-alerting/KbAlertingService.mjs:6               import {Memory_Config as aiConfig} from '../../services.mjs';
ai/services/graph/activePrCycleSection.mjs:1                 import {Memory_Config as aiConfig} from '../../services.mjs';
ai/services/graph/TopologyInferenceEngine.mjs:3              import {Memory_Config as AiConfig} from '../../services.mjs';

Live latest-open sweep: checked the latest 10 open issues at 2026-08-19T14:40Z; no equivalent found.

The Problem

ai/services.mjs:64 is import Memory_Config from './mcp/server/memory-core/config.mjs' — the barrel merely re-exports it. So these five reach through a barrel that also re-exports the knowledge-base, memory-core and ingestion families, and inherit its entire runtime reach, to obtain a module the barrel itself imports in one line.

This is #17369's shape one layer up: a module reaching a barrel for a leaf and inheriting the barrel's reach.

The Architectural Reality

  • The sanctioned form already exists and is widely used. Sibling non-entrypoint services import the same module directly — MemoryCoreRecorderService:5, SourceRegistryService:5, CommunityBatchAdmissionService:5, SummaryService:1. This is repo idiom, not invention, and the config binding is identical.
  • ADR-0019 C1 was checked before proposing this, since it is zero-tolerance on AiConfig imports in non-entrypoints. Importing config.mjs is the sanctioned form those siblings use, and the ADR's own V-B-A correction names TaskDefinitions.mjs as the single genuine C1 site. This does not add one.
  • Measured with a load hook logging at me.db = new Database(...), so the evidence is the open itself, not an import-graph inference. The probe bootstraps src/Neo.mjs + src/core/_export.mjs first — without it these modules die as ReferenceError: Neo is not defined, which produced a false zero on the first run.

The Fix

Replace the barrel import with a direct one in each of the five. Behaviour-preserving for config resolution; the only change is reach.

Acceptance Criteria

  • AC-1: None of the five imports ai/services.mjs.
  • AC-2: Each obtains aiConfig from ai/mcp/server/memory-core/config.mjs directly, matching the sibling services already doing so.
  • AC-3: A runtime probe shows the database open before and its absence after, per module. The before-arm is the control and must fire — a probe that reports no open because it crashed on the missing Neo bootstrap is a false zero and does not satisfy this.
  • AC-4: Modules that still open the database through a different path are named individually with that path, not silently counted as closed. Partial is an acceptable outcome; an unstated partial is not.
  • AC-5: Existing specs for the touched daemons stay green, and hostBarrelRuntimeReach.spec.mjs#17384's guard — stays green.

Out of Scope

  • The eager open in GraphService.initAsync itself — #17383, still open. This removes consumers from the path; it does not change what the path does.
  • The other 9 non-config importers of the 14, which pull real services and need per-service reach checks.
  • ai/agent/Loop.mjs, which does import * as SDK so its use cannot be read from the import at all.

Avoided Traps

  • Assuming the swap is safe because it looks like one line. ADR-0019 C1 makes a naive "import AiConfig directly" a zero-tolerance violation in a non-entrypoint; it is only correct here because the sibling pattern establishes config.mjs as the sanctioned source.
  • Counting a crashed probe as a clean result. The first measurement reported one module as never opening the database; it was dying before it got there.

Part of #17383.

⚖️ Ada · @neo-opus-ada · Claude Opus 5 · Claude Code

tobiu referenced in commit e1e0517 - "fix(ai): five config-only consumers stop reaching the Brain barrel (#17390) (#17389) on Aug 19, 2026, 5:21 PM
tobiu closed this issue on Aug 19, 2026, 5:21 PM