fix(embeddings): use MERGE instead of CREATE for CodeEmbedding inserts

CREATE fails with duplicate PK when a CodeEmbedding node already exists,
which happens when:
- A PostToolUse hook triggers a concurrent gitnexus analyze during an
  active analyze run (git commits fire the hook)
- A partial prior run left some embeddings in the DB before a crash

Switching to MERGE makes the insert idempotent: existing embeddings are
updated in place, new ones are created, no PK violations.

Fixes: #822
This commit is contained in:
jonasvanderhaegen-xve 2026-04-14 12:59:14 +02:00
parent 41844edf88
commit 8d38cc99fa
2 changed files with 3 additions and 3 deletions

View file

@ -100,8 +100,8 @@ const batchInsertEmbeddings = async (
) => Promise<void>,
updates: Array<{ id: string; embedding: number[] }>,
): Promise<void> => {
// INSERT into separate embedding table - much more memory efficient!
const cypher = `CREATE (e:CodeEmbedding {nodeId: $nodeId, embedding: $embedding})`;
// MERGE instead of CREATE — idempotent, handles concurrent analyzes and partial prior runs
const cypher = `MERGE (e:CodeEmbedding {nodeId: $nodeId}) SET e.embedding = $embedding`;
const paramsList = updates.map((u) => ({ nodeId: u.id, embedding: u.embedding }));
await executeWithReusedStatement(cypher, paramsList);
};

View file

@ -222,7 +222,7 @@ export async function runFullAnalysis(
const paramsList = batch.map((e) => ({ nodeId: e.nodeId, embedding: e.embedding }));
try {
await executeWithReusedStatement(
`CREATE (e:CodeEmbedding {nodeId: $nodeId, embedding: $embedding})`,
`MERGE (e:CodeEmbedding {nodeId: $nodeId}) SET e.embedding = $embedding`,
paramsList,
);
} catch {