Resolves #16474
The Data Sync Pipeline has failed every run since its last green at 2026-08-02T20:13:14Z, on the content indexes and SEO stage:
Cannot find package 'chromadb'
imported from ai/services/knowledge-base/ChromaManager.mjs
A docs job required a vector-database client, and it did so to read GitHub labels. --include-labels dynamically imports docs/index/labels.mjs, which reached GH_LabelService through ai/services.mjs — a barrel with 66 eager top-level imports spanning every MCP server. Importing one export constructs all of them.
The coupling is old and was always free. The two-path install tier (#16389, merged after that last green run) moved chromadb into the Brain tier, and the Body-tier CI running this script stopped paying for an import it never needed. Nothing about the split is wrong — it made a latent dependency load-bearing.
Evidence: L3 (the failure and the fix both reproduced locally under a Body-tier-equivalent install, with a positive control) → L4 required (the pipeline itself green on dev). Residual: post-merge pipeline recovery [#16474].
Deltas from ticket
makeSafe is not lost, and that was checked rather than assumed. The barrel wraps services in makeSafe(service, spec), which Zod-validates and marshals input arguments. list_labels (ai/mcp/server/github-workflow/openapi.yaml:135) declares no parameters and no requestBody; the raw method is async listLabels(); the call site passes nothing. So the wrapper resolves to parse({}) → paramNames: [] → method.call(service) — identical to the direct call.
That equivalence is local, not general, and the call site says so: a method with parameters would also lose object→positional marshalling, so this is not a licence to narrow other barrel imports without checking.
The Neo bootstrap is not optional. A bare direct import throws:
ReferenceError: Neo is not defined
at src/core/Compare.mjs:166
LabelService is a Neo.setupClass class and the barrel had been performing the namespace bootstrap too. Measured: Neo + core/_export is sufficient — InstanceManager is not needed here. Both imports look unused, so both carry a comment saying they are not.
Three pre-existing alignment fixes in getContrastColor. Unrelated to this change and present on dev (verified against origin/dev's own copy), but the staged-file hook rejects the commit while they are in a file I touch.
Test Evidence
The failure reproduces locally, because this machine's main checkout is a Body-tier install. To test the fix in the branch that has it, the worktree's chromadb was temporarily hidden to make it Body-tier-equivalent:
FIXED (this branch):
Fetching labels from GitHub...
Found 38 labels. Writing to apps/portal/resources/data/labels.json...
Successfully generated labels.json
POSITIVE CONTROL (dev's version, same hidden-chromadb environment):
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'chromadb'
imported from …/ai/services/knowledge-base/ChromaManager.mjsgit status on the generated index: no diff. The output is byte-identical to what is committed — the AC that matters is that the label index is unchanged, not merely that the script runs.
Static import walk over the entry point, run against both versions with the same instrument:
| version |
modules walked |
reaches chromadb |
dev |
107 |
yes — via ai/services.mjs → DreamService → GoldenPathSynthesizer → memory-core HealthService → StorageRouter → CollectionProxy → ChromaManager |
| this branch |
27 |
no |
The control matters: the walker demonstrably finds chromadb when it is reachable, so the negative result is a measurement rather than a broken probe. (CI's error names the knowledge-base ChromaManager while the walk finds the memory-core one first — two arms of the same barrel, same conclusion.)
Surfaces touched: buildScripts/docs/index/labels.mjs → exercised end-to-end above; no dedicated spec covers this build script (None found), and its output is asserted by diff against the committed index.
Post-Merge Validation
Out of Scope
Making ai/services.mjs lazy. That would fix this class everywhere and is the better long-term answer, but it changes a surface every MCP server imports. This narrows one consumer; a census of other Body-tier barrel consumers is worth filing if the pattern recurs.
Commits
652d99b292 — import LabelService directly, with the bootstrap it needs
Authored by Ada (Claude Opus 5, Claude Code). Session eeacb603-97f1-4241-9b2f-3a542cab6d2c.
Resolves #16474
The Data Sync Pipeline has failed every run since its last green at
2026-08-02T20:13:14Z, on thecontent indexes and SEOstage:A docs job required a vector-database client, and it did so to read GitHub labels.
--include-labelsdynamically importsdocs/index/labels.mjs, which reachedGH_LabelServicethroughai/services.mjs— a barrel with 66 eager top-level imports spanning every MCP server. Importing one export constructs all of them.The coupling is old and was always free. The two-path install tier (#16389, merged after that last green run) moved
chromadbinto the Brain tier, and the Body-tier CI running this script stopped paying for an import it never needed. Nothing about the split is wrong — it made a latent dependency load-bearing.Evidence: L3 (the failure and the fix both reproduced locally under a Body-tier-equivalent install, with a positive control) → L4 required (the pipeline itself green on
dev). Residual: post-merge pipeline recovery [#16474].Deltas from ticket
makeSafeis not lost, and that was checked rather than assumed. The barrel wraps services inmakeSafe(service, spec), which Zod-validates and marshals input arguments.list_labels(ai/mcp/server/github-workflow/openapi.yaml:135) declares noparametersand norequestBody; the raw method isasync listLabels(); the call site passes nothing. So the wrapper resolves toparse({})→paramNames: []→method.call(service)— identical to the direct call.That equivalence is local, not general, and the call site says so: a method with parameters would also lose object→positional marshalling, so this is not a licence to narrow other barrel imports without checking.
The Neo bootstrap is not optional. A bare direct import throws:
LabelServiceis aNeo.setupClassclass and the barrel had been performing the namespace bootstrap too. Measured:Neo+core/_exportis sufficient —InstanceManageris not needed here. Both imports look unused, so both carry a comment saying they are not.Three pre-existing alignment fixes in
getContrastColor. Unrelated to this change and present ondev(verified againstorigin/dev's own copy), but the staged-file hook rejects the commit while they are in a file I touch.Test Evidence
The failure reproduces locally, because this machine's main checkout is a Body-tier install. To test the fix in the branch that has it, the worktree's
chromadbwas temporarily hidden to make it Body-tier-equivalent:FIXED (this branch): Fetching labels from GitHub... Found 38 labels. Writing to apps/portal/resources/data/labels.json... Successfully generated labels.json POSITIVE CONTROL (dev's version, same hidden-chromadb environment): Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'chromadb' imported from …/ai/services/knowledge-base/ChromaManager.mjsgit statuson the generated index: no diff. The output is byte-identical to what is committed — the AC that matters is that the label index is unchanged, not merely that the script runs.Static import walk over the entry point, run against both versions with the same instrument:
chromadbdevai/services.mjs→DreamService→GoldenPathSynthesizer→ memory-coreHealthService→StorageRouter→CollectionProxy→ChromaManagerThe control matters: the walker demonstrably finds
chromadbwhen it is reachable, so the negative result is a measurement rather than a broken probe. (CI's error names the knowledge-base ChromaManager while the walk finds the memory-core one first — two arms of the same barrel, same conclusion.)Surfaces touched:
buildScripts/docs/index/labels.mjs→ exercised end-to-end above; no dedicated spec covers this build script (None found), and its output is asserted by diff against the committed index.Post-Merge Validation
content indexes and SEOwithoutERR_MODULE_NOT_FOUND.devand the standing alarm #16428 self-closes on recovery. If it does not, the chromadb import was one cause and not the only one — the streak began after2026-08-02T20:13:14Zand this fixes what run 30861274995 shows, which is not proof it is the sole failure.apps/portal/resources/data/labels.jsonis unchanged by the first post-merge pipeline run.Out of Scope
Making
ai/services.mjslazy. That would fix this class everywhere and is the better long-term answer, but it changes a surface every MCP server imports. This narrows one consumer; a census of other Body-tier barrel consumers is worth filing if the pattern recurs.Commits
652d99b292— import LabelService directly, with the bootstrap it needsAuthored by Ada (Claude Opus 5, Claude Code). Session eeacb603-97f1-4241-9b2f-3a542cab6d2c.