[PIX-13084] fix(server): устранить гонку мока в issue-agent-mutation-ownership-routes.test.ts #189

Merged
andrei merged 1 commit from agent/fullstack/pix-13084 into master 2026-07-05 11:38:14 +00:00
Owner

Что сделано

  • В issue-agent-mutation-ownership-routes.test.ts заменил конкурентный Promise.all([vi.importActual(middleware), vi.importActual(routes/issues)]) на последовательные await — убрал единственное отличие этого файла от соседних (external-object-routes.test.ts, issue-attachment-routes.test.ts), где такой гонки не наблюдалось.
  • Добавил недостающий мок heartbeatService.cancelScheduledRetriesForIssue (нужен маршруту routes/issues.ts:6608), который раньше падал с TypeError: ... is not a function и глушился внутренним try/catch.

Зачем

CI-лог упавшего прогона (job 51272 / task 35830, API Tests) показал, что 11 из 62 тестов упали не из-за коллизии тестовых данных (литеральных UUID), а потому что реальный, немоканный сервисный код (taskWatchdogService.reconcileForIssueAndAncestors, heartbeat.cancelScheduledRetriesForIssue) исполнился поверх фейкового db-мока — vi.doMock("../services/index.js", ...) не успел примениться к моменту резолва маршрута. Отсюда db.execute is not a function в логах и цепочка assertion-failures (expected 200 to be 403, expected 422 to be 200 и т.п.) — реальные бизнес-правила (например, обязательный projectId) сработали вместо замоканных заглушек.

Это НЕ известная гонка act-runner (PIX-13081, "network not found") и НЕ дефект самого продакшен-кода — локально файл стабильно зелёный (62/62), в этом же CI-прогоне до и после падали/проходили десятки других route-suite файлов без проблем. Разница именно этого файла — конкурентный импорт двух самых больших модулей репо (routes/issues.ts ~8600 строк, middleware/index.js) в самом крупном route-suite (62 теста, ~90 вызовов createApp() за прогон), что даёт больше всего шансов поймать редкую гонку резолва модулей на перегруженном self-hosted раннере.

План тестирования

  • npx vitest run src/__tests__/issue-agent-mutation-ownership-routes.test.ts — 62/62 зелёные, WARN про "not a function" в логе больше нет.
  • pnpm --filter @paperclipai/server typecheck — 0 ошибок.
  • Полный pnpm typecheck (весь workspace) прогнан pre-push хуком — зелёный.

Где могу ошибаться

  • Это защитное снижение риска гонки (устранение конкурентного резолва модулей), а не 100%-доказанный root cause на уровне внутренностей Vitest/Vite — сама гонка нагрузочно-зависима и не воспроизводится локально по требованию.
  • Job "API Tests" уже помечен continue-on-error: true и НЕ входит в обязательные status checks для мержа в master (только "PR Quality Gates" и "Agents CI / Typecheck and Build") — то есть PR #187 фактически не блокируется этим падением технически, хотя создаёт шум в CI.
  • Аналогичный конкурентный Promise.all паттерн есть ещё в external-object-routes.test.ts и issue-attachment-routes.test.ts — они пока не падали в CI, поэтому намеренно не трогал их в этом PR (не относится к PIX-13084), но при повторении проблемы там стоит применить тот же фикс.
## Что сделано - В `issue-agent-mutation-ownership-routes.test.ts` заменил конкурентный `Promise.all([vi.importActual(middleware), vi.importActual(routes/issues)])` на последовательные `await` — убрал единственное отличие этого файла от соседних (`external-object-routes.test.ts`, `issue-attachment-routes.test.ts`), где такой гонки не наблюдалось. - Добавил недостающий мок `heartbeatService.cancelScheduledRetriesForIssue` (нужен маршруту `routes/issues.ts:6608`), который раньше падал с `TypeError: ... is not a function` и глушился внутренним `try/catch`. ## Зачем CI-лог упавшего прогона (job 51272 / task 35830, API Tests) показал, что 11 из 62 тестов упали не из-за коллизии тестовых данных (литеральных UUID), а потому что реальный, немоканный сервисный код (`taskWatchdogService.reconcileForIssueAndAncestors`, `heartbeat.cancelScheduledRetriesForIssue`) исполнился поверх фейкового `db`-мока — `vi.doMock("../services/index.js", ...)` не успел примениться к моменту резолва маршрута. Отсюда `db.execute is not a function` в логах и цепочка assertion-failures (`expected 200 to be 403`, `expected 422 to be 200` и т.п.) — реальные бизнес-правила (например, обязательный `projectId`) сработали вместо замоканных заглушек. Это НЕ известная гонка act-runner (PIX-13081, "network not found") и НЕ дефект самого продакшен-кода — локально файл стабильно зелёный (62/62), в этом же CI-прогоне до и после падали/проходили десятки других route-suite файлов без проблем. Разница именно этого файла — конкурентный импорт двух самых больших модулей репо (`routes/issues.ts` ~8600 строк, `middleware/index.js`) в самом крупном route-suite (62 теста, ~90 вызовов `createApp()` за прогон), что даёт больше всего шансов поймать редкую гонку резолва модулей на перегруженном self-hosted раннере. ## План тестирования - `npx vitest run src/__tests__/issue-agent-mutation-ownership-routes.test.ts` — 62/62 зелёные, WARN про "not a function" в логе больше нет. - `pnpm --filter @paperclipai/server typecheck` — 0 ошибок. - Полный `pnpm typecheck` (весь workspace) прогнан pre-push хуком — зелёный. ## Где могу ошибаться - Это защитное снижение риска гонки (устранение конкурентного резолва модулей), а не 100%-доказанный root cause на уровне внутренностей Vitest/Vite — сама гонка нагрузочно-зависима и не воспроизводится локально по требованию. - Job "API Tests" уже помечен `continue-on-error: true` и НЕ входит в обязательные status checks для мержа в master (только "PR Quality Gates" и "Agents CI / Typecheck and Build") — то есть PR #187 фактически не блокируется этим падением технически, хотя создаёт шум в CI. - Аналогичный конкурентный `Promise.all` паттерн есть ещё в `external-object-routes.test.ts` и `issue-attachment-routes.test.ts` — они пока не падали в CI, поэтому намеренно не трогал их в этом PR (не относится к PIX-13084), но при повторении проблемы там стоит применить тот же фикс.
fix(server): устранить гонку мока в issue-agent-mutation-ownership-routes.test.ts (PIX-13084)
Some checks failed
security/pr-scan No security concerns detected
PR Quality Gates / PR Quality Gates (pull_request_target) Successful in 4s
Agents CI / Typecheck and Build (pull_request) Successful in 6m21s
Agents CI / API Tests (pull_request) Failing after 1m51s
e4012b4bb8
CI-лог job 51272/task 35830 показал, что при 11 падениях в файле реально
выполнялся немоканный сервисный код (taskWatchdogService.reconcileForIssueAndAncestors
и heartbeat.cancelScheduledRetriesForIssue) поверх фейкового db — то есть
vi.doMock("../services/index.js", ...) не применился к моменту резолва
маршрута. Единственное отличие этого файла от похожих (external-object-routes,
issue-attachment-routes) — конкурентный Promise.all([vi.importActual(middleware),
vi.importActual(routes/issues)]) для двух самых крупных модулей в самом большом
route-suite (62 теста, ~90 вызовов createApp() за прогон). Заменил на
последовательные await, убрав окно для гонки резолва модулей на нагруженном раннере.

Заодно добавил недостающий мок heartbeatService.cancelScheduledRetriesForIssue
(routes/issues.ts:6608) — раньше вызов падал с "not a function" и глушился
try/catch, оставляя WARN в логах теста без явного покрытия.
andrei merged commit 056b0b30d7 into master 2026-07-05 11:38:14 +00:00
andrei deleted branch agent/fullstack/pix-13084 2026-07-05 11:38:14 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
europa-tech-srl/europa-tech-agents!189
No description provided.