feat(FN-5060): complete Step 2 — stabilize shared dedup guard exports

Fusion-Task-Id: FN-5060
Fusion-Task-Lineage: 35434cc4-583f-4e50-9ca3-c12546d220c1
This commit is contained in:
Fusion (runfusion.ai)
2026-05-18 20:02:52 -07:00
committed by gsxdsm
parent 65f9995b26
commit d5438ebc11
3 changed files with 19 additions and 4 deletions

View File

@@ -4,7 +4,7 @@ import { computeContentFingerprint } from "./duplicate-detection.js";
const DEFAULT_WINDOW_MS = 60_000;
const MAX_WINDOW_MS = 300_000;
const deterministicGuardLocks = new Map<string, Promise<void>>();
export const deterministicGuardLocks = new Map<string, Promise<void>>();
// Test-only compatibility hook used by dashboard deterministic-dedup route tests.
export const __deterministicGuardLocksForTests = deterministicGuardLocks;
@@ -59,7 +59,8 @@ export async function runDeterministicDuplicateGuard(
return { action: "duplicate", fingerprint, existing: deterministicConflict, releaseLock: noop };
}
} catch (error) {
opts?.logger?.warn("Deterministic duplicate pre-check failed; proceeding", {
opts?.logger?.warn("FN-5084 deterministic pre-check failed; proceeding", {
contentFingerprint: fingerprint,
error: error instanceof Error ? error.message : String(error),
});
}
@@ -69,7 +70,16 @@ export async function runDeterministicDuplicateGuard(
const lockKey = `${opts.lockScope}:${fingerprint}`;
const existingLock = deterministicGuardLocks.get(lockKey);
if (existingLock) {
await existingLock;
try {
await existingLock;
} catch (error) {
opts?.logger?.warn("FN-5084 deterministic lock wait failed; proceeding", {
lockKey,
contentFingerprint: fingerprint,
error: error instanceof Error ? error.message : String(error),
});
deterministicGuardLocks.delete(lockKey);
}
}
let releaseCalled = false;
@@ -98,8 +108,9 @@ export async function runDeterministicDuplicateGuard(
return { action: "duplicate", fingerprint, existing: deterministicConflict, releaseLock };
}
} catch (error) {
opts?.logger?.warn("Deterministic duplicate pre-check failed; proceeding", {
opts?.logger?.warn("FN-5084 deterministic pre-check failed; proceeding", {
lockKey,
contentFingerprint: fingerprint,
error: error instanceof Error ? error.message : String(error),
});
}

View File

@@ -141,6 +141,7 @@ export {
export { getTaskDuplicateLineage } from "./duplicate-lineage.js";
export {
__getDeterministicGuardMutexSize,
deterministicGuardLocks,
runDeterministicDuplicateGuard,
reconcileDeterministicDuplicate,
__deterministicGuardLocksForTests,

View File

@@ -25,6 +25,7 @@ import {
formatRoleMismatchReason,
getCurrentRepo,
findDuplicateMatches,
deterministicGuardLocks,
runDeterministicDuplicateGuard,
reconcileDeterministicDuplicate,
} from "@fusion/core";
@@ -41,6 +42,8 @@ const REVIEW_VERDICT_RE = /###\s+Verdict:\s*(APPROVE|REVISE|RETHINK|UNAVAILABLE)
const REVIEW_STEP_RE = /^(plan|code) review Step (\d+): (APPROVE|REVISE|RETHINK|UNAVAILABLE)\b/i;
const DUPLICATE_STOPWORDS = new Set(["a", "an", "the", "and", "or", "of", "to", "for", "in", "is", "on", "with", "fn"]);
export const __fingerprintCreateLocksForTests = deterministicGuardLocks;
function buildDuplicateQuery(title: string | undefined, description: string): string {
const tokens = `${title ?? ""} ${description}`
.toLowerCase()