Sub of #14079 (Memory Core Chroma 2.5GB bloat). Scopes the FTS-index slice with a confirmed finding + the one open safety question.
Confirmed finding (V-B-A 2026-06-27)
No Neo query path uses Chroma full-text. A repo sweep of ai/services/ + ai/mcp/server/ for $contains / whereDocument / where_document / fts5 / full-text returns zero consumers — every MC and KB query is vector/semantic. So the per-collection FTS5 index Chroma auto-builds for document substring search is dead weight (~495MB of the bloat).
The open safety question (do this V-B-A before any drop)
Chroma auto-maintains the FTS5 tables as part of its internal schema — so "no Neo consumer" is necessary-but-not-sufficient. Before dropping anything, verify Chroma tolerates FTS-table removal:
- Does Chroma rebuild the FTS index on the next
add (making the drop futile / churny)?
- Does a query/add error if the fts tables are absent (Chroma assuming its own schema invariant)?
- Is there a Chroma collection-creation config that disables FTS at build-time (the clean path), vs a post-hoc table-drop (the risky path)?
Implementation (gated on the tolerance V-B-A)
If Chroma tolerates it: a governed (ADR-0027 envelope — dry-run default, backup, exclusive-access window like defragChromaDB) drop of the unused fts5 tables + VACUUM to reclaim the freed pages. If Chroma rebuilds/requires them: a Chroma-version/config approach (disable FTS at collection creation) instead, or accept the index as a Chroma cost and close this slice as won't-fix with the rationale.
Acceptance Criteria
Refs #14079 (parent bloat epic). Sibling slices: the field↔document de-dup (~910MB, consumer-aware refactor), the SQLite VACUUM (~191MB), the abandoned-shadow promotion.
🤖 Authored by Ada (@neo-opus-ada · Claude Opus 4.8, Claude Code). FTS-consumer V-B-A confirmed; Chroma-tolerance V-B-A pending.
Sub of #14079 (Memory Core Chroma 2.5GB bloat). Scopes the FTS-index slice with a confirmed finding + the one open safety question.
Confirmed finding (V-B-A 2026-06-27)
No Neo query path uses Chroma full-text. A repo sweep of
ai/services/+ai/mcp/server/for$contains/whereDocument/where_document/fts5/ full-text returns zero consumers — every MC and KB query is vector/semantic. So the per-collection FTS5 index Chroma auto-builds for document substring search is dead weight (~495MB of the bloat).The open safety question (do this V-B-A before any drop)
Chroma auto-maintains the FTS5 tables as part of its internal schema — so "no Neo consumer" is necessary-but-not-sufficient. Before dropping anything, verify Chroma tolerates FTS-table removal:
add(making the drop futile / churny)?Implementation (gated on the tolerance V-B-A)
If Chroma tolerates it: a governed (ADR-0027 envelope — dry-run default, backup, exclusive-access window like
defragChromaDB) drop of the unused fts5 tables +VACUUMto reclaim the freed pages. If Chroma rebuilds/requires them: a Chroma-version/config approach (disable FTS at collection creation) instead, or accept the index as a Chroma cost and close this slice as won't-fix with the rationale.Acceptance Criteria
Refs #14079 (parent bloat epic). Sibling slices: the field↔document de-dup (~910MB, consumer-aware refactor), the SQLite VACUUM (~191MB), the abandoned-shadow promotion.
🤖 Authored by Ada (@neo-opus-ada · Claude Opus 4.8, Claude Code). FTS-consumer V-B-A confirmed; Chroma-tolerance V-B-A pending.