FN-8047: migrate AgentStore multi-node tests to PostgreSQL

Migrate multi-node AgentStore coverage to shared PostgreSQL-backed fixtures.

- Make concurrent central claim insertion resolve unique-key races as checkout conflicts.
- Rework claim and owning-node handoff tests to use shared async PostgreSQL layers.
- Restore PostgreSQL-compatible tests from the quarantine ledger.

Files changed:
 packages/core/src/async-central-db.ts              |  9 ++-
 .../cross-node-claim-mutex.integration.test.ts     | 72 ++++++++++---------
 .../distributed-claim-mutex.integration.test.ts    | 27 +++----
 .../owning-node-handoff.integration.test.ts        | 41 +++++------
 .../__tests__/reliability-interactions/_helpers.ts | 83 ++++++++++++++++++++--
 .../multi-node-claim-mutex-interactions.test.ts    | 28 +++-----
 .../owning-node-unavailable-interactions.test.ts   | 36 +++++-----
 packages/engine/vitest.config.ts                   |  8 +--
 scripts/lib/test-quarantine.json                   | 25 -------
 9 files changed, 180 insertions(+), 149 deletions(-)

Fusion-Task-Id: FN-8047

Fusion-Task-Lineage: 3b7ee21e-0190-4364-a0cb-88aac5e2e1a3

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-16 05:33:55 -07:00
parent 92a8dc8325
commit 969fce7aa1
9 changed files with 177 additions and 146 deletions

View File

@@ -172,6 +172,10 @@ export async function tryClaimTask(
const now = input.renewedAt;
if (!existing) {
/*
FNXC:AsyncCentralClaims 2026-07-16-10:55:
FN-8047 requires concurrent first claims from separate nodes to produce one winner and a normal conflict for the loser. PostgreSQL transactions can both observe an absent row, so make the unique-key collision non-throwing and classify the persisted winner below instead of leaking a database constraint error through AgentStore checkout.
*/
await tx.insert(schema.central.taskClaims).values({
projectId: input.projectId,
taskId: input.taskId,
@@ -182,11 +186,14 @@ export async function tryClaimTask(
leaseRenewedAt: now,
createdAt: now,
updatedAt: now,
});
}).onConflictDoNothing();
const claim = await getTaskClaim(tx, input.projectId, input.taskId);
if (!claim) {
throw new Error("Task claim insert succeeded but row could not be read back");
}
if (claim.ownerNodeId !== input.nodeId || claim.ownerAgentId !== input.agentId) {
return { ok: false, reason: "conflict", current: claim };
}
return { ok: true, claim };
}