Закрывает 4 Important issues из code-review Task 4 (a2c5374):
- #1 SupplierPortalClient: parse_url host validation → SupplierClientException
вместо silent cookie skip + false-positive SupplierAuthException
- #2 dispatch_sync(RefreshSupplierSessionJob) обёрнут try/catch (request retry +
loadSession) → raw exceptions translated в SupplierAuthException для
consistency с error taxonomy перед Task 5 real Playwright impl
- #3 RefreshSupplierSessionJob stub handle() теперь throws LogicException
с понятным сообщением (вместо silent no-op → confusing 'cache still empty'
error). После Task 5 — LogicException заменяется real Playwright code.
Снят final-модификатор класса (test override через container bind + Laravel
dispatchSync serialization не работает с anonymous classes).
- #5 SupplierProjectDto::equals → canonical order для workdays/regions
через sort в constructor (defense vs PG jsonb non-deterministic order).
Без этого Task 6 SyncJob false-positive обнаруживал бы diff где его нет
→ unnecessary updateProject HTTP calls.
+3 tests в SupplierPortalClientTest (malformed url, 2 retry-translation paths)
+2 tests в новом SupplierProjectDtoTest (order-independent equals + non-equal)
+1 stub-класс ThrowingRefreshSupplierSessionJob (anonymous classes несовместимы
с SerializesModels trait в dispatchSync).
Pest: 38/38 supplier-suite, 574/574 full suite (576 total, 2 skipped, +5 new
tests vs Task 4 baseline). PHPStan 0 errors. Pint clean.