fix(uptime): объяснить неизвестный результат теста скорости

This commit is contained in:
Denozordec committed 2026-10-10 01:41:15 +07:00
1 parent dbe1e7c917
commit 5944e5e751
13 files changed
+190 -24

No files matched your search

+12 -2
View File
@@ -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")
+2 -3
View File
@@ -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<boolean>
@@ -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 })
@@ -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
}
+2 -7
View File
@@ -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<Parameters<typeof db.transaction>[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<SpeedTestRunResult> {
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<SpeedWriteTransaction, SpeedProbeContext>(probeId ? {
id: probeId, srcServerId: params.srcServerId, dstServerId: params.dstServerId,
srcInterface: String(params.srcInterface ?? "").trim(), dstInterface: String(params.dstInterface ?? "").trim(),
+12 -2
View File
@@ -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.
+3 -3
View File
@@ -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).
+12 -2
View File
@@ -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)
+3 -3
View File
@@ -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 не закрывает их автоматически.
+10
View File
@@ -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.
+12 -2
View File
@@ -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.
@@ -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
}
@@ -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"
]
}
@@ -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
}