test(FN-5152): cover same-millisecond near-duplicate finalize race

Fusion-Task-Id: FN-5152
Fusion-Task-Lineage: 954570d8-82e1-4519-a739-c52ee790d2db
This commit is contained in:
Fusion (runfusion.ai)
2026-05-19 11:16:33 -07:00
committed by gsxdsm
parent 80ffed7a47
commit 4d9068d927
2 changed files with 38 additions and 5 deletions

View File

@@ -148,4 +148,32 @@ describe("reliability interactions: near-duplicate intake", () => {
const updatedNewer = await fx.store.getTask(newer.id);
expect(updatedNewer.column).toBe("todo");
});
it("archives at most one sibling when both near-duplicates finalize in the same millisecond", async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-05-19T12:00:00.000Z"));
const fx = await createFixture();
fixtures.push(fx);
const first = await fx.store.createTask({
title: "Create PR routes missing handlers",
description: "Missing /api/tasks/:id/pr/options and /api/tasks/:id/pr/preflight and /api/tasks/:id/pr/generate-metadata",
});
const second = await fx.store.createTask({
title: "Missing handlers for create PR routes",
description: "GET /api/tasks/:id/pr/options and GET /api/tasks/:id/pr/preflight and POST /api/tasks/:id/pr/generate-metadata all fail",
});
const settings = await fx.store.getSettings();
await Promise.all([
(fx.triage as any).finalizeApprovedTask(first, basePrompt, settings, {}),
(fx.triage as any).finalizeApprovedTask(second, basePrompt, settings, {}),
]);
const refreshed = await fx.store.listTasks({ includeArchived: true });
const archived = refreshed.filter((task) => task.id === first.id || task.id === second.id).filter((task) => task.column === "archived");
expect(archived.length).toBeLessThanOrEqual(1);
vi.useRealTimers();
});
});

View File

@@ -2367,19 +2367,24 @@ export class TriageProcessor {
const taskCreatedAt = Date.parse(task.createdAt);
const candidatesById = new Map(candidates.map((candidate) => [candidate.id, candidate]));
const isStrictlyOlderOrTieCanonical = (candidate: NearDuplicateCandidate): boolean => {
if (candidate.createdAt < taskCreatedAt) return true;
if (candidate.createdAt > taskCreatedAt) return false;
return candidate.id.localeCompare(task.id, undefined, { numeric: true }) < 0;
};
const olderMatches = matches.filter((match) => {
const candidate = candidatesById.get(match.id);
return candidate ? candidate.createdAt <= taskCreatedAt : false;
return candidate ? isStrictlyOlderOrTieCanonical(candidate) : false;
});
const canonical = (olderMatches[0] ?? matches[0]);
const canonical = olderMatches[0] ?? matches[0];
const canonicalTask = candidatesById.get(canonical.id);
if (!canonicalTask) {
return;
}
// FN-5152: only archive the task being finalized when it is the newer-or-equal
// sibling. Older tasks never lose to a newer near-duplicate candidate.
if (taskCreatedAt >= canonicalTask.createdAt) {
// FN-5152: only archive the task being finalized when it is the newer sibling,
// or the tie-loser when both rows share the same millisecond timestamp.
if (isStrictlyOlderOrTieCanonical(canonicalTask)) {
await this.store.updateTask(task.id, {
sourceMetadataPatch: {
nearDuplicateOf: canonical.id,