1ba1df8df1
Закрывает CV.11 audit BLOCKER #3 (Plan 2/5 closure). Проблема: $tries=3 на retry-сценарий (DB hiccup, queue worker restart) — handle() запускался повторно без guard'а на $lead->processed_at. Второй проход создавал ВТОРОЙ Deal в БД с тем же vid (DuplicateDetector помечал его дублем без charge, но deal-row оставался). Также $lead->update(['deals_created_count' => $createdCount]) переписывал счётчик: первый run = 1, второй run = 0 (все дубли) → искажение метрики. Fix: в начале handle() после findOrFail — if ($lead->processed_at !== null) return; + Log::info с processed_at и deals_created_count для диагностики. TDD: новый тест 'idempotent on retry — second handle() returns early, no ghost duplicate deals' (RouteSupplierLeadJobTest:271). Проверяет 2 последовательных вызова runRouteJob — assertion на Deal::count, balance_leads, delivered_today, deals_created_count все остаются на 1st-run значениях. Pest: 548/546 passed (+1 тест от baseline 547), 1740 assertions, 17s parallel. Larastan + Pint: passed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>