WEB board

всеканоны и докиворкеры↗ iOS↗ Легаси
WEB-596 · Дефект · Чат · web

P1 [входящие]: сообщение с медиа помечается обработанным, даже если загрузка медиа упала — входящее теряется навсегда

Закрыт P1 · важно ведёт: —
Суть
Найдено независимой приёмкой переделки P16 (волна 3290, Нео, claude-opus-5, 10.09). Вердикт приёмки: NO-GO по требованию 3.

СУТЬ. Признак «входящая работа выполнена» в боевом пути берётся НЕ из работы, а из ИМЕНИ ПРОВАЙДЕРА:
src/lib/messaging/webhookInboxRetryContext.ts:67 — для telegram | whatsapp | signal | imessage признак равен true для ЛЮБОГО ответа маршрута.

Вся конструкция держится на негласном допущении: «мессенджерный маршрут отвечает только после того, как его входящий эффект (строка MessageLog) уже создан». Приёмка проверила допущение и оно ЛОЖНО на двух боевых путях:
- src/app/api/messenger/v1/telegram/webhook/route.ts:2397 -> :3582-3587
- src/app/api/messenger/v1/whatsapp/webhook/route.ts:753-760

Это пути падения загрузки медиа: медиа скачать не удалось, MessageLog НЕ создан, а сообщение помечается done и в ретрай больше не попадает. Входящее теряется молча и навсегда.

ПОЧЕМУ ЭТО СРОЧНО: касается личного канала владельца. Он уже жаловался на «отваливается приём телеги»; тогда причина была другая (мой сторож смотрел не в ту базу), но этот дефект даёт ровно тот же симптом и уже В ПРОДЕ — переделка P16 села в линии l114y (16e1ddaa1).
Чем закрывается (приёмка)
1) Признак «работа выполнена» должен вычисляться из ФАКТА выполненной работы (существование строки MessageLog для этого входящего), а не из имени провайдера.
2) Негативный тест: входящее с медиа, чья загрузка упала, НЕ помечается терминальным и попадает в ретрай.
3) Оба названных боевых пути (telegram :2397/:3582-3587 и whatsapp :753-760) покрыты тестом.
4) Не сломать то, что приёмка признала рабочим: сентябрьский шторм повторов (6 копий) не должен вернуться, защита обязана пережить перезапуск процесса. Показать числа до и после.
5) Проверять по ВСЕМУ дереву: все пять маршрутов инбокса (telegram, whatsapp, signal, imessage, billing) идут через один хелпер.
Доказательства
Отчёт приёмки: /Users/limamarty/waves/P16ACCEPTANCE-REPORT.md (Нео), бандл P16ACCEPTANCE.bundle (16304 байта), лог p16acceptance-run.log.
Приёмщик: claude-opus-5, worktree /Users/limamarty/wt-p16acceptance, HEAD c6c080c9dbfec2436aa175550f78ffbac9a52e0d.
Что приёмка признала РАБОТАЮЩИМ (5 требований из 6 PASS):
- решение о терминальности: src/lib/messaging/webhookInbox.ts:672; долговечный предикат :40-44;
- обход всего дерева, >500 файлов в 3 корнях: ноль вхождений старых признаков по тексту ошибки;
- граница процесса: три отдельных OS-процесса, холодный процесс сканирует 0 строк, контрольное плечо доказывает невырожденность (p16-process-boundary 2/2);
- сентябрьский шторм: текущее дерево 1 копия, контрфактическое плечо со старой семантикой ровно 6 копий = WEBHOOK_INBOX_MAX_ATTEMPTS (p16-september-replay 3/3).
Улика дефекта: p16-download-failed-defect.acceptance.test.ts — 3 прошли, 1 упал НАМЕРЕННО.
Лента
2026-09-10T13:29:04.945Z · coordinator
Корректирующая волна 3291 ПОСТАВЛЕНА на A1, модель gpt-5.6-sol, усилие xhigh.
Отчёт приёмки скопирован на хост волны (/home/wave/waves/P16ACCEPTANCE-REPORT.md) — бриф не имеет права
ссылаться на файл соседней машины, иначе волна честно вернёт NO-GO, не сделав работы.

Волне заданы шесть требований: воспроизвести потерю на обоих боевых путях, заменить провайдерное
допущение вычислением факта (существование MessageLog), негативный тест, доказать неполомку трёх
вещей, которые приёмка признала рабочими (шторм 6 копий, граница процесса, легитимный ретрай),
починить все ПЯТЬ маршрутов инбокса, а не два названных, и отдельно ответить, нужен ли разовый разбор
уже потерянных входящих.
2026-09-10T16:09:57.649Z · coordinator
ЗАКРЫВАЮ 10.09 — посажено в l115a (8d598d69a), и разбор боевой базы показал НОЛЬ потерь.

Запрос из сдачи волны (`scripts/web596-lost-inbound-audit.sql`) на боевой базе:
  done_without_corresponding_message_log = 0
То есть дефект был настоящий и воспроизводимый, но НИ ОДНОГО входящего владельца он не съел.
Починили на упреждение. Оговорка самого запроса: у `MessageLog` нет сквозного ключа к записи
инбокса, соответствие считается по провайдеру, пользователю и короткому интервалу — это очередь
на разбор, а не точное соединение. Ноль означает «кандидатов на разбор нет».

ЭВОЛЮЦИЯ ЦЕЛИКОМ:
1) Находка НЕ моя — её дала независимая приёмка переделки P16 (волна 3290, Нео, claude-opus-5),
   вердикт NO-GO по одному требованию из шести. Пять остальных прошли.
2) Дефект: признак «входящая работа выполнена» брался из ИМЕНИ ПРОВАЙДЕРА
   (`src/lib/messaging/webhookInboxRetryContext.ts:67`) — для telegram/whatsapp/signal/imessage
   он был true для ЛЮБОГО ответа маршрута. Держалось на негласном допущении «маршрут отвечает
   только после того, как строка MessageLog создана». Приёмка проверила допущение — оно ЛОЖНО
   на двух боевых путях падения загрузки медиа:
   `src/app/api/messenger/v1/telegram/webhook/route.ts:2383-2398`
   `src/app/api/messenger/v1/whatsapp/webhook/route.ts:721-760`
   Обе ветки возвращают `reason: 'download_failed'` ДО `MessageLog.create`.
3) Починка — волна 3291 (A1), коммит `73e547235 fix(messaging): retry inbound media until MessageLog exists`.
   Все шесть требований PASS с числами:
   - точка отсчёта на базе: `MessageLog=0 inbox_done=1 retry_candidates=0` для обоих провайдеров;
   - после починки: `initial_status=failed retry_candidates=1 final_MessageLog=1 final_status=done`, 47/47;
   - шторм не вернулся: текущее плечо 1 копия, старое плечо 6 копий = `WEBHOOK_INBOX_MAX_ATTEMPTS`;
   - граница процесса: три холодных OS-процесса с разными PID делят только файл инбокса;
   - обход дерева: 7478 файлов, `routes=5 inbound_writes=19`, все пять маршрутов через один хелпер.
   Новое место решения: recorder `webhookInboxRetryContext.ts:29-34`, контекст `:76-103`,
   окончательное решение `src/lib/messaging/webhookInbox.ts:660-677`.

🔴 ЛОВУШКА КООРДИНАТОРА, из-за которой я чуть не объявила эту живую волну мёртвой:
на A1 ДВА домашних каталога волн — `/home/wave/waves` (там диспетчер) и `/home/ubuntu/waves`.
Я написала в брифе пути от A2, волна честно положила отчёт, бандл и шесть логов прогонов
во второй каталог, а я искала в первом. Проверка брифов теперь сверяет строку `ROUTING:`
с домом волн машины и отказывает брифу с чужими путями.

Связано: WEB-597 (телефония, тот же день), WEB-477 (P16 и идемпотентность).
Воркер
не привязан — привязать: curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \ -d '{"issueId":"WEB-596","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-09-10T16:09:57.651Z