Summary
Migrate existing embeddings to pgvector, keep the CSV/embeddings_content columns, and cut over chatbot + similarity matching (and Librarian C.1) to use embedding_vec on Postgres.
This is a follow-on to the Heroku slug work (#975): drop app-side numpy/scipy/sklearn for prod chat matching by doing cosine in Postgres.
Related: Librarian C.1 already expects embedding_vec + <=> (PR #937 by @PRAteek-singHWY); the W8 Alembic migration was never written. Prod DB is Heroku Postgres essential-1 (pgvector extension supported; $0 for the extension itself).
Local plan: .cursor/plans/pgvector-migration.md
Goals
- Add
embeddings.embedding_vec (pgvector), backfill from existing CSV embeddings where dim matches.
- Keep
embeddings (CSV string) + embeddings_content (raw text) on the same row (link by PK).
- Dual-write on
add_embedding (CSV + vector + content).
- Cut over chatbot and existing similarity paths to pgvector on Postgres.
- Enable Librarian
CRE_LIBRARIAN_RETRIEVER_BACKEND=pgvector once migrated.
Locked decisions
| Decision |
Choice |
| Dim policy |
Single project-wide dim; migration hard-fails if multiple dims detected (alert clearly) |
| Migration backfill |
Idempotent CSV → embedding_vec only (WHERE embedding_vec IS NULL + dim match) |
| Re-run |
Safe/expected after failure or partial fill — re-run migration/backfill, not LLM re-embed |
| Re-embed on Heroku/prod |
Forbidden — likely OOM-killed; re-embed only on a high-memory machine, then sync/backfill |
| Multi-dim |
Exit fail migration; do not silently pick a majority dim |
Contributor warning (must land in code)
Near migration / embedding write / regenerate CLI:
Do not re-embed the full corpus on Heroku/production dynos — likely OOM-killed.
Re-embedding (fix missing / wrong-dim via LLM) must run only where there is enough RAM (local or high-resource worker), then sync/backfill vectors.
Alembic on prod only: enable extension, add column, copy CSV→vector for matching dims.
Implementation outline
-
Alembic (Postgres-only)
CREATE EXTENSION IF NOT EXISTS vector
- Detect dims; if ≠ 1 distinct → raise and abort
ADD COLUMN embedding_vec vector(N) with that N
- Idempotent backfill from CSV
embeddings
- Optional HNSW index (may defer on Essential-1)
- SQLite/CI: skip vector (CSV + in-memory fallback)
-
db.Embeddings + add_embedding — dual-write CSV + embedding_vec
-
Chat + existing match paths — prefer pgvector on Postgres; avoid pulling sklearn/numpy on Heroku for chat
-
Librarian — already queries embedding_vec; flip backend env after migrate
-
Verification
make alembic-guardrail before prod upgrade
- Backup:
scripts/db/backup-opencreorg.sh before prod migrate
- Tests: dual-write, multi-dim fail, idempotent backfill
- No re-embed in release/
Procfile
Success criteria
Out of scope
- Dropping the CSV
embeddings column
- Automatic LLM re-embed on deploy/Heroku
- Librarian W8 graph-write path (separate)
Context
Summary
Migrate existing embeddings to pgvector, keep the CSV/
embeddings_contentcolumns, and cut over chatbot + similarity matching (and Librarian C.1) to useembedding_vecon Postgres.This is a follow-on to the Heroku slug work (#975): drop app-side numpy/scipy/sklearn for prod chat matching by doing cosine in Postgres.
Related: Librarian C.1 already expects
embedding_vec+<=>(PR #937 by @PRAteek-singHWY); the W8 Alembic migration was never written. Prod DB is Heroku Postgresessential-1(pgvector extension supported; $0 for the extension itself).Local plan:
.cursor/plans/pgvector-migration.mdGoals
embeddings.embedding_vec(pgvector), backfill from existing CSVembeddingswhere dim matches.embeddings(CSV string) +embeddings_content(raw text) on the same row (link by PK).add_embedding(CSV + vector + content).CRE_LIBRARIAN_RETRIEVER_BACKEND=pgvectoronce migrated.Locked decisions
embedding_veconly (WHERE embedding_vec IS NULL+ dim match)Contributor warning (must land in code)
Near migration / embedding write / regenerate CLI:
Implementation outline
Alembic (Postgres-only)
CREATE EXTENSION IF NOT EXISTS vectorADD COLUMN embedding_vec vector(N)with that Nembeddingsdb.Embeddings+add_embedding— dual-write CSV +embedding_vecChat + existing match paths — prefer pgvector on Postgres; avoid pulling sklearn/numpy on Heroku for chat
Librarian — already queries
embedding_vec; flip backend env after migrateVerification
make alembic-guardrailbefore prod upgradescripts/db/backup-opencreorg.shbefore prod migrateProcfileSuccess criteria
embeddings_contentpreservedmake lint/make test/ alembic guardrail greenOut of scope
embeddingscolumnContext
PgVectorRetriever