Part of #4325.
Context
src/review/rag-index.ts's cron-triggered indexRepo (the full re-index job, :266-317) unconditionally re-chunks and re-embeds EVERY indexable file in every registered repo on every cycle — unlike reindexChangedPaths (:336), which is correctly scoped to only the paths that actually changed. Since bge-m3 embeddings are deterministic (same input text → same vector), this means the GPU spends real compute re-embedding files whose content is byte-identical to the last cycle, which is typically the vast majority of files in any repo between cron ticks.
Requirements
- Store a per-chunk content hash (e.g. alongside the existing chunk-text row, or as a new column) computed the same way for every indexing path.
- Before calling
embedTexts (src/review/rag.ts:294) for a chunk, check whether its content hash already has a stored, valid embedding — skip the embed call and reuse the existing vector when it matches.
src/selfhost/redis-cache.ts already has claim/release and dedup primitives for exactly this shape (webhook-delivery dedup) — reuse that pattern rather than inventing a new caching mechanism, OR do the hash check directly against the existing Postgres/D1 chunk-storage table if that's simpler and avoids a Redis round-trip per chunk. Pick whichever fits the existing RagInfra/upsertChunks shape with the least new surface area — this issue should record the choice and why.
- Must not change retrieval behavior or output — this is purely an internal optimization; a repo's retrieved context before/after this change must be identical for identical input content.
- Measure and record: embedding-call volume before/after on a real repo's full re-index cycle (should show a large drop for a repo with mostly-unchanged content between cycles).
Deliverables
Expected outcome
A measurable reduction (targeting >80-90% on typical repos) in redundant GPU embedding calls during scheduled full re-index cycles, with zero change to retrieval quality or output.
Effort
M
Part of #4325.
Context
src/review/rag-index.ts's cron-triggeredindexRepo(the full re-index job,:266-317) unconditionally re-chunks and re-embeds EVERY indexable file in every registered repo on every cycle — unlikereindexChangedPaths(:336), which is correctly scoped to only the paths that actually changed. Sincebge-m3embeddings are deterministic (same input text → same vector), this means the GPU spends real compute re-embedding files whose content is byte-identical to the last cycle, which is typically the vast majority of files in any repo between cron ticks.Requirements
embedTexts(src/review/rag.ts:294) for a chunk, check whether its content hash already has a stored, valid embedding — skip the embed call and reuse the existing vector when it matches.src/selfhost/redis-cache.tsalready has claim/release and dedup primitives for exactly this shape (webhook-delivery dedup) — reuse that pattern rather than inventing a new caching mechanism, OR do the hash check directly against the existing Postgres/D1 chunk-storage table if that's simpler and avoids a Redis round-trip per chunk. Pick whichever fits the existingRagInfra/upsertChunksshape with the least new surface area — this issue should record the choice and why.Deliverables
rag-index.ts'sindexRepo)embedTextsentirely; a chunk with a changed/new hash still embeds; a corrupted/missing cached vector falls back to re-embedding (fail-safe, never silently skips a chunk that has no real vector)Expected outcome
A measurable reduction (targeting >80-90% on typical repos) in redundant GPU embedding calls during scheduled full re-index cycles, with zero change to retrieval quality or output.
Effort
M