---
number: 12169
title: >-
  refactor(ai): defrag uses canonical dummyEmbeddingFunction; drop
  github-workflow copy (#12165)
author: neo-opus-ada
state: MERGED
createdAt: '2026-05-29T10:55:14Z'
updatedAt: '2026-05-29T11:32:35Z'
closedAt: '2026-05-29T11:32:32Z'
mergedAt: '2026-05-29T11:32:32Z'
head: agent/12165-dummy-ef-ssot
base: dev
url: 'https://github.com/neomjs/neo/pull/12169'
---
Resolves #12165
Related: #12101, #12166

Authored by Claude Opus 4.8 (Claude Code 1M). Session b124b83a-2cca-4a2b-a711-64868439ba1e.

FAIR-band: over-target [20/30] — operator-direction (operator "dig in" on the #12101 follow-up subs). Rebalance: #12168 (the foundation) offered to under-target @neo-gpt [10/30] — see A2A.

**Scope narrowed during review** (operator architectural challenge): this PR carries only the two **chain-independent** dummy-EF cleanups. The KB realm-leaf dedup is explicitly **out** — see below.

## What shipped

- **defragChromaDB.mjs** — hardcoded `const dummyEf = {name:'dummy', …}` → `const dummyEf = AiConfig.dummyEmbeddingFunction`. The defrag is a maintenance **script** reading the canonical Tier-1 source at point-of-use (a consumer read, not a child-provider re-assign). The old `name:'dummy'` is exactly what chromadb-3.x mapped to the (non-existent) `@chroma-core/dummy` package → the deserialization warning during `chroma defrag (knowledge-base)`.
- **github-workflow/config.template.mjs** — `dummyEmbeddingFunction` removed (the server never imports chroma — dead config; `grep -c chromadb` = 0).

## Explicitly NOT in this PR (deferred to #12166)

KB's `dummyEmbeddingFunction` consolidation. An interim attempt used `dummyEmbeddingFunction: {default: AiConfig.dummyEmbeddingFunction}` — but that is the **child-provider-re-assigns-parent anti-pattern** (`default: AiConfig.x`) that Epic #12101 exists to eliminate. KB already carries that pattern for `auth.*` / `backupPath` / `engines.chroma.*` (from #12164); **all** of them — `dummyEmbeddingFunction` included — are removed in **#12166** via chain-inheritance (KB *omits* the leaves and inherits them through `getParent()`), never re-assigned. So this PR does not touch KB.

## Commits

- `613f721ec` — initial (defrag + GH-workflow + an interim KB snapshot).
- `e1dbf00a4` — reverts the KB snapshot per the architectural review above. **Net diff vs dev = defrag + github-workflow only** (squash-merge collapses the add-then-revert).

## Deltas from ticket

KB dedup removed from #12165 scope → moved to #12166 (it requires the parent chain to do without a snapshot). #12165 ticket rescoped to match.

## Evidence

Evidence: L1 (static config-shape + Neo-bootstrapped import) → L2 desired for warning-clear. Residual: defrag warning-clear needs a live `chroma defrag` run [#12165 post-merge]; suppression fallback tracked on #12102.

- github-workflow template parses + `dummyEmbeddingFunction === undefined` (Neo-bootstrapped import).
- `defragChromaDB.mjs` imports `AiConfig` from `../../config.mjs`; `AiConfig.dummyEmbeddingFunction` resolves to the canonical Tier-1 EF (`name='dummy_embedding_function'` + verbose anti-legacy structure).

## Test Evidence

- Affected specs grep-confirmed to NOT assert the `dummyEmbeddingFunction` structure (github-workflow `ConfigCompleteness.spec` asserts `issueSync` keys only). Edits don't red them.
- Full Playwright suite runs in CI (worktree has no `node_modules`).

## MCP config-template change

- `github-workflow/config.template.mjs`: `dummyEmbeddingFunction` removed.
- **Local `config.mjs` follow-up after merge:** regenerate each clone's gitignored github-workflow `config.mjs` from the template; restart that MCP server. No `config.mjs` committed.

## Post-Merge Validation

- [ ] Regenerate github-workflow `config.mjs`; restart its MCP server.
- [ ] Confirm `chroma defrag (knowledge-base)` no longer emits `@chroma-core/dummy is not installed`. If residual, suppression follow-up is on #12102.
