diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index 24602090..bf0cf9d8 100644 --- a/docs/ux-ui-external-acceptance.md +++ b/docs/ux-ui-external-acceptance.md @@ -243,3 +243,13 @@ GET outbox: anonymous, неверные issuer/signature, expired и malformed Первый запуск harness остановился до создания fixture: jose отсутствует в production-образе как тестовая зависимость. Для генерации стандартной HS256 подписи использован встроенный node:crypto, production middleware и настройки не менялись. Dispatcher не запускался, scheduler admission закрыт, сообщений не отправлено. App/pool/container завершены; fixture удалены, отдельный SQL подтвердил ноль тестовых строк; остались только три основные Compose-службы. Границы: реальный Portal login/issuer endpoint не вызывался, браузерный RBAC и доставка не заявлены этим тестом. Q-7 подтверждён для API отказа до действия в этих границах. Следующий блок 12.5.43 — успешный UI retry и сохранение checkpoint при потере подтверждения HTTP в отдельной БД, с запретом внешней отправки. Локальный коммит без 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. + +Первый POST200 подтверждает только постановку в pending/version1, подпись UI прямо сообщает, что отправка и доставка ещё не подтверждены. Во втором сценарии обёртка production retry бросает исключение после завершённой транзакции: настоящий HTTP500 при фактически сохранённом pending/version1. Диалог и checkbox риска остаются, повтор заблокирован. После отмены, refresh и reload предупреждение о неизвестном результате сохраняется; SQL подтверждает две pending-строки/version1/retry_count0 и ноль истории. Явная проверка результата снимает checkpoint без нового POST. Всего POST:200/500, lostReceipts1, senderCalls0, JS errors0; панель и диалог помещаются в320px. + +Скриншоты просмотрены: [предупреждение после перезагрузки](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. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index f88db730..307ed974 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,12 +1,12 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-08: 12.5.42 подтвердил production JWT/RBAC очереди на PostgreSQL: 401 для недействительных токенов, 403 без нужных прав; отказанные POST не вызывают retry и не меняют БД. Write/admin получают pending/version1, старый повтор —409. Fixture удалены, реальных сообщений нет. Следующий блок 12.5.43 — успешный UI retry и сохранение checkpoint при потере подтверждения HTTP. Runtime backend8782054/frontendf194e72 прежний; 12.5 открыт. +Актуальное продолжение 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 открыт. Общий план проекта 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. [Протокол](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 — пояснение неподтверждённого результата в диалоге. [Протокол](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 b47e978b..79ce9b64 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-08: 12.5.42 подтвердил production JWT/RBAC очереди на PostgreSQL: 401 для недействительных токенов, 403 без нужных прав; отказанные POST не вызывают retry и не меняют БД. Write/admin получают pending/version1, старый повтор —409. Fixture удалены, реальных сообщений нет. Следующий блок 12.5.43 — успешный UI retry и сохранение checkpoint при потере подтверждения HTTP. Runtime backend8782054/frontendf194e72 прежний; 12.5 открыт. +Актуальное продолжение 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 открыт. Общий план: [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.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. + +Первый POST200 подтверждает только постановку в pending/version1, подпись UI прямо сообщает, что отправка и доставка ещё не подтверждены. Во втором сценарии обёртка production retry бросает исключение после завершённой транзакции: настоящий HTTP500 при фактически сохранённом pending/version1. Диалог и checkbox риска остаются, повтор заблокирован. После отмены, refresh и reload предупреждение о неизвестном результате сохраняется; SQL подтверждает две pending-строки/version1/retry_count0 и ноль истории. Явная проверка результата снимает checkpoint без нового POST. Всего POST:200/500, lostReceipts1, senderCalls0, JS errors0; панель и диалог помещаются в320px. + +Скриншоты просмотрены: [предупреждение после перезагрузки](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.42 — настоящие JWT/RBAC очереди на PostgreSQL (2026-10-08) [Отчёт JWT/RBAC](ux-ui/acceptance/outbox-rbac-2026-10-08.json): production buildApp/handlers/auth из backend8782054, AUTH_REQUIRED=true только внутри изолированного процесса, отдельная БД mmapp_acceptance_20261007. JWT HS256 подписаны серверным ключом в памяти; подпись, issuer и exp проверяет штатный middleware. Fastify inject проходит настоящий путь приложения и SQL, но не является браузерным запросом или удалённым сокетом. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 72b0dde8..ac9e4819 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.42 подтвердил production JWT/RBAC очереди на PostgreSQL: 401 для недействительных токенов, 403 без нужных прав; отказанные POST не вызывают retry и не меняют БД. Write/admin получают pending/version1, старый повтор —409. Fixture удалены, реальных сообщений нет. Следующий блок 12.5.43 — успешный UI retry и сохранение checkpoint при потере подтверждения HTTP. Runtime backend8782054/frontendf194e72 прежний; 12.5 открыт. +Актуальное продолжение 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 открыт. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. @@ -1408,3 +1408,13 @@ GET outbox: anonymous, неверные issuer/signature, expired и malformed Первый запуск harness остановился до создания fixture: jose отсутствует в production-образе как тестовая зависимость. Для генерации стандартной HS256 подписи использован встроенный node:crypto, production middleware и настройки не менялись. Dispatcher не запускался, scheduler admission закрыт, сообщений не отправлено. App/pool/container завершены; fixture удалены, отдельный SQL подтвердил ноль тестовых строк; остались только три основные Compose-службы. Границы: реальный Portal login/issuer endpoint не вызывался, браузерный RBAC и доставка не заявлены этим тестом. Q-7 подтверждён для API отказа до действия в этих границах. Следующий блок 12.5.43 — успешный UI retry и сохранение checkpoint при потере подтверждения HTTP в отдельной БД, с запретом внешней отправки. Локальный коммит без 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. + +Первый POST200 подтверждает только постановку в pending/version1, подпись UI прямо сообщает, что отправка и доставка ещё не подтверждены. Во втором сценарии обёртка production retry бросает исключение после завершённой транзакции: настоящий HTTP500 при фактически сохранённом pending/version1. Диалог и checkbox риска остаются, повтор заблокирован. После отмены, refresh и reload предупреждение о неизвестном результате сохраняется; SQL подтверждает две pending-строки/version1/retry_count0 и ноль истории. Явная проверка результата снимает checkpoint без нового POST. Всего POST:200/500, lostReceipts1, senderCalls0, JS errors0; панель и диалог помещаются в320px. + +Скриншоты просмотрены: [предупреждение после перезагрузки](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. diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index 1aacc063..18dbc6c2 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -251,3 +251,13 @@ GET outbox: anonymous, неверные issuer/signature, expired и malformed Первый запуск harness остановился до создания fixture: jose отсутствует в production-образе как тестовая зависимость. Для генерации стандартной HS256 подписи использован встроенный node:crypto, production middleware и настройки не менялись. Dispatcher не запускался, scheduler admission закрыт, сообщений не отправлено. App/pool/container завершены; fixture удалены, отдельный SQL подтвердил ноль тестовых строк; остались только три основные Compose-службы. Границы: реальный Portal login/issuer endpoint не вызывался, браузерный RBAC и доставка не заявлены этим тестом. Q-7 подтверждён для API отказа до действия в этих границах. Следующий блок 12.5.43 — успешный UI retry и сохранение checkpoint при потере подтверждения HTTP в отдельной БД, с запретом внешней отправки. Локальный коммит без 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. + +Первый POST200 подтверждает только постановку в pending/version1, подпись UI прямо сообщает, что отправка и доставка ещё не подтверждены. Во втором сценарии обёртка production retry бросает исключение после завершённой транзакции: настоящий HTTP500 при фактически сохранённом pending/version1. Диалог и checkbox риска остаются, повтор заблокирован. После отмены, refresh и reload предупреждение о неизвестном результате сохраняется; SQL подтверждает две pending-строки/version1/retry_count0 и ноль истории. Явная проверка результата снимает checkpoint без нового POST. Всего POST:200/500, lostReceipts1, senderCalls0, JS errors0; панель и диалог помещаются в320px. + +Скриншоты просмотрены: [предупреждение после перезагрузки](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. diff --git a/docs/ux-ui/acceptance/browser-outbox-retry-2026-10-08.json b/docs/ux-ui/acceptance/browser-outbox-retry-2026-10-08.json new file mode 100644 index 00000000..3885f0bd --- /dev/null +++ b/docs/ux-ui/acceptance/browser-outbox-retry-2026-10-08.json @@ -0,0 +1,59 @@ +{ + "date": "2026-10-08", + "backendSource": "8782054", + "frontendSource": "f194e72", + "database": "mmapp_acceptance_20261007", + "browserHttpMocks": false, + "sqlFixture": true, + "posts": [ + { + "status": 200, + "body": { + "expectedVersion": 0, + "acknowledgedDuplicateRisk": true + } + }, + { + "status": 500, + "body": { + "expectedVersion": 0, + "acknowledgedDuplicateRisk": true + } + } + ], + "confirmedQueueCaptionDoesNotClaimDelivery": true, + "unconfirmedReceipt": { + "httpStatus": 500, + "actualCommittedRows": [ + { + "id": "acceptance-browser-retry-1791444381380-confirmed", + "status": "pending", + "resolution_version": 1, + "retry_count": 0 + }, + { + "id": "acceptance-browser-retry-1791444381380-unconfirmed", + "status": "pending", + "resolution_version": 1, + "retry_count": 0 + } + ], + "dialogPreserved": true, + "riskCheckboxPreserved": true, + "retryDisabled": true, + "checkpointSurvivesRefreshAndReload": true, + "explicitReviewClearsCheckpointWithoutPost": true + }, + "historyRows": 0, + "externalSenderCalls": 0, + "retryPosts": 2, + "lostReceipts": 1, + "mobileFits": true, + "mobileDialogFits": true, + "pageErrors": [], + "limits": [ + "Synthetic queue rows; scheduler stopped; no real Telegram send or chat check", + "Backend wrapper throws after actual retry transaction committed: real HTTP500, not physical network disconnect", + "Auth false on isolated loopback stand; Portal SSO not tested" + ] +} diff --git a/docs/ux-ui/screens/outbox-retry-checkpoint-real-320-2026-10-08.png b/docs/ux-ui/screens/outbox-retry-checkpoint-real-320-2026-10-08.png new file mode 100644 index 00000000..213826ed Binary files /dev/null and b/docs/ux-ui/screens/outbox-retry-checkpoint-real-320-2026-10-08.png differ diff --git a/docs/ux-ui/screens/outbox-retry-unknown-real-320-2026-10-08.png b/docs/ux-ui/screens/outbox-retry-unknown-real-320-2026-10-08.png new file mode 100644 index 00000000..bc9bb075 Binary files /dev/null and b/docs/ux-ui/screens/outbox-retry-unknown-real-320-2026-10-08.png differ