✨ feat(search): ONNX embeddings + hybrid RRF ranking (#2905 Phase 2)
Phase 2 of GL !2905 — closes the search-first architecture work. Stacks on Phase 1 (FTS5 infra, !199 (merged) merged).
Three commits
cc35a9ba — Phase 2 main: ONNX embeddings + hybrid RRF + skill updates
- Schema v4 migration adds 3 embedding tables (
discussions_embeddings,audit_embeddings,file_registry_embeddings) with FK CASCADE where the source PK allows - NEW
src/embeddings/{model,store,backfill}.ts— lazy-loaded@huggingface/transformers+bge-small-en-v1.5(33MB, 384-dim); brute-force JS cosine over Float32 BLOBs; fire-and-forget backfill on server startup - 3 search tools gain
mode='keyword'|'semantic'|'hybrid'(defaulthybrid) — RRF over FTS5 + cosine + recency-decay - Inline embed on every source write (
discussion_append,audit_log,file_registry_*) — fire-and-forget post-write, never blocks - Skills (
tmb_planning193 /tmb_review199 /tmb_recovery131) get a one-paragraph search-first reference; all <200 LOC - Fallback: if
onnxruntime-nodefails to load, search degrades to FTS5-only withwarning: 'semantic_unavailable'— no hard failure - 53 new test assertions across embeddings.test.ts (12) + search.test.ts extended (26) + schema-upgrade.test.ts extended (15)
ee12cc33 — hook chmod fix
scripts/hooks/pr-reviewer-spawn-prompt-shape.sh missed the +x bit during the slim-skills (!198 (merged)) Write-based conflict resolution. Caught by L0 install-smoke's test -x scripts/hooks/*.sh check. One-line chmod +x.
8427fcfb — defensive migrations + L0 Dockerfile auto-tracking
Two L0-discovered bugs:
migrateV2toV3(Phase 1, !199 (merged)) andmigrateV3toV4(Phase 2) referenced base tables in CREATE statements. On a synthetic legacy-v1 fixture (L0 install-smoke seeds onlyplugin_meta+plugin_config+identity), the base tables don't exist yet — migrations crashed withno such table: discussions. Fix: wrap each per-source-table block intableExists()guards;applySchema's schema.sql re-run is the safety net.tests/docker/install-smoke.DockerfileA7 hardcodedschema_version = "2". Fix: readTARGET_SCHEMA_VERSIONfromdb.tsat build time so the assertion auto-tracks future bumps. Backup-file glob broadened topre-v*.bak.
Verification — ALL layers L0–L4 green; L5/L6 issues filed as follow-ups
| Layer | Result |
|---|---|
| L0 install-smoke | |
| L1 lints (26) | |
| L2 unit (438+) | |
| L3 integration | |
| L4 workflow-sim (5) | |
| L5 dogfood | kind='event' scorers — to be filed |
| L6 chain |
pr-reviewer
Verdict: PASS (attempt 2, validation_attempts id=28, loud audit trail with per-claim line citations).
Minor non-blocking note from pr-reviewer: file_registry_embeddings PK omits FK to file_registry (composite-PK source — (repo, path) — single-column FK to rowid isn't portable). Backfill repopulates after any deletion. Backlog candidate: add an AFTER DELETE trigger for orphan cleanup.
Plan after merge (per Human comment on !199 (merged))
After this MR merges, file separate v0.8.0 release-ceremony issue. Both the v0.6.x→v0.7.0-rc upgrade path (v2→v3→v4) and the fresh-DB v4 path are tested in L0 + L2 schema-upgrade tests, so the user-machine upgrade story is verified end-to-end.
Held for manual review per session pattern — no auto-merge.