fix(core): follow merged tombstones in the position lookup

A merged child still holds its (parent_id, position) slot under the unique
index, so skipping tombstones made every retry collide. Follow the tombstone
to the surviving work instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Winther
2026-10-30 19:32:27 +01:00
co-authored by Claude Opus 5.5
parent 437ca143e5
commit 50c115b4c7
3 changed files with 22 additions and 4 deletions
+5 -3
View File
@@ -4,6 +4,7 @@ import type { Db } from "@sttracker/db/db";
import { newId, nowIso } from "@sttracker/db/ids";
import {
createWorkIn,
finalWorkId,
findWorkByExternalIdsIn,
normalizePosition,
resolveAliasIn,
@@ -85,12 +86,13 @@ async function resolve(k: K, userId: string | null, hint: WorkHint, actor: strin
.select("id")
.where("parent_id", "=", parentId)
.where("position", "=", position)
.where("merged_into_id", "is", null)
.where("owner_user_id", "is", null)
.executeTakeFirst();
if (child) {
await updateWorkFromHintIn(k, child.id, hint, actor);
return { workId: child.id, created: false, draft: false };
// A merged tombstone still holds its (parent_id, position) slot: follow it to the surviving work.
const workId = await finalWorkId(k, child.id);
await updateWorkFromHintIn(k, workId, hint, actor);
return { workId, created: false, draft: false };
}
return { workId: await createWorkIn(k, { hint, parentId }, actor), created: true, draft: false };
}