From 291a8279bde6513f1fda8acb542af054ed47eec8 Mon Sep 17 00:00:00 2001 From: Kelly Date: Sat, 13 Dec 2025 00:46:10 -0700 Subject: [PATCH] fix(entry-point-discovery): Self-healing duplicate detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When resolving platform_dispensary_id, check if it already exists on another dispensary. If so, mark current dispensary as duplicate instead of failing with unique constraint violation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../tasks/handlers/entry-point-discovery.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/backend/src/tasks/handlers/entry-point-discovery.ts b/backend/src/tasks/handlers/entry-point-discovery.ts index ea2d3c43..05584482 100644 --- a/backend/src/tasks/handlers/entry-point-discovery.ts +++ b/backend/src/tasks/handlers/entry-point-discovery.ts @@ -501,6 +501,35 @@ async function updateDispensaryWithPlatformId( source: string, slug: string ): Promise { + // Self-healing: Check if platform_dispensary_id already exists on another dispensary + const existingResult = await pool.query(` + SELECT id, name FROM dispensaries + WHERE platform_dispensary_id = $1 AND id != $2 + `, [platformId, dispensaryId]); + + if (existingResult.rows.length > 0) { + const existing = existingResult.rows[0]; + console.log(`[EntryPointDiscovery] Platform ID ${platformId} already exists on dispensary ${existing.id} (${existing.name})`); + console.log(`[EntryPointDiscovery] Marking dispensary ${dispensaryId} as duplicate of ${existing.id}`); + + // Mark current dispensary as duplicate and disable it + await pool.query(` + UPDATE dispensaries + SET + id_resolution_status = 'duplicate', + id_resolution_error = $2, + crawl_enabled = false, + stage = 'duplicate', + updated_at = NOW(), + last_modified_at = NOW(), + last_modified_by_task = $3, + last_modified_task_id = $4 + WHERE id = $1 + `, [dispensaryId, `Duplicate of dispensary ${existing.id} (${existing.name})`, task.role, task.id]); + + return; // Don't queue product_discovery for duplicates + } + // Update dispensary with platform ID and stage checkpoint // Stage transitions: discovered/validated → promoted (ready for crawling) await pool.query(`