diff --git a/packages/core/src/__tests__/duplicate-intake.test.ts b/packages/core/src/__tests__/duplicate-intake.test.ts index 0b75d2e579..29d4f4a17a 100644 --- a/packages/core/src/__tests__/duplicate-intake.test.ts +++ b/packages/core/src/__tests__/duplicate-intake.test.ts @@ -180,6 +180,24 @@ describe("findSameAgentDuplicates", () => { expect(first).toBe(second); }); + it("never anchors on dates or UUIDs, and a date never outranks a file-path anchor", () => { + expect(computeCrossParentDiagnosticClaimId({ + description: "Fix nightly build failure observed on 2026-07-22 in the settings modal", + })).toBeNull(); + expect(computeCrossParentDiagnosticClaimId({ + description: "Fix failed run d3be2cd6-9221-4e1d-a27a-c5fbe04f9200 stuck in merge", + })).toBeNull(); + + const withDate = computeCrossParentDiagnosticClaimId({ + description: "Fix typecheck error in packages/core/src/store.ts since 2026-07-22", + }); + const withoutDate = computeCrossParentDiagnosticClaimId({ + description: "Fix typecheck error in packages/core/src/store.ts", + }); + expect(withDate).not.toBeNull(); + expect(withDate).toBe(withoutDate); + }); + it("does not claim ordinary work that merely names a file path", () => { expect(computeCrossParentDiagnosticClaimId({ description: "Add caching to packages/core/src/store.ts for faster board loads", diff --git a/packages/core/src/duplicate-intake.ts b/packages/core/src/duplicate-intake.ts index d7083132c8..dc6e0e7c14 100644 --- a/packages/core/src/duplicate-intake.ts +++ b/packages/core/src/duplicate-intake.ts @@ -121,8 +121,16 @@ function normalizeDiagnosticObject(value: string): string | null { return /[0-9@./_-]/.test(normalized) ? normalized : null; } +/* +FNXC:TaskCreationDeduplication 2026-07-22-15:20: +A distinctive slug must have at least one non-hex segment. Dates ("2026-07-22") and +UUIDs are hyphen-shaped but identify WHEN/WHICH RUN, not WHAT is broken: two unrelated +failure reports quoting the same date must not silently converge into one task, and a +date must never outrank a real file-path anchor in the sorted-first object pick. +*/ function isDistinctiveSlug(value: string): boolean { - return /^[a-z0-9]+(?:-[a-z0-9]+){2,}$/.test(value); + return /^[a-z0-9]+(?:-[a-z0-9]+){2,}$/.test(value) + && value.split("-").some((segment) => !/^[0-9a-f]+$/.test(segment)); } function normalizeDiagnosticPath(value: string): string { diff --git a/packages/dashboard/app/components/TaskTokenStatsPanel.tsx b/packages/dashboard/app/components/TaskTokenStatsPanel.tsx index b478316ed7..c6f5f73e20 100644 --- a/packages/dashboard/app/components/TaskTokenStatsPanel.tsx +++ b/packages/dashboard/app/components/TaskTokenStatsPanel.tsx @@ -306,13 +306,23 @@ export function TaskTokenStatsPanel({ tokenUsage, loading, task }: TaskTokenStat