[CL-RECOVERY] fix: убрать ложные срабатывания auto-close disposition эвристики #168

Merged
andrei merged 1 commit from agent/cto/pix-12986-terminal-disposition-fix into master 2026-07-04 13:14:26 +00:00
Owner

Что сделано

Исправлена regex-эвристика в server/src/services/recovery/service.ts (issueScopedTerminalDisposition / extractDeclaredHandoffTerminalDisposition), которая определяет итоговый статус задачи по тексту финального результата успешного запуска, когда агент не вызвал явный PATCH статуса.

Эвристика искала терминальные слова (done, завершен, выполнен, закрыт и т.д.) в радиусе 120 символов от идентификатора задачи, без проверки границы слова и без учёта отрицания.

Зачем

Обнаружено при аудите автономии (PIX-12986, 2026-07-04): задачи PIX-12935 (grantRole на Base mainnet) и PIX-12933 (пополнение gas-wallets) были автоматически закрыты системой как done, хотя агент явно написал в финальном summary in_progress, а реальное действие CEO (on-chain транзакция) ещё не произошло. Обе задачи — финансовые/on-chain блокеры, ожидающие ручного действия CEO.

Корень проблемы: слово завершен совпадало как подстрока внутри несвязанного слова завершения ("Сводка завершения heartbeat", то есть про завершение самого прогона, а не задачи), плюс не проверялось отрицание ("ещё не done", "не закрыто").

Последствие: ложное закрытие финансовых блокеров маскирует реальный статус ожидания CEO-решения и рвёт continuation path (задача была бы разбужена автоматически при ответе CEO, пока висит in_progress/blocked).

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

  • pnpm --filter @paperclipai/server typecheck — 0 ошибок
  • pnpm exec vitest run src/services/recovery/ — 34/34 тестов зелёные (было 27, +7 новых regression-тестов в terminal-disposition.test.ts)
  • Новые тесты воспроизводят точный текст из реальных запусков PIX-12935/PIX-12933 (verbatim resultJson.summary) и проверяют, что после фикса результат — null (не done), а также что реальные case (done, blocked) по-прежнему детектятся.

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

  • Эвристика остаётся basado на regex/расстоянии, не на полноценном NLP — экзотические формулировки всё ещё теоретически могут дать ложное срабатывание, но конкретный подтверждённый баг (substring-коллизия + игнорирование отрицания) закрыт.
  • Функции extractDeclaredHandoffTerminalDisposition и issueScopedTerminalDisposition переведены в export для тестируемости — публичный контракт модуля не менялся, только видимость.
  • PIX-12935 и PIX-12933 как issues уже некорректно закрыты done в БД до этого фикса — отдельно скорректированы вручную через API в рамках PIX-12986 (не через этот PR, т.к. это данные, а не код).
## Что сделано Исправлена regex-эвристика в `server/src/services/recovery/service.ts` (`issueScopedTerminalDisposition` / `extractDeclaredHandoffTerminalDisposition`), которая определяет итоговый статус задачи по тексту финального результата успешного запуска, когда агент не вызвал явный PATCH статуса. Эвристика искала терминальные слова (`done`, `завершен`, `выполнен`, `закрыт` и т.д.) в радиусе 120 символов от идентификатора задачи, без проверки границы слова и без учёта отрицания. ## Зачем Обнаружено при аудите автономии (PIX-12986, 2026-07-04): задачи PIX-12935 (`grantRole` на Base mainnet) и PIX-12933 (пополнение gas-wallets) были автоматически закрыты системой как `done`, хотя агент явно написал в финальном summary `in_progress`, а реальное действие CEO (on-chain транзакция) ещё не произошло. Обе задачи — финансовые/on-chain блокеры, ожидающие ручного действия CEO. Корень проблемы: слово `завершен` совпадало как подстрока внутри несвязанного слова `завершения` ("Сводка завершения heartbeat", то есть про завершение самого прогона, а не задачи), плюс не проверялось отрицание ("ещё не done", "не закрыто"). Последствие: ложное закрытие финансовых блокеров маскирует реальный статус ожидания CEO-решения и рвёт continuation path (задача была бы разбужена автоматически при ответе CEO, пока висит `in_progress`/`blocked`). ## План тестирования - `pnpm --filter @paperclipai/server typecheck` — 0 ошибок - `pnpm exec vitest run src/services/recovery/` — 34/34 тестов зелёные (было 27, +7 новых regression-тестов в `terminal-disposition.test.ts`) - Новые тесты воспроизводят точный текст из реальных запусков PIX-12935/PIX-12933 (verbatim `resultJson.summary`) и проверяют, что после фикса результат — `null` (не `done`), а также что реальные case (`done`, `blocked`) по-прежнему детектятся. ## Где могу ошибаться - Эвристика остаётся basado на regex/расстоянии, не на полноценном NLP — экзотические формулировки всё ещё теоретически могут дать ложное срабатывание, но конкретный подтверждённый баг (substring-коллизия + игнорирование отрицания) закрыт. - Функции `extractDeclaredHandoffTerminalDisposition` и `issueScopedTerminalDisposition` переведены в `export` для тестируемости — публичный контракт модуля не менялся, только видимость. - PIX-12935 и PIX-12933 как issues уже некорректно закрыты `done` в БД до этого фикса — отдельно скорректированы вручную через API в рамках PIX-12986 (не через этот PR, т.к. это данные, а не код).
fix(recovery): убрать ложные срабатывания в auto-close эвристике disposition
Some checks failed
security/pr-scan No security concerns detected
PR Quality Gates / PR Quality Gates (pull_request_target) Successful in 5s
Agents CI / Typecheck and Build (pull_request) Successful in 5m34s
Agents CI / API Tests (pull_request) Failing after 22s
8972c894fc
Регекс-эвристика issueScopedTerminalDisposition/extractDeclaredHandoffTerminalDisposition
не проверяла границы слов и отрицание, из-за чего PIX-12935 и PIX-12933 (финансовые
блокеры on-chain grantRole и gas-wallet funding) были автоматически закрыты как `done`,
хотя агент явно указал `in_progress` и реальное действие CEO ещё не выполнено.
Причина: слово "завершен" совпадало как подстрока в "завершения" (сводка о завершении
heartbeat, а не задачи), без учёта соседних кириллических символов и отрицания "не".

Добавлена проверка границы слова (не кириллический символ до/после совпадения) и
отрицания ("не X" перед терминальным словом), плюс regression-тесты на реальных
текстах из PIX-12935/PIX-12933.
andrei merged commit 701fd241eb into master 2026-07-04 13:14:26 +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!168
No description provided.