WEB board

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

Telegram voice: durable retry после transient transcription failure

Закрыт P1 · важно ведёт: a1-fix-wave
Суть
## Доказанный production symptom — 21.08
- Telegram update 793650686 дошёл до webhook; MessageLog cmt3g277o001q14obzew8slvi создан до vendor call и честно помечен failed.
- media_transcribe / gpt-4o-mini-transcribe получил VendorCallRejectedError: accounting_unhealthy (HTTP 503). Это следствие WEB-308 fail-closed epoch, не отдельный Whisper outage.
- Дефект устойчивости: route сохраняет receipt/status/error, но не сохраняет Telegram file_id или аудиобайты. parsedMessage.mediaUrl временный и содержит bot token, хранить его нельзя. После ответа webhook Telegram Bot API не даёт getMessage; getUpdates занят canonical webhook.
- Поэтому новые voice снова заработают после WEB-308, но конкретный failed audio нельзя автоматически переиграть — owner должен переслать его.

## Scope
- Durable non-secret retry reference/media with bounded retention.
- Same billing gateway and durable request identity; no bypass и no direct SQL.
- Duplicate update/retry must not create a second paid dispatch or MessageLog row.
- Terminal failure explicit; no silent catch; additive migration only if unavoidable.

## Worker brief
- ~/Downloads/WORKER-BRIEFS-20260821/VOICE-RETRY-CODEX.md
- Planned isolated M4 Codex implementation after clean source snapshot; no deploy/apply/commit/push.

## 21.08 22:04 UTC — owner подтвердил: Telegram voice всё ещё не работает
Новый inbound текст `cmt3hz72m003p14ob03qlwbpf` processed: «голос телеги не работает еще». Последний настоящий voice остаётся `cmt3g277o001q14obzew8slvi` (21:11:12Z): status=failed, content=[voice] transcription pending, error `stage=billing_gateway class=VendorCallRejectedError guard=accounting_unhealthy http=503`. Journal подтверждает: `media_transcribe/gpt-4o-mini-transcribe` отклонён закрытым accounting gate; fallback `whisper-1` вне allowlist.

То есть Telegram webhook и сохранение receipt работают; ломается платная транскрипция до vendor-вызова. Это всё ещё зависимость от WEB-308. Конкретный аудиофайл автоматически не восстановить: route не сохранил безопасный durable file_id/байты; после paidReady=true owner должен переслать. Durable retry scope этого тикета остаётся обязательным, чтобы следующий transient отказ не терял payload.

## 21.08 23:16 UTC — свежий живой voice FAIL, зависимость от WEB-308 подтверждена
Owner отправил новый voice. MessageLog id `cmt3kiyug005n14ob19716jjl`, createdAt `2026-08-21 23:16:13.673Z`, status `failed`. Файл принят webhook, но транскрипция остановлена ДО vendor call: `stage=billing_gateway class=VendorCallRejectedError guard=accounting_unhealthy http=503`. Пользователь видит «Не удалось расшифровать…». Это не потеря audio и не webhook-дефект; пока `paidReady=false`, speech-to-text fail-closed. После WEB-308 / `paidReady=true` обязателен новый resend и доказательство `processed` с текстом.

## 22.08 10:18 UTC — exact current failure is durable inbound receipt before paid transcription gate
MessageLog contains two recent inbound voice rows, so Telegram webhook/delivery is alive: 2026-08-21 21:11:12.900Z and 23:16:13.673Z. Both are status=failed, content=[voice] transcription pending, error stage=billing_gateway class=VendorCallRejectedError guard=accounting_unhealthy http=503. Thus bytes/message reached the product but paid gpt-4o-mini-transcribe was refused before vendor call while WEB-308 accounting gate is closed. Owner must resend after paidReady=true unless WEB-310 durable retry replays the retained media. This is distinct from older 11:05Z unsupported oga failure.

## 22.08 12:02 UTC — voice boundary unchanged; root remains paid gate
No new inbound voice after 11:00Z. Service health 200 but paidReady=false on reconstructed accounting_truth; egress direct-deny self-check PASS. Two prior Telegram voice rows remain failed before vendor transcription and need durable replay proof or owner resend after paidReady=true. Actual accounting rows are terminal (incidents REPAIRED=7, outbox RESOLVED=7); blocker is operator-held startup cause, not live monetary backlog.

## 22.08 15:41Z — WEB-308 green; fresh voice proof still absent
- WEB-308 is now done and live paid readiness is HTTP 200 / paidReady=true / failures=[]; the reconcile timer remains green.
- No new inbound Telegram voice has arrived after the gate opened. The newest inbound at 15:41:04Z is text asking whether voice should work.
- Therefore the expected dependency is removed, but voice is not yet live-proven. Owner was asked to resend one voice; it must create a processed MessageLog row with transcript rather than billing_gateway/accounting_unhealthy.
- Earlier failed voice rows cannot replay automatically because the route did not retain a durable non-secret media reference. WEB-310 stays in_progress until fresh proof and the durable retry scope are both resolved.
- Owner notification: message_id 12805.

## 22.08 15:51:33Z — fresh post-WEB-308 voice processed
- Owner resent a new Telegram voice after paid readiness became green.
- MessageLog id `cmt4k2z34001vg8ptdgky4un8`, type `voice`, createdAt `2026-08-22 15:51:33.664Z`.
- Terminal state is `processed`; recognized content exactly matches the owner's question; error is empty.
- Live journal contains the `media_transcribe` path and subsequent Telegram handling. This is the first post-WEB-308 proof that new voice transcription works through the paid gate.
- WEB-310 remains `in_progress`: this successful fresh message removes the current availability symptom, but does not implement durable retry for a future transient failure, and old failed audio still cannot replay automatically.
- Owner notified in Telegram: message_id 12808.

## 2026-08-23 BOARDSWEEP: DEAD-SOUL-CLAIM
- Evidence: updatedAt=2026-08-22T15:53:00.663Z, older than 24h; body has only a planned worker brief and no active voice-retry wave/process. Candidate for return to todo; status unchanged.
- buildFixed: <empty>; canonical: v4-081ff4fb5 / 081ff4fb5f6110f8001daec7ed910ccef2e395dc.
- Status preserved by sweep: in_progress.

## 2026-08-23 UTC — WEB-310 FIX READY
- Durable Telegram voice retry реализован в worktree `/home/ubuntu/waves/wt-web310`.
- Commit: `ef039e861`; patch: `/home/ubuntu/waves/WEB-310-fix.patch`; report: `/home/ubuntu/waves/WEB-310-FIX-REPORT.md`.
- `AgentTask` payload хранит только server-side-safe Telegram `file_id`; dedupe key по `chatId/messageId`; backoff 60/120/240s; cap 3; после cap — честное сообщение в тот же chat.
- Tests: ESLint rc=0; Prisma validate rc=0; type-check rc=0; targeted tests 10/10 rc=0. Negative: permanent failure → cap → one notification; transient failure → retry → success.
- Не деплоил, статус тикета не менял, live/provider calls не запускал.

WEB310_FIX_READY

## 2026-08-23 UTC — WEB-310 FINAL ARTIFACT HASH
- Functional fix commit amended for whitespace-only cleanup: `5ca2cb54e`.
- Final patch is `/home/ubuntu/waves/WEB-310-fix.patch` (637 lines); report is `/home/ubuntu/waves/WEB-310-FIX-REPORT.md`.
- Existing `WEB310_FIX_READY` marker retained; status intentionally unchanged.

## 2026-08-23 UTC — WEB-310 FINAL COMPATIBILITY FIX
- Final commit: `36e44be97`; retained backward-compatible `reason: voice_transcription_failed` and added `retryQueued` so existing WEB-051 contract remains green while durable retry is reported by status.
- Final patch: `/home/ubuntu/waves/WEB-310-fix.patch` (639 lines); targeted tests 10/10 rc=0.
- Existing `WEB310_FIX_READY` marker retained; status intentionally unchanged.
Доказательства

[2026-08-24 STALEREV против 61bc04462; в проде с посадки 45 v4-5a4edbac3] Вердикт SERVED: реализация+тесты доказаны в target tree; принято по приёмке 45-тикетного разбора. Отчёт: A1 /home/ubuntu/waves/STALEREVIEW-REPORT.md (STALEREVIEW_DONE).
Починено в
v4-5a4edbac3
Воркер
не привязан — привязать: curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \ -d '{"issueId":"WEB-310","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-08-24T14:29:00.483Z