diff --git a/backend/src/routes/speed-test.test.ts b/backend/src/routes/speed-test.test.ts index 7f83291b..7ab6e391 100644 --- a/backend/src/routes/speed-test.test.ts +++ b/backend/src/routes/speed-test.test.ts @@ -28,12 +28,22 @@ missing = true; assert.equal((await send(base)).statusCode, 404); assert.equal(c for (const [error, code] of [[new SpeedProbeEndpointsChanged(), 409], [new SpeedProbeContextChanged(), 409], [Error("На интерфейсе назначения нет активного IP"), 400], [Error("Server not found"), 400], [Error("authentication failed"), 502], [Error("socket hang up"), 502]] as const) { problem = error; const response = await send({ ...base, runId: "failed", direction: "transmit", durationSec: 20 }); assert.equal(response.statusCode, code); assert.equal(failures.at(-1)?.runId, "failed"); assert.equal(failures.at(-1)?.durationSec, 20); assert.equal(failures.at(-1)?.direction, "transmit") } -const beforeUnknown = { runs: commands.length, failures: failures.length } +for (const transport of ["Connection timed out after 30s", "socket hang up", "read ECONNRESET"]) { + problem = Error(transport) + const response = await send({ ...base, runId: "transport-failed" }) + assert.equal(response.statusCode, 502) + assert.match(response.json().error, /Результат теста скорости неизвестен/) + assert.doesNotMatch(response.json().error, /socket|ECONNRESET|timed out/) + assert.equal(failures.at(-1)?.message, transport) +} +problem = Error("RouterOS отклонил авторизацию bandwidth-test") +assert.equal((await send(base)).json().error, problem.message) +const beforePersistenceUnknown = { runs: commands.length, failures: failures.length } problem = new SpeedRunPersistenceUnknown("actual-run-id") const unknown = await send(base) assert.equal(unknown.statusCode, 502); assert.equal(unknown.json().outcome, "unknown") assert.equal(unknown.json().runId, "actual-run-id"); assert.match(unknown.json().error, /сохранение результата не подтверждено/) -assert.equal(failures.length, beforeUnknown.failures); assert.equal(commands.length, beforeUnknown.runs + 1) +assert.equal(failures.length, beforePersistenceUnknown.failures); assert.equal(commands.length, beforePersistenceUnknown.runs + 1) await app.close(); console.log("Speed-test HTTP:26 invalid inputs; explicit persistence unknown/runId skips failure write and command retry") process.env.AUTH_REQUIRED = "true"; process.env.AUTH_JWT_SECRET = "speed-command-test-secret"; process.env.AUTH_ISSUER = "https://auth.test.local"; process.env.NODE_ENV = "test" const { default: authPlugin, requireAuth } = await import("../plugins/auth.js") diff --git a/backend/src/routes/speed-test.ts b/backend/src/routes/speed-test.ts index 7c7b9a67..1f74cbe6 100644 --- a/backend/src/routes/speed-test.ts +++ b/backend/src/routes/speed-test.ts @@ -2,6 +2,7 @@ import type { FastifyPluginAsyncZod } from "@fastify/type-provider-zod" import { speedTestCommandSchema, type SpeedTestCommand } from "@mmapp/contracts" import type { SpeedTestRunResult } from "../services/uptime-speed-service.js" import { SpeedProbeContextChanged, SpeedRunPersistenceUnknown } from "../services/speed-run-persistence.js" +import { speedRunErrorMessage } from "../services/speed-run-error-message.js" export function createSpeedTestRoute(deps: { serverExists: (id: number) => Promise @@ -23,9 +24,7 @@ export function createSpeedTestRoute(deps: { } const raw = error instanceof Error ? error.message : "Bandwidth test failed" await deps.failure({ ...command, message: raw }) - const message = /timed out|socket hang up|ECONNRESET/i.test(raw) - ? "BTTest timeout/socket hang up: проверь доступность destination, /tool bandwidth-server, firewall и корректность интерфейсов" - : raw + const message = speedRunErrorMessage(raw) if (error instanceof SpeedProbeContextChanged) return reply.code(409).send({ error: message }) if (/активного IP|Server not found/i.test(raw)) return reply.code(400).send({ error: message }) return reply.code(502).send({ error: message }) diff --git a/backend/src/services/speed-run-error-message.ts b/backend/src/services/speed-run-error-message.ts new file mode 100644 index 00000000..6c1750d2 --- /dev/null +++ b/backend/src/services/speed-run-error-message.ts @@ -0,0 +1,6 @@ +/** A lost transport receipt cannot establish whether RouterOS completed the test. */ +export function speedRunErrorMessage(raw: string): string { + return /timed out|socket hang up|ECONNRESET/i.test(raw) + ? "Результат теста скорости неизвестен: ответ устройства не получен. Проверьте его состояние перед повторным запуском." + : raw +} diff --git a/backend/src/services/uptime-speed-service.ts b/backend/src/services/uptime-speed-service.ts index 59a12f3d..89f5e1fa 100644 --- a/backend/src/services/uptime-speed-service.ts +++ b/backend/src/services/uptime-speed-service.ts @@ -10,6 +10,7 @@ import { parsePing } from "./uptime-collector.js" import { assertBandwidthTestCompleted } from "./bandwidth-test-status.js" import { assertSpeedProbeContext, persistSpeedRun, SpeedRunPersistenceUnknown, type SpeedProbeContext } from "./speed-run-persistence.js" import { readBandwidthTestRates } from "./bandwidth-test-rates.js" +import { speedRunErrorMessage } from "./speed-run-error-message.js" type SpeedWriteTransaction = Parameters[0]>[0] function speedProbeContextWhere(target: SpeedProbeContext) { @@ -73,12 +74,6 @@ export interface SpeedTestRunResult { } } -function humanizeSpeedError(raw: string): string { - return /timed out|socket hang up|ECONNRESET/i.test(raw) - ? "BTTest timeout/socket hang up: проверь доступность destination, /tool bandwidth-server, firewall и корректность интерфейсов" - : raw -} - /** Полный цикл bandwidth-test + after-ping + запись в БД. Вызывать внутри withBtestNodeLocks при необходимости — здесь lock уже снаружи. */ export async function executeBandwidthSpeedTestInner(params: SpeedTestRunParams): Promise { const probeId = String(params.probeId ?? "").trim() @@ -232,7 +227,7 @@ export async function recordSpeedTestFailure(params: { message: string }) { const probeId = String(params.probeId ?? "").trim() - const message = humanizeSpeedError(params.message) + const message = speedRunErrorMessage(params.message) await persistSpeedRun(probeId ? { id: probeId, srcServerId: params.srcServerId, dstServerId: params.dstServerId, srcInterface: String(params.srcInterface ?? "").trim(), dstInterface: String(params.dstInterface ?? "").trim(), diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index 5ff4583a..1c898645 100644 --- a/docs/ux-ui-external-acceptance.md +++ b/docs/ux-ui-external-acceptance.md @@ -1,6 +1,6 @@ # UX/UI: протокол внешней приёмки 12.5 -Актуальное продолжение 2026-10-10: завершены12.5.93–97. Реальный HTTP receipt disconnect после передачи короткой bandwidth команды: API502/error history, предыдущие snapshots сохранены, native1/noauto retry, independent native done и UI2/2. Own DB fixtures удалены. Следующий12.5.98 — заменить техническое timeout/socket сообщение понятным пояснением неизвестного native результата, профильная проверка/deploy; затем общая регрессия. Runtime backend ux-diagnostics89/frontend ux-ospf91. Этап12.5 открыт. +Актуальное продолжение 2026-10-10: завершены12.5.93–98. На стенде backend ux-speed98/frontend ux-ospf91; неизвестный native результат при transport loss теперь явно объяснён одинаково в API/history/UI, live2/2. Собственные fixtures очищены, credentials не менялись. Следующий12.5.99 — общая backend/main/context регрессия; backend/main уже запущены и пока не объявлены прошедшими. Актуальная внешняя матрица docs/ux-ui-remaining-acceptance.md; этап12.5 открыт. IPsec78: реальный PSK responder established, mode-config198.18.78.10 и online=true подтверждены API; точные собственные объекты удалены. Сертификатный/DN online, late failure и history restore остаются открытыми. [Отчёт](ux-ui/acceptance/ipsec-mode-config-2026-10-09.json), [журнал](ux-ui-progress.md). @@ -700,7 +700,7 @@ flowchart LR ## 12.5.77 — основной блок IPsec (2026-10-09) -Актуальное продолжение 2026-10-10: завершены12.5.93–97. Реальный HTTP receipt disconnect после передачи короткой bandwidth команды: API502/error history, предыдущие snapshots сохранены, native1/noauto retry, independent native done и UI2/2. Own DB fixtures удалены. Следующий12.5.98 — заменить техническое timeout/socket сообщение понятным пояснением неизвестного native результата, профильная проверка/deploy; затем общая регрессия. Runtime backend ux-diagnostics89/frontend ux-ospf91. Этап12.5 открыт. +Актуальное продолжение 2026-10-09: 12.5.77 завершил укрупнённый основной блок IPsec: достоверное чтение, запрет опроса выключенных устройств, совместимый RouterOS7 мастер, раздельные ID клиентов, безопаснее удаление, URL устройства/вкладки, Docker обеих частей и реальная приёмка. Local30/30 + context6/6 + backend67, live browser4/4, PSK и сертификатный защищённый GRE/Ping3/3 на двух CHR; cleanup/DB controls passed. Runtime backend/frontend ux-ipsec77, version1.0.0-test.ipsec77. Следующий12.5.78 — остаточная профильная приёмка IPsec: сопоставление active-peer/online, выдача mode-config, поздние ошибки операций и история восстановления; затем маршрутизация. Этап12.5 открыт. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). @@ -925,3 +925,13 @@ API502, history error/TXRX/Pingnull, probe error с прежними42/17/15/0; Свои history/probe exact IDs удалены, исходные списки совпали, только3 compose containers/backend/PG healthy. Один короткий capped native запуск с первой попытки, без RouterOS configuration/account changes/build/deploy. Native команда не отменялась; physical WAN failure/abort/multi-instance locks не приняты. Lab AUTH_REQUIRED=false, rights не проверялись повторно. HTTP ошибка приложения не доказывает failure native команды. Обнаружено оставшееся UX ограничение: timeout/socket message техническая и не объясняет неопределённость native результата. Следующий98 — единый понятный transport error для HTTP/history, профильные tests и один backend build/live повтор только изменённого message path; затем общая регрессия на согласованном runtime. Этап12.5 открыт. Один локальный коммит без push. + +## 12.5.98 — понятный неизвестный результат теста скорости (2026-10-10) + +После реального lost receipt97 техническое сообщение заменено единым speedRunErrorMessage для HTTP и сохраняемой истории: «Результат теста скорости неизвестен: ответ устройства не получен. Проверьте его состояние перед повторным запуском». Timeout/socket hang up/ECONNRESET не означают доказанный native failure. Известный отказ авторизации и остальные конкретные ошибки сохраняются; неизвестное сохранение PG остаётся отдельным outcome=unknown/runId. HTTP502/history error означают ошибку получения результата приложением; schema/status/автоматический retry не расширялись. + +**Проверки.** Speed-test HTTP validation/persistence/RBAC и дополнительные3 transport cases/известная auth error passed; локальный contracts/backend production build и scoped ESLint passed. Service иroute используют один formatter. [Deployment](ux-ui/acceptance/deployed-speed-message-2026-10-10.json): одна Docker backend сборка из context diagnostics89 +3 working-tree files, package/lockfile неизменны, production tsc/entry/node --check/pg_restore18.6/compose --wait passed. Runtime backend ux-speed98/version1.0.0-test.speed98/image779b0fc010c9…; frontend ux-ospf91 прежний. Label speed98 — блок, не Git SHA. Приватный .env backup сохранён; обновлён только BACKEND_IMAGE_TAG. + +[Native/API/PG](ux-ui/acceptance/speed-message-2026-10-10.json) и [browser](ux-ui/acceptance/browser-speed-message-2026-10-10.json): повторён только изменённый receipt path, одна capped10Mbit/s TCP3s команда, реальное закрытие socket после передачи, native independently done, API/history содержат новое сообщение; прежние синтетические42/17/15/0 сохранены, native1/noauto retry. Live1280/3202/2, сообщение видно в probe card, reload/document fits/pageerror0/UI command POST0. Свои disabled probe/history удалены, исходные IDs совпали, только3 compose containers/backend/PG healthy; RouterOS/credentials не менялись. + +При согласовании указателей94–97 обнаружено, что массовая замена также затронула исторический абзац77 в плане/протоколе. Восстановлен точный абзац из40f730b, история/дата2026-10-09 сохранены; следующие обновления ограничены текущими указателями. Следующий99 — одна общая backend/main/context регрессия на текущем source, с восстановлением исходных доказательств, затем итоговая сводка. General backend/main runs уже запущены, их результат этим блоком не заявлен. Квота23% использовано; этап12.5 открыт. Один локальный commit без push. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index a6e79c7b..7e98c6ed 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,12 +1,12 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-10: завершены12.5.93–97. Реальный HTTP receipt disconnect после передачи короткой bandwidth команды: API502/error history, предыдущие snapshots сохранены, native1/noauto retry, independent native done и UI2/2. Own DB fixtures удалены. Следующий12.5.98 — заменить техническое timeout/socket сообщение понятным пояснением неизвестного native результата, профильная проверка/deploy; затем общая регрессия. Runtime backend ux-diagnostics89/frontend ux-ospf91. Этап12.5 открыт. +Актуальное продолжение 2026-10-10: завершены12.5.93–98. На стенде backend ux-speed98/frontend ux-ospf91; неизвестный native результат при transport loss теперь явно объяснён одинаково в API/history/UI, live2/2. Собственные fixtures очищены, credentials не менялись. Следующий12.5.99 — общая backend/main/context регрессия; backend/main уже запущены и пока не объявлены прошедшими. Актуальная внешняя матрица docs/ux-ui-remaining-acceptance.md; этап12.5 открыт. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-10. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. ## Актуальная точка продолжения — 2026-10-10 -Актуальное продолжение 2026-10-10: завершены12.5.93–97. Реальный HTTP receipt disconnect после передачи короткой bandwidth команды: API502/error history, предыдущие snapshots сохранены, native1/noauto retry, independent native done и UI2/2. Own DB fixtures удалены. Следующий12.5.98 — заменить техническое timeout/socket сообщение понятным пояснением неизвестного native результата, профильная проверка/deploy; затем общая регрессия. Runtime backend ux-diagnostics89/frontend ux-ospf91. Этап12.5 открыт. +Актуальное продолжение 2026-10-10: завершены12.5.93–98. На стенде backend ux-speed98/frontend ux-ospf91; неизвестный native результат при transport loss теперь явно объяснён одинаково в API/history/UI, live2/2. Собственные fixtures очищены, credentials не менялись. Следующий12.5.99 — общая backend/main/context регрессия; backend/main уже запущены и пока не объявлены прошедшими. Актуальная внешняя матрица docs/ux-ui-remaining-acceptance.md; этап12.5 открыт. Этапы0–11 завершены в локальных границах журнала. История выполненных внешних блоков и доказательства сохранены в [журнале](ux-ui-stage-12.md) и [протоколе](ux-ui-external-acceptance.md). Реальная Telegram доставка, Portal SSO, multi-instance и оставшиеся профильные сетевые ограничения открыты. @@ -371,6 +371,6 @@ flowchart LR ## 12.5.77 — основной блок IPsec (2026-10-09) -Актуальное продолжение 2026-10-10: завершены12.5.93–97. Реальный HTTP receipt disconnect после передачи короткой bandwidth команды: API502/error history, предыдущие snapshots сохранены, native1/noauto retry, independent native done и UI2/2. Own DB fixtures удалены. Следующий12.5.98 — заменить техническое timeout/socket сообщение понятным пояснением неизвестного native результата, профильная проверка/deploy; затем общая регрессия. Runtime backend ux-diagnostics89/frontend ux-ospf91. Этап12.5 открыт. +Актуальное продолжение 2026-10-09: 12.5.77 завершил укрупнённый основной блок IPsec: достоверное чтение, запрет опроса выключенных устройств, совместимый RouterOS7 мастер, раздельные ID клиентов, безопаснее удаление, URL устройства/вкладки, Docker обеих частей и реальная приёмка. Local30/30 + context6/6 + backend67, live browser4/4, PSK и сертификатный защищённый GRE/Ping3/3 на двух CHR; cleanup/DB controls passed. Runtime backend/frontend ux-ipsec77, version1.0.0-test.ipsec77. Следующий12.5.78 — остаточная профильная приёмка IPsec: сопоставление active-peer/online, выдача mode-config, поздние ошибки операций и история восстановления; затем маршрутизация. Этап12.5 открыт. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 3072d796..b2627c8c 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-10: завершены12.5.93–97. Реальный HTTP receipt disconnect после передачи короткой bandwidth команды: API502/error history, предыдущие snapshots сохранены, native1/noauto retry, independent native done и UI2/2. Own DB fixtures удалены. Следующий12.5.98 — заменить техническое timeout/socket сообщение понятным пояснением неизвестного native результата, профильная проверка/deploy; затем общая регрессия. Runtime backend ux-diagnostics89/frontend ux-ospf91. Этап12.5 открыт. +Актуальное продолжение 2026-10-10: завершены12.5.93–98. На стенде backend ux-speed98/frontend ux-ospf91; неизвестный native результат при transport loss теперь явно объяснён одинаково в API/history/UI, live2/2. Собственные fixtures очищены, credentials не менялись. Следующий12.5.99 — общая backend/main/context регрессия; backend/main уже запущены и пока не объявлены прошедшими. Актуальная внешняя матрица docs/ux-ui-remaining-acceptance.md; этап12.5 открыт. Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). @@ -36,7 +36,17 @@ | 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 | | 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 | | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 | -| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–97 и ограничения ниже. Runtime backend ux-diagnostics89/frontend ux-ospf91. | +| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–98 и ограничения ниже. Runtime backend ux-diagnostics89/frontend ux-ospf91. | + +## 12.5.98 — понятный неизвестный результат теста скорости (2026-10-10) + +После реального lost receipt97 техническое сообщение заменено единым speedRunErrorMessage для HTTP и сохраняемой истории: «Результат теста скорости неизвестен: ответ устройства не получен. Проверьте его состояние перед повторным запуском». Timeout/socket hang up/ECONNRESET не означают доказанный native failure. Известный отказ авторизации и остальные конкретные ошибки сохраняются; неизвестное сохранение PG остаётся отдельным outcome=unknown/runId. HTTP502/history error означают ошибку получения результата приложением; schema/status/автоматический retry не расширялись. + +**Проверки.** Speed-test HTTP validation/persistence/RBAC и дополнительные3 transport cases/известная auth error passed; локальный contracts/backend production build и scoped ESLint passed. Service иroute используют один formatter. [Deployment](ux-ui/acceptance/deployed-speed-message-2026-10-10.json): одна Docker backend сборка из context diagnostics89 +3 working-tree files, package/lockfile неизменны, production tsc/entry/node --check/pg_restore18.6/compose --wait passed. Runtime backend ux-speed98/version1.0.0-test.speed98/image779b0fc010c9…; frontend ux-ospf91 прежний. Label speed98 — блок, не Git SHA. Приватный .env backup сохранён; обновлён только BACKEND_IMAGE_TAG. + +[Native/API/PG](ux-ui/acceptance/speed-message-2026-10-10.json) и [browser](ux-ui/acceptance/browser-speed-message-2026-10-10.json): повторён только изменённый receipt path, одна capped10Mbit/s TCP3s команда, реальное закрытие socket после передачи, native independently done, API/history содержат новое сообщение; прежние синтетические42/17/15/0 сохранены, native1/noauto retry. Live1280/3202/2, сообщение видно в probe card, reload/document fits/pageerror0/UI command POST0. Свои disabled probe/history удалены, исходные IDs совпали, только3 compose containers/backend/PG healthy; RouterOS/credentials не менялись. + +При согласовании указателей94–97 обнаружено, что массовая замена также затронула исторический абзац77 в плане/протоколе. Восстановлен точный абзац из40f730b, история/дата2026-10-09 сохранены; следующие обновления ограничены текущими указателями. Следующий99 — одна общая backend/main/context регрессия на текущем source, с восстановлением исходных доказательств, затем итоговая сводка. General backend/main runs уже запущены, их результат этим блоком не заявлен. Квота23% использовано; этап12.5 открыт. Один локальный commit без push. ## 12.5.97 — реальный обрыв HTTP receipt bandwidth-test (2026-10-10) diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md index 771f2f0c..7b2e8b2b 100644 --- a/docs/ux-ui-remaining-acceptance.md +++ b/docs/ux-ui-remaining-acceptance.md @@ -1,8 +1,8 @@ # Оставшаяся внешняя приёмка — 2026-10-10 -Это актуальная матрица после 12.5.97. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. +Это актуальная матрица после 12.5.98. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. -Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-diagnostics89`, frontend `ux-ospf91`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты последнего сценария удалены, исходные11 коллекций×2 восстановлены; пароли не менялись. +Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-speed98`, frontend `ux-ospf91`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты последнего сценария удалены, исходные11 коллекций×2 восстановлены; пароли не менялись. | Раздел | Подтверждено | Осталось / условие завершения | | --- | --- | --- | @@ -25,7 +25,7 @@ ## Следующая последовательность 1. **12.5.95 завершён:** [source/context/compiled audit](ux-ui/acceptance/deployment-source-audit-2026-10-10.json), production source drift не выявлен; нормализация и исключения явно указаны. -2. **12.5.96 timezone завершён:** [6 live UI cases](ux-ui/acceptance/browser-speed-timezone-2026-10-10.json). 97 HTTP receipt disconnect принят: [протокол](ux-ui/acceptance/speed-disconnect-2026-10-10.json). Следующий98 — понятное сообщение неизвестного native результата. +2. **12.5.96 timezone завершён:** [6 live UI cases](ux-ui/acceptance/browser-speed-timezone-2026-10-10.json). 97 HTTP receipt disconnect принят: [протокол](ux-ui/acceptance/speed-disconnect-2026-10-10.json). 98 сообщение неизвестного native результата исправлено/развёрнуто. Следующий99 — общая регрессия. 3. **Заключительный профильный контроль:** после последнего исправления собрать только затронутую часть, проверить её live и обновить матрицу. Общую регрессию выполнить один раз на согласованном runtime. 4. **Внешние зависимости:** Telegram/Portal/client OS/multi-WAN/scale проходят отдельную приёмку при наличии нужных аккаунтов, устройств и разрешений. Лабораторный результат двух CHR не закрывает их автоматически. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 8ffcdcf1..9a7da907 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -2234,3 +2234,13 @@ API502, history error/TXRX/Pingnull, probe error с прежними42/17/15/0; Свои history/probe exact IDs удалены, исходные списки совпали, только3 compose containers/backend/PG healthy. Один короткий capped native запуск с первой попытки, без RouterOS configuration/account changes/build/deploy. Native команда не отменялась; physical WAN failure/abort/multi-instance locks не приняты. Lab AUTH_REQUIRED=false, rights не проверялись повторно. HTTP ошибка приложения не доказывает failure native команды. Обнаружено оставшееся UX ограничение: timeout/socket message техническая и не объясняет неопределённость native результата. Следующий98 — единый понятный transport error для HTTP/history, профильные tests и один backend build/live повтор только изменённого message path; затем общая регрессия на согласованном runtime. Этап12.5 открыт. Один локальный коммит без push. + +## 12.5.98 — понятный неизвестный результат теста скорости (2026-10-10) + +После реального lost receipt97 техническое сообщение заменено единым speedRunErrorMessage для HTTP и сохраняемой истории: «Результат теста скорости неизвестен: ответ устройства не получен. Проверьте его состояние перед повторным запуском». Timeout/socket hang up/ECONNRESET не означают доказанный native failure. Известный отказ авторизации и остальные конкретные ошибки сохраняются; неизвестное сохранение PG остаётся отдельным outcome=unknown/runId. HTTP502/history error означают ошибку получения результата приложением; schema/status/автоматический retry не расширялись. + +**Проверки.** Speed-test HTTP validation/persistence/RBAC и дополнительные3 transport cases/известная auth error passed; локальный contracts/backend production build и scoped ESLint passed. Service иroute используют один formatter. [Deployment](ux-ui/acceptance/deployed-speed-message-2026-10-10.json): одна Docker backend сборка из context diagnostics89 +3 working-tree files, package/lockfile неизменны, production tsc/entry/node --check/pg_restore18.6/compose --wait passed. Runtime backend ux-speed98/version1.0.0-test.speed98/image779b0fc010c9…; frontend ux-ospf91 прежний. Label speed98 — блок, не Git SHA. Приватный .env backup сохранён; обновлён только BACKEND_IMAGE_TAG. + +[Native/API/PG](ux-ui/acceptance/speed-message-2026-10-10.json) и [browser](ux-ui/acceptance/browser-speed-message-2026-10-10.json): повторён только изменённый receipt path, одна capped10Mbit/s TCP3s команда, реальное закрытие socket после передачи, native independently done, API/history содержат новое сообщение; прежние синтетические42/17/15/0 сохранены, native1/noauto retry. Live1280/3202/2, сообщение видно в probe card, reload/document fits/pageerror0/UI command POST0. Свои disabled probe/history удалены, исходные IDs совпали, только3 compose containers/backend/PG healthy; RouterOS/credentials не менялись. + +При согласовании указателей94–97 обнаружено, что массовая замена также затронула исторический абзац77 в плане/протоколе. Восстановлен точный абзац из40f730b, история/дата2026-10-09 сохранены; следующие обновления ограничены текущими указателями. Следующий99 — одна общая backend/main/context регрессия на текущем source, с восстановлением исходных доказательств, затем итоговая сводка. General backend/main runs уже запущены, их результат этим блоком не заявлен. Квота23% использовано; этап12.5 открыт. Один локальный commit без push. diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index a385715f..80d62f1b 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -1,6 +1,6 @@ # Тестовый сервер UX/UI — 2026-10-10 -Сервер161.104.46.222 предоставлен для временного тестирования. Backend ux-diagnostics89/version1.0.0-test.diagnostics89, frontend ux-ospf91/version1.0.0-test.ospf91; backend/PG healthy, frontend HTTP/browser passed. Основной блок IPsec77 принят в границах журнала, own fixtures/fake DB rows удалены; каталог flash CHR2 сохранён из-за неподтверждённого ownership. SSH/оба CHR доступны, пароли прежние. +Сервер161.104.46.222 предоставлен для временного тестирования. Backend ux-speed98/version1.0.0-test.speed98, frontend ux-ospf91/version1.0.0-test.ospf91; backend/PG healthy, frontend HTTP/browser passed. Основной блок IPsec77 принят в границах журнала, own fixtures/fake DB rows удалены; каталог flash CHR2 сохранён из-за неподтверждённого ownership. SSH/оба CHR доступны, пароли прежние. | Параметр | Проверенное состояние | | --- | --- | @@ -14,7 +14,7 @@ | PostgreSQL | postgres:18-alpine,18.6;mmapp-test-postgres healthy;SELECT version() passed | | Данные | Отдельный Compose project mmapp-test,том mmapp-test_mmapp-pgdata и каталог ./data | | Доступ | PostgreSQL не публикуется;frontend3000/backend8000 привязаны к127.0.0.1 после запуска | -| Образы приложения | mmapp-test/backend:ux-diagnostics89 и mmapp-test/frontend:ux-ospf91; запущены | +| Образы приложения | mmapp-test/backend:ux-speed98 и mmapp-test/frontend:ux-ospf91; запущены | Compose SHA256:3052bd6ab5d9865f97605cebfb5ff27a4410cd3357b81153a65a87fb7c92582f. OptionalBACKEND_IMAGE_TAG позволяетобновлятьbackendотдельно. Локальный и удалённый файлы совпали. Шаблоны: [Compose](../deploy/docker-compose.test.yml), [env без секретов](../deploy/env.test.example). @@ -747,3 +747,13 @@ API502, history error/TXRX/Pingnull, probe error с прежними42/17/15/0; Свои history/probe exact IDs удалены, исходные списки совпали, только3 compose containers/backend/PG healthy. Один короткий capped native запуск с первой попытки, без RouterOS configuration/account changes/build/deploy. Native команда не отменялась; physical WAN failure/abort/multi-instance locks не приняты. Lab AUTH_REQUIRED=false, rights не проверялись повторно. HTTP ошибка приложения не доказывает failure native команды. Обнаружено оставшееся UX ограничение: timeout/socket message техническая и не объясняет неопределённость native результата. Следующий98 — единый понятный transport error для HTTP/history, профильные tests и один backend build/live повтор только изменённого message path; затем общая регрессия на согласованном runtime. Этап12.5 открыт. Один локальный коммит без push. + +## 12.5.98 — понятный неизвестный результат теста скорости (2026-10-10) + +После реального lost receipt97 техническое сообщение заменено единым speedRunErrorMessage для HTTP и сохраняемой истории: «Результат теста скорости неизвестен: ответ устройства не получен. Проверьте его состояние перед повторным запуском». Timeout/socket hang up/ECONNRESET не означают доказанный native failure. Известный отказ авторизации и остальные конкретные ошибки сохраняются; неизвестное сохранение PG остаётся отдельным outcome=unknown/runId. HTTP502/history error означают ошибку получения результата приложением; schema/status/автоматический retry не расширялись. + +**Проверки.** Speed-test HTTP validation/persistence/RBAC и дополнительные3 transport cases/известная auth error passed; локальный contracts/backend production build и scoped ESLint passed. Service иroute используют один formatter. [Deployment](ux-ui/acceptance/deployed-speed-message-2026-10-10.json): одна Docker backend сборка из context diagnostics89 +3 working-tree files, package/lockfile неизменны, production tsc/entry/node --check/pg_restore18.6/compose --wait passed. Runtime backend ux-speed98/version1.0.0-test.speed98/image779b0fc010c9…; frontend ux-ospf91 прежний. Label speed98 — блок, не Git SHA. Приватный .env backup сохранён; обновлён только BACKEND_IMAGE_TAG. + +[Native/API/PG](ux-ui/acceptance/speed-message-2026-10-10.json) и [browser](ux-ui/acceptance/browser-speed-message-2026-10-10.json): повторён только изменённый receipt path, одна capped10Mbit/s TCP3s команда, реальное закрытие socket после передачи, native independently done, API/history содержат новое сообщение; прежние синтетические42/17/15/0 сохранены, native1/noauto retry. Live1280/3202/2, сообщение видно в probe card, reload/document fits/pageerror0/UI command POST0. Свои disabled probe/history удалены, исходные IDs совпали, только3 compose containers/backend/PG healthy; RouterOS/credentials не менялись. + +При согласовании указателей94–97 обнаружено, что массовая замена также затронула исторический абзац77 в плане/протоколе. Восстановлен точный абзац из40f730b, история/дата2026-10-09 сохранены; следующие обновления ограничены текущими указателями. Следующий99 — одна общая backend/main/context регрессия на текущем source, с восстановлением исходных доказательств, затем итоговая сводка. General backend/main runs уже запущены, их результат этим блоком не заявлен. Квота23% использовано; этап12.5 открыт. Один локальный commit без push. diff --git a/docs/ux-ui/acceptance/browser-speed-message-2026-10-10.json b/docs/ux-ui/acceptance/browser-speed-message-2026-10-10.json new file mode 100644 index 00000000..7313c681 --- /dev/null +++ b/docs/ux-ui/acceptance/browser-speed-message-2026-10-10.json @@ -0,0 +1,24 @@ +{ + "date": "2026-10-10", + "cases": [ + { + "width": 1280, + "errorHistoryVisible": true, + "previousSnapshot42and17Preserved": true, + "reload": true, + "documentFits": true, + "unknownNativeMessageVisible": true + }, + { + "width": 320, + "errorHistoryVisible": true, + "previousSnapshot42and17Preserved": true, + "reload": true, + "documentFits": true, + "unknownNativeMessageVisible": true + } + ], + "errors": [], + "httpMocks": false, + "uiNativePosts": 0 +} diff --git a/docs/ux-ui/acceptance/deployed-speed-message-2026-10-10.json b/docs/ux-ui/acceptance/deployed-speed-message-2026-10-10.json new file mode 100644 index 00000000..89a3a60f --- /dev/null +++ b/docs/ux-ui/acceptance/deployed-speed-message-2026-10-10.json @@ -0,0 +1,39 @@ +{ + "date": "2026-10-10", + "backendImage": "mmapp-test/backend:ux-speed98", + "backendVersion": "1.0.0-test.speed98", + "backendImageId": "sha256:779b0fc010c9d0a52b9a774429cce77d28163d2374c24e4d2f64a3ab7ea18792", + "frontendImage": "mmapp-test/frontend:ux-ospf91", + "buildContext": "build-diagnostics89 copied to build-speed98; 3 working-tree production overrides", + "revisionLabel": "speed98 (stage label, not Git SHA)", + "archiveSha256": "1659e9b7fa1b135cbd3e61b77e097eb2bf6d0ee74816c508e989a374f60cb4a0", + "overrides": [ + { + "path": "backend/src/routes/speed-test.ts", + "normalizedSha256": "28d876438f8ac5ab6200f1193d53ce416018f28d847229c99eae82c1c5ec9111" + }, + { + "path": "backend/src/services/uptime-speed-service.ts", + "normalizedSha256": "9ffd217471ebc090dea178f2717ffb5cdb8bb27efe6f3db5e2346d8d066d2ea9" + }, + { + "path": "backend/src/services/speed-run-error-message.ts", + "normalizedSha256": "e31365d1282b87cd15b479c8a4b45333af997839d6f2f9cffb4887886b9f0d37" + } + ], + "validation": { + "localContractsBackendBuild": true, + "scopedEslint": true, + "speedHttpAndSignedJwtTests": true, + "dockerProductionBuild": true, + "entryNodeCheck": true, + "pgRestoreVersion": "18.6", + "composeWaitHealthy": true, + "liveUiCases": 2 + }, + "limits": [ + "General backend/main UI regression running separately; not claimed passed in this block", + "Only backend image changed; frontend/dependencies/migrations/account configuration unchanged", + "History error is application receipt outcome; native completion remains unknown to app on transport loss" + ] +} diff --git a/docs/ux-ui/acceptance/speed-message-2026-10-10.json b/docs/ux-ui/acceptance/speed-message-2026-10-10.json new file mode 100644 index 00000000..8c2864fe --- /dev/null +++ b/docs/ux-ui/acceptance/speed-message-2026-10-10.json @@ -0,0 +1,53 @@ +{ + "date": "2026-10-10", + "name": "mm-drop98-1791571091446", + "rateLimitBps": 10000000, + "durationSec": 3, + "syntheticPreviousSnapshot": { + "txAvgMbps": 42, + "rxAvgMbps": 17, + "pingRttMs": 15, + "pingLossPct": 0 + }, + "httpMocks": false, + "routerOsMocks": false, + "receiptSocketDestroyed": true, + "httpStatus": 502, + "receipt": { + "error": "Результат теста скорости неизвестен: ответ устройства не получен. Проверьте его состояние перед повторным запуском." + }, + "nativeCompletion": { + "status": "done testing", + "responseRows": 5, + "httpStatus": 200 + }, + "nativeCount": 1, + "probe": { + "id": "mm-drop98-1791571091446", + "last_status": "error", + "last_tx_avg_mbps": 42, + "last_rx_avg_mbps": 17, + "last_ping_rtt_ms": 15, + "last_ping_loss_pct": 0, + "last_error": "Результат теста скорости неизвестен: ответ устройства не получен. Проверьте его состояние перед повторным запуском." + }, + "history": [ + { + "id": "mm-drop98-1791571091446", + "status": "error", + "tx_avg_mbps": null, + "rx_avg_mbps": null, + "ping_rtt_ms": null, + "ping_loss_pct": null, + "error": "Результат теста скорости неизвестен: ответ устройства не получен. Проверьте его состояние перед повторным запуском." + } + ], + "automaticRetry": false, + "limits": [ + "Real Node HTTP client socket closed after request forwarded; RouterOS independently completed. Not physical WAN loss or cancelled native command.", + "Previous metrics deliberately seeded on own disabled probe, not new real measurements.", + "History error means application did not obtain confirmed test result; native completion was observed only by independent relay." + ], + "cleanupHistory": true, + "cleanupProbes": true +} \ No newline at end of file