From b55588f29be0de02639bc795801e55b89f03aad7 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Thu, 8 Oct 2026 14:30:54 +0700 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=D0=BE=D0=B1=D1=8A=D1=8F=D1=81=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BD=D0=B5=D0=BF=D0=BE=D0=B4=D1=82=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=B6=D0=B4=D1=91=D0=BD=D0=BD=D1=8B=D0=B9=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B7=D1=83=D0=BB=D1=8C=D1=82=D0=B0=D1=82=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B2=D1=82=D0=BE=D1=80=D0=B0=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/alerts-outbox-panel.tsx | 7 ++++++- docs/ux-ui-external-acceptance.md | 10 ++++++++++ docs/ux-ui-plan.md | 4 ++-- docs/ux-ui-progress.md | 12 +++++++++++- docs/ux-ui-stage-12.md | 12 +++++++++++- docs/ux-ui-test-server.md | 10 ++++++++++ ...box-retry-explained-local-320-2026-10-08.png | Bin 0 -> 35713 bytes tests/e2e/alerts-outbox.spec.ts | 14 ++++++++++++++ 8 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 docs/ux-ui/screens/outbox-retry-explained-local-320-2026-10-08.png diff --git a/components/alerts-outbox-panel.tsx b/components/alerts-outbox-panel.tsx index 07e408ca..d7ba96a5 100644 --- a/components/alerts-outbox-panel.tsx +++ b/components/alerts-outbox-panel.tsx @@ -30,7 +30,12 @@ export function AlertsOutboxPanel({base,operationsBusy,available,beginOperation, const requestRevision=++writeRevision.current,abort=new AbortController();writeController.current=abort;setOutboxPending(source,true) const current=()=>active.current&&requestRevision===writeRevision.current try{await retryAlertsOutbox(base,selected.id,{expectedVersion:selected.resolutionVersion,acknowledgedDuplicateRisk:true},{signal:abort.signal});if(current()){setOutboxPending(source,false);setSelected(null);setMessage("Сообщение поставлено в очередь. Отправка и доставка ещё не подтверждены.");void refresh()}} - catch(e){if(current()){if(e instanceof ApiClientError&&[400,401,403,409,422].includes(e.status))setOutboxPending(source,false);setMutationError(e instanceof Error?e.message:"Результат повтора неизвестен")}} + catch(e){if(current()){ + const rejected=e instanceof ApiClientError&&[400,401,403,409,422].includes(e.status) + if(rejected)setOutboxPending(source,false) + const detail=e instanceof Error?e.message:"Ответ не получен" + setMutationError(rejected?detail:"Результат повтора не подтверждён. Автоматический повтор заблокирован. Проверьте очередь и чат перед новой попыткой. "+detail) + }} finally{mutationLock.current=false;endOperation();if(current())setMutationBusy(false)} } return
void refresh()}>Обновить} contentClassName="space-y-3 px-5 py-4"> diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index bf0cf9d8..c4017e38 100644 --- a/docs/ux-ui-external-acceptance.md +++ b/docs/ux-ui-external-acceptance.md @@ -253,3 +253,13 @@ GET outbox: anonymous, неверные issuer/signature, expired и malformed Скриншоты просмотрены: [предупреждение после перезагрузки](ux-ui/screens/outbox-retry-checkpoint-real-320-2026-10-08.png), [диалог после HTTP500](ux-ui/screens/outbox-retry-unknown-real-320-2026-10-08.png). Первое тестовое ожидание внутреннего текста исключения исправлено на штатный production текст «Внутренняя ошибка сервера»; приложение не обязано раскрывать исключение. При пересоздании fixture первый прогон очищен с exitCode0. Итоговые контейнеры/сеть/туннель3018 удалены, backend exitCode0, независимый SQL подтвердил ноль fixture-строк. Основной стенд и RouterOS не менялись. Границы: управляемый отказ получения receipt после фактического COMMIT, а не физический разрыв сети; AUTH_REQUIRED=false; реальных сообщений и проверки чата нет. Найдена UX-недоработка: внутри открытого диалога generic HTTP500 не объясняет неизвестный исход текущего повтора. Следующий блок 12.5.44 — явное пояснение и профильная проверка диалога. Локальный коммит без push. + +## 12.5.44 — понятное пояснение неподтверждённого повтора в диалоге (2026-10-08) + +По результатам реального теста12.5.43 уточнён catch в components/alerts-outbox-panel.tsx. При HTTP500, потере ответа или некорректном receipt ошибка прямо в открытом диалоге сообщает: «Результат повтора не подтверждён. Автоматический повтор заблокирован. Проверьте очередь и чат перед новой попыткой», затем показывает подробность ошибки. API400/401/403/409/422 остаются подтверждёнными отказами: checkpoint снимается, исходная ошибка сохраняется. Правила повторной отправки, права и API не менялись. + +Профильный Playwright alerts-outbox.spec.ts:8/8, включая новый HTTP500 сценарий, сохранённый checkbox, disabled retry, reload guard и320px; прежние success, malformed receipt, reader, conflict и focus/cancel проходят. Eslint изменённых файлов и tsc --project tmp/tsconfig-speed-check.json --noEmit passed. Scoped config исключает старые копии исходников в tmp; это не утверждение о чистоте обычного полного tsc. [Локальный диалог320px](ux-ui/screens/outbox-retry-explained-local-320-2026-10-08.png) просмотрен. HTTP-ответы в этих локальных браузерных тестах подменены; реальные SQL/HTTP результаты43 сохраняются отдельно. + +Применён skill ReUI и MCP get_audit_checklist: композиция, установленные primitives, base-nova и semantic tokens сохранены; новых API/стилей/компонентов нет. Ошибка объявляется существующим role=alert, реальные секреты не добавлены; подтверждение риска и управление фокусом покрыты профильными тестами. Изменение пока локальное, удалённый frontend остаётсяf194e72. + +Следующий12.5.45 — production Docker build нового frontend, обновление тестового стенда и повтор сценария HTTP500 после COMMIT на отдельной БД. Локальный коммит без push. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index 307ed974..b6976313 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,12 +1,12 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-08: 12.5.43 проверил успешный browser retry и потерю HTTP receipt после реального COMMIT: POST200/500, обе fixture pending/version1; checkpoint сохраняется после refresh/reload и снимается явно без нового POST. JS errors=0, отправок Telegram нет; стенд очищен. Следующий блок 12.5.44 — понятное сообщение о неподтверждённом повторе в открытом диалоге. Runtime backend8782054/frontendf194e72 прежний; 12.5 открыт. +Актуальное продолжение 2026-10-08: 12.5.44 уточнил ошибку неизвестного исхода в диалоге Telegram retry: пояснение блокировки и необходимости проверки очереди/чата видно сразу вместе с деталями API. Подтверждённые отказы сохраняют прежнее поведение. Playwright8/8, scoped typecheck и lint passed, ReUI checklist проверен. Следующий 12.5.45 — сборка/развёртывание frontend и повтор реального HTTP/PG сценария. Пока runtime backend8782054/frontendf194e72 прежний; 12.5 открыт. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-08. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. ## Актуальная точка продолжения — 2026-10-08 -Этапы0–11 завершены в описанных локальных границах. Этап12 остаётся открытым. На161.104.46.222 развёрнуты backend/frontend8782054; два CHR подключены. PG backup/restore/rollback, single-instance quiescence, JWT/RBAC и browser restore приняты в границах журнала. PG-8 проверен с настоящими PG/native и введённой после COMMIT ошибкой подтверждения; новый browser UI сохраняет snapshot и сверяет историю. ROS-8/9 API/SQL/native приняты в описанных границах. Browser-смена пары/длительности и удаление во время native-теста приняты в12.5.24. Реальный отказ bandwidth-аутентификации принят в12.5.25. 12.5.26 обнаружил и локально исправил30s timeout Next proxy. Исправленный frontendaa7dbdf развёрнут и проверен в12.5.27; backend8782054 прежний. ROS-3 reverse2→1/native-afterping принят в12.5.28; forward timeout открыт. Форма frontendf194e72 проверена без моков и развёрнута в12.5.29. Read-only диагностика12.5.30 не установила причину. 12.5.31 выявил текущий отказ авторизацииCHR2 вCLI/REST/SSH. В12.5.32 пользователь восстановил доступCHR2; dashboard/native1→2 passed, блокировка снята. TCP receive/both подтверждены после восстановлениядоступа в12.5.33; UDP transmit3s/API/history/UI подтверждены в12.5.34; Q-6productionenqueue/PG race принят в12.5.35; Q-4 realHTTP/PG race принят в12.5.36; Q-1productionclaim/PG/interceptedsender принят в12.5.37; 12.5.38 подтвердил SQL settlement rollback и сохранение sent после ошибки подтверждения COMMIT; 12.5.39 подтвердил unknown/processing без автоматического повтора при неопределённом ответе; 12.5.40 подтвердил задержку повтора и failed после исчерпания попыток при явном отказе; 12.5.41 подтвердил браузерные состояния очереди на HTTP/PG; 12.5.42 подтвердил production JWT/RBAC очереди на PostgreSQL; 12.5.43 подтвердил браузерный retry и checkpoint при потере HTTP receipt; следующий 12.5.44 — пояснение неподтверждённого результата в диалоге. [Протокол](ux-ui-external-acceptance.md) и [журнал](ux-ui-stage-12.md) сохраняют точные доказательства и ограничения. +Этапы0–11 завершены в описанных локальных границах. Этап12 остаётся открытым. На161.104.46.222 развёрнуты backend/frontend8782054; два CHR подключены. PG backup/restore/rollback, single-instance quiescence, JWT/RBAC и browser restore приняты в границах журнала. PG-8 проверен с настоящими PG/native и введённой после COMMIT ошибкой подтверждения; новый browser UI сохраняет snapshot и сверяет историю. ROS-8/9 API/SQL/native приняты в описанных границах. Browser-смена пары/длительности и удаление во время native-теста приняты в12.5.24. Реальный отказ bandwidth-аутентификации принят в12.5.25. 12.5.26 обнаружил и локально исправил30s timeout Next proxy. Исправленный frontendaa7dbdf развёрнут и проверен в12.5.27; backend8782054 прежний. ROS-3 reverse2→1/native-afterping принят в12.5.28; forward timeout открыт. Форма frontendf194e72 проверена без моков и развёрнута в12.5.29. Read-only диагностика12.5.30 не установила причину. 12.5.31 выявил текущий отказ авторизацииCHR2 вCLI/REST/SSH. В12.5.32 пользователь восстановил доступCHR2; dashboard/native1→2 passed, блокировка снята. TCP receive/both подтверждены после восстановлениядоступа в12.5.33; UDP transmit3s/API/history/UI подтверждены в12.5.34; Q-6productionenqueue/PG race принят в12.5.35; Q-4 realHTTP/PG race принят в12.5.36; Q-1productionclaim/PG/interceptedsender принят в12.5.37; 12.5.38 подтвердил SQL settlement rollback и сохранение sent после ошибки подтверждения COMMIT; 12.5.39 подтвердил unknown/processing без автоматического повтора при неопределённом ответе; 12.5.40 подтвердил задержку повтора и failed после исчерпания попыток при явном отказе; 12.5.41 подтвердил браузерные состояния очереди на HTTP/PG; 12.5.42 подтвердил production JWT/RBAC очереди на PostgreSQL; 12.5.43 подтвердил браузерный retry и checkpoint при потере HTTP receipt; 12.5.44 добавил ясное пояснение в диалоге, проверено локально; следующий 12.5.45 — production frontend build/deploy и реальная HTTP/PG проверка. [Протокол](ux-ui-external-acceptance.md) и [журнал](ux-ui-stage-12.md) сохраняют точные доказательства и ограничения. Реальные pg_dump/pg_restore, PG rollback и остановка UDP worker требуют внешней приёмки. Датированные продолжения ниже — история; точный следующий шаг также указан в начале [журнала](ux-ui-progress.md). diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 79ce9b64..ccc54a1e 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-08: 12.5.43 проверил успешный browser retry и потерю HTTP receipt после реального COMMIT: POST200/500, обе fixture pending/version1; checkpoint сохраняется после refresh/reload и снимается явно без нового POST. JS errors=0, отправок Telegram нет; стенд очищен. Следующий блок 12.5.44 — понятное сообщение о неподтверждённом повторе в открытом диалоге. Runtime backend8782054/frontendf194e72 прежний; 12.5 открыт. +Актуальное продолжение 2026-10-08: 12.5.44 уточнил ошибку неизвестного исхода в диалоге Telegram retry: пояснение блокировки и необходимости проверки очереди/чата видно сразу вместе с деталями API. Подтверждённые отказы сохраняют прежнее поведение. Playwright8/8, scoped typecheck и lint passed, ReUI checklist проверен. Следующий 12.5.45 — сборка/развёртывание frontend и повтор реального HTTP/PG сценария. Пока runtime backend8782054/frontendf194e72 прежний; 12.5 открыт. Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). @@ -34,6 +34,16 @@ | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 | | 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в описанных границах:12.3.83,main1186/1186,context221/221. Этап остаётся в работе: стенд12.5.1–3 развёрнут,bootstrap/smoke проверены;остальные сценарии12.5 не выполнены. | +## 12.5.44 — понятное пояснение неподтверждённого повтора в диалоге (2026-10-08) + +По результатам реального теста12.5.43 уточнён catch в components/alerts-outbox-panel.tsx. При HTTP500, потере ответа или некорректном receipt ошибка прямо в открытом диалоге сообщает: «Результат повтора не подтверждён. Автоматический повтор заблокирован. Проверьте очередь и чат перед новой попыткой», затем показывает подробность ошибки. API400/401/403/409/422 остаются подтверждёнными отказами: checkpoint снимается, исходная ошибка сохраняется. Правила повторной отправки, права и API не менялись. + +Профильный Playwright alerts-outbox.spec.ts:8/8, включая новый HTTP500 сценарий, сохранённый checkbox, disabled retry, reload guard и320px; прежние success, malformed receipt, reader, conflict и focus/cancel проходят. Eslint изменённых файлов и tsc --project tmp/tsconfig-speed-check.json --noEmit passed. Scoped config исключает старые копии исходников в tmp; это не утверждение о чистоте обычного полного tsc. [Локальный диалог320px](ux-ui/screens/outbox-retry-explained-local-320-2026-10-08.png) просмотрен. HTTP-ответы в этих локальных браузерных тестах подменены; реальные SQL/HTTP результаты43 сохраняются отдельно. + +Применён skill ReUI и MCP get_audit_checklist: композиция, установленные primitives, base-nova и semantic tokens сохранены; новых API/стилей/компонентов нет. Ошибка объявляется существующим role=alert, реальные секреты не добавлены; подтверждение риска и управление фокусом покрыты профильными тестами. Изменение пока локальное, удалённый frontend остаётсяf194e72. + +Следующий12.5.45 — production Docker build нового frontend, обновление тестового стенда и повтор сценария HTTP500 после COMMIT на отдельной БД. Локальный коммит без push. + ## 12.5.43 — браузерный повтор и потеря подтверждения после COMMIT (2026-10-08) [Отчёт браузера](ux-ui/acceptance/browser-outbox-retry-2026-10-08.json): production backend8782054/frontendf194e72, отдельная БД mmapp_acceptance_20261007, два синтетических unknown-сообщения. Реальные браузерные HTTP запросы и production retry transaction; scheduler admission закрыт, dispatcher не запускается, внешний Telegram fetch запрещён. Изолированный frontend использует отдельную Docker-сеть и alias backend. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index ac9e4819..07fb5fc6 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -1,6 +1,6 @@ # Этап 12: итоговая приёмка UX/UI -Актуальное продолжение 2026-10-08: 12.5.43 проверил успешный browser retry и потерю HTTP receipt после реального COMMIT: POST200/500, обе fixture pending/version1; checkpoint сохраняется после refresh/reload и снимается явно без нового POST. JS errors=0, отправок Telegram нет; стенд очищен. Следующий блок 12.5.44 — понятное сообщение о неподтверждённом повторе в открытом диалоге. Runtime backend8782054/frontendf194e72 прежний; 12.5 открыт. +Актуальное продолжение 2026-10-08: 12.5.44 уточнил ошибку неизвестного исхода в диалоге Telegram retry: пояснение блокировки и необходимости проверки очереди/чата видно сразу вместе с деталями API. Подтверждённые отказы сохраняют прежнее поведение. Playwright8/8, scoped typecheck и lint passed, ReUI checklist проверен. Следующий 12.5.45 — сборка/развёртывание frontend и повтор реального HTTP/PG сценария. Пока runtime backend8782054/frontendf194e72 прежний; 12.5 открыт. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. @@ -1418,3 +1418,13 @@ GET outbox: anonymous, неверные issuer/signature, expired и malformed Скриншоты просмотрены: [предупреждение после перезагрузки](ux-ui/screens/outbox-retry-checkpoint-real-320-2026-10-08.png), [диалог после HTTP500](ux-ui/screens/outbox-retry-unknown-real-320-2026-10-08.png). Первое тестовое ожидание внутреннего текста исключения исправлено на штатный production текст «Внутренняя ошибка сервера»; приложение не обязано раскрывать исключение. При пересоздании fixture первый прогон очищен с exitCode0. Итоговые контейнеры/сеть/туннель3018 удалены, backend exitCode0, независимый SQL подтвердил ноль fixture-строк. Основной стенд и RouterOS не менялись. Границы: управляемый отказ получения receipt после фактического COMMIT, а не физический разрыв сети; AUTH_REQUIRED=false; реальных сообщений и проверки чата нет. Найдена UX-недоработка: внутри открытого диалога generic HTTP500 не объясняет неизвестный исход текущего повтора. Следующий блок 12.5.44 — явное пояснение и профильная проверка диалога. Локальный коммит без push. + +## 12.5.44 — понятное пояснение неподтверждённого повтора в диалоге (2026-10-08) + +По результатам реального теста12.5.43 уточнён catch в components/alerts-outbox-panel.tsx. При HTTP500, потере ответа или некорректном receipt ошибка прямо в открытом диалоге сообщает: «Результат повтора не подтверждён. Автоматический повтор заблокирован. Проверьте очередь и чат перед новой попыткой», затем показывает подробность ошибки. API400/401/403/409/422 остаются подтверждёнными отказами: checkpoint снимается, исходная ошибка сохраняется. Правила повторной отправки, права и API не менялись. + +Профильный Playwright alerts-outbox.spec.ts:8/8, включая новый HTTP500 сценарий, сохранённый checkbox, disabled retry, reload guard и320px; прежние success, malformed receipt, reader, conflict и focus/cancel проходят. Eslint изменённых файлов и tsc --project tmp/tsconfig-speed-check.json --noEmit passed. Scoped config исключает старые копии исходников в tmp; это не утверждение о чистоте обычного полного tsc. [Локальный диалог320px](ux-ui/screens/outbox-retry-explained-local-320-2026-10-08.png) просмотрен. HTTP-ответы в этих локальных браузерных тестах подменены; реальные SQL/HTTP результаты43 сохраняются отдельно. + +Применён skill ReUI и MCP get_audit_checklist: композиция, установленные primitives, base-nova и semantic tokens сохранены; новых API/стилей/компонентов нет. Ошибка объявляется существующим role=alert, реальные секреты не добавлены; подтверждение риска и управление фокусом покрыты профильными тестами. Изменение пока локальное, удалённый frontend остаётсяf194e72. + +Следующий12.5.45 — production Docker build нового frontend, обновление тестового стенда и повтор сценария HTTP500 после COMMIT на отдельной БД. Локальный коммит без push. diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index 18dbc6c2..6eedd9ce 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -261,3 +261,13 @@ GET outbox: anonymous, неверные issuer/signature, expired и malformed Скриншоты просмотрены: [предупреждение после перезагрузки](ux-ui/screens/outbox-retry-checkpoint-real-320-2026-10-08.png), [диалог после HTTP500](ux-ui/screens/outbox-retry-unknown-real-320-2026-10-08.png). Первое тестовое ожидание внутреннего текста исключения исправлено на штатный production текст «Внутренняя ошибка сервера»; приложение не обязано раскрывать исключение. При пересоздании fixture первый прогон очищен с exitCode0. Итоговые контейнеры/сеть/туннель3018 удалены, backend exitCode0, независимый SQL подтвердил ноль fixture-строк. Основной стенд и RouterOS не менялись. Границы: управляемый отказ получения receipt после фактического COMMIT, а не физический разрыв сети; AUTH_REQUIRED=false; реальных сообщений и проверки чата нет. Найдена UX-недоработка: внутри открытого диалога generic HTTP500 не объясняет неизвестный исход текущего повтора. Следующий блок 12.5.44 — явное пояснение и профильная проверка диалога. Локальный коммит без push. + +## 12.5.44 — понятное пояснение неподтверждённого повтора в диалоге (2026-10-08) + +По результатам реального теста12.5.43 уточнён catch в components/alerts-outbox-panel.tsx. При HTTP500, потере ответа или некорректном receipt ошибка прямо в открытом диалоге сообщает: «Результат повтора не подтверждён. Автоматический повтор заблокирован. Проверьте очередь и чат перед новой попыткой», затем показывает подробность ошибки. API400/401/403/409/422 остаются подтверждёнными отказами: checkpoint снимается, исходная ошибка сохраняется. Правила повторной отправки, права и API не менялись. + +Профильный Playwright alerts-outbox.spec.ts:8/8, включая новый HTTP500 сценарий, сохранённый checkbox, disabled retry, reload guard и320px; прежние success, malformed receipt, reader, conflict и focus/cancel проходят. Eslint изменённых файлов и tsc --project tmp/tsconfig-speed-check.json --noEmit passed. Scoped config исключает старые копии исходников в tmp; это не утверждение о чистоте обычного полного tsc. [Локальный диалог320px](ux-ui/screens/outbox-retry-explained-local-320-2026-10-08.png) просмотрен. HTTP-ответы в этих локальных браузерных тестах подменены; реальные SQL/HTTP результаты43 сохраняются отдельно. + +Применён skill ReUI и MCP get_audit_checklist: композиция, установленные primitives, base-nova и semantic tokens сохранены; новых API/стилей/компонентов нет. Ошибка объявляется существующим role=alert, реальные секреты не добавлены; подтверждение риска и управление фокусом покрыты профильными тестами. Изменение пока локальное, удалённый frontend остаётсяf194e72. + +Следующий12.5.45 — production Docker build нового frontend, обновление тестового стенда и повтор сценария HTTP500 после COMMIT на отдельной БД. Локальный коммит без push. diff --git a/docs/ux-ui/screens/outbox-retry-explained-local-320-2026-10-08.png b/docs/ux-ui/screens/outbox-retry-explained-local-320-2026-10-08.png new file mode 100644 index 0000000000000000000000000000000000000000..2e8bd3b66067dd17253e8ffdb3a1dcf0a8a91cc7 GIT binary patch literal 35713 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.fulfill({status:409,json:{error:"Fixture queue conflict"}}));const dialog=await openRetry(page);await dialog.getByRole("button",{name:"Поставить в очередь повторно"}).click();await expect(dialog.getByRole("alert")).toHaveText("Fixture queue conflict");await expect(dialog.getByRole("checkbox")).toBeChecked();await expect(dialog.getByRole("button",{name:"Поставить в очередь повторно"})).toBeEnabled() }) +test("Manual queue retry: HTTP500 explains unknown outcome inside the dialog and preserves the guard",async({page})=>{ + await page.setViewportSize({width:320,height:1000});let calls=0 + await retrySetup(page,r=>{calls++;return r.fulfill({status:500,json:{error:"Внутренняя ошибка сервера"}})}) + const dialog=await openRetry(page);await dialog.getByRole("button",{name:"Поставить в очередь повторно"}).click() + await expect(dialog.getByRole("alert")).toContainText("Результат повтора не подтверждён. Автоматический повтор заблокирован. Проверьте очередь и чат перед новой попыткой.") + await expect(dialog.getByRole("alert")).toContainText("Внутренняя ошибка сервера") + await expect(dialog.getByRole("checkbox")).toBeChecked();await expect(dialog.getByRole("button",{name:"Поставить в очередь повторно"})).toBeDisabled() + const bounds=await dialog.boundingBox();expect(bounds!.x).toBeGreaterThanOrEqual(0);expect(bounds!.x+bounds!.width).toBeLessThanOrEqual(320) + await dialog.screenshot({path:"test-results/alerts-outbox-http500-320.png"}) + await dialog.getByRole("button",{name:"Отмена"}).click();await page.reload() + const panel=page.getByRole("region",{name:"Очередь Telegram",exact:true});await expect(panel).toContainText("Результат повтора неизвестен") + await expect(panel.getByRole("button",{name:"Повторить сообщение Held retry fixture"})).toBeDisabled();expect(calls).toBe(1) +}) + test("Manual queue retry: mobile confirmation fits, cancel restores focus without POST",async({page})=>{await page.setViewportSize({width:320,height:1000});let calls=0;await retrySetup(page,r=>{calls++;return r.fulfill({json:{ok:true}})});const dialog=await openRetry(page);const bounds=await dialog.boundingBox();expect(bounds!.x).toBeGreaterThanOrEqual(0);expect(bounds!.x+bounds!.width).toBeLessThanOrEqual(320);await dialog.screenshot({path:"test-results/alerts-outbox-dialog-320.png"});await page.keyboard.press("Escape");await expect(dialog).toHaveCount(0);await expect(page.getByRole("button",{name:"Повторить сообщение Held retry fixture"})).toBeFocused();expect(calls).toBe(0)})