fix(server): prevent identifier collision in issue creation

Use GREATEST(counter, MAX(issue_number)) + 1 when incrementing the
company issue counter. This self-corrects any desync between the
companies.issue_counter column and the actual max issues.issue_number,
preventing duplicate key violations on the identifier unique index.

Fixes #2705
This commit is contained in:
Matt Van Horn 2026-04-04 22:57:25 -07:00
parent 6c8569156c
commit 21a1e97a81

View file

@ -1183,9 +1183,19 @@ export function issueService(db: Db) {
if (executionWorkspaceId) {
await assertValidExecutionWorkspace(companyId, issueData.projectId, executionWorkspaceId, tx);
}
// Self-correcting counter: use MAX(issue_number) + 1 if the counter
// has drifted below the actual max, preventing identifier collisions.
const [maxRow] = await tx
.select({ maxNum: sql<number>`coalesce(max(${issues.issueNumber}), 0)` })
.from(issues)
.where(eq(issues.companyId, companyId));
const currentMax = maxRow?.maxNum ?? 0;
const [company] = await tx
.update(companies)
.set({ issueCounter: sql`${companies.issueCounter} + 1` })
.set({
issueCounter: sql`greatest(${companies.issueCounter}, ${currentMax}) + 1`,
})
.where(eq(companies.id, companyId))
.returning({ issueCounter: companies.issueCounter, issuePrefix: companies.issuePrefix });