fix(ospf): показать конфликт состояний OSPF и BFD
This commit is contained in:
1 parent
4d3cb659c1
commit
12ead0b6c2
15 files changed
+6321
-18
No files matched your search
@@ -5,7 +5,7 @@ import { OspfTopologyScope } from "@/components/ospf-topology-scope"
|
||||
import { usePrefersReducedMotion } from "@/hooks/use-prefers-reduced-motion"
|
||||
import { deriveOspfRouterIdentity } from "@/lib/ospf-router-identity"
|
||||
import { buildOspfCostIndex, ospfCostKey } from "@/lib/ospf-cost"
|
||||
import { normalizeOspfState, normalizeBfdState, ospfNodeState, type OspfNeighborState, type BfdState } from "@/lib/ospf-state"
|
||||
import { normalizeOspfState, normalizeBfdState, ospfNodeState, ospfBfdConflicts, type OspfNeighborState, type BfdState } from "@/lib/ospf-state"
|
||||
import { useMemo, useState, useEffect, useRef, Suspense } from "react"
|
||||
import { useSearchParams } from "next/navigation"
|
||||
import { readOspfUrl, patchOspfUrl, type OspfTab } from "@/lib/ospf-url-state"
|
||||
@@ -62,6 +62,7 @@ interface OspfItem {
|
||||
}
|
||||
|
||||
interface OspfNeighbor {
|
||||
neighborAddress?: string
|
||||
id: string
|
||||
localRouter: string
|
||||
localLabel: string
|
||||
@@ -136,6 +137,7 @@ function backendToNeighbor(b: BackendNeighbor, ifaceMap: Map<string, number | nu
|
||||
remoteRouter: serverByRouterId[b.routerId] ?? b.routerId,
|
||||
remoteLabel: labels[serverByRouterId[b.routerId]] ?? b.routerId,
|
||||
remoteRouterId: b.routerId,
|
||||
neighborAddress: b.address,
|
||||
area: b.areaId !== b.area ? `${b.area} (${b.areaId})` : b.area,
|
||||
state,
|
||||
cost: ifaceMap.get(costKey) ?? null,
|
||||
@@ -1144,9 +1146,9 @@ function OspfRoute() {
|
||||
const href = patchOspfUrl(new URLSearchParams(window.location.search), values)
|
||||
if (href !== window.location.pathname + window.location.search) (replace ? window.history.replaceState : window.history.pushState).call(window.history, null, "", href)
|
||||
}
|
||||
return <OspfPageContent key={JSON.stringify([mode, backendUrl])} filterServerId={state.server} activeTab={state.tab} contextError={state.error} search={state.search} selectedNodeId={state.node} onSearch={value => navigate({ q: value }, true)} onSelectNode={node => navigate({ node })} onSelectServer={id => navigate({ server: id === ALL_SERVERS_ID ? null : id, node: null })} onSelectTab={tab => navigate({ tab: tab === "interfaces" ? null : tab })} onResetContext={() => navigate({ server: null, tab: null, q: null, node: null })} />
|
||||
return <OspfPageContent key={JSON.stringify([mode, backendUrl])} filterServerId={state.server} activeTab={state.tab} contextError={state.error} search={state.search} selectedNodeId={state.node} onSearch={value => navigate({ q: value }, true)} onSelectNode={node => navigate({ node })} onSelectServer={id => navigate({ server: id === ALL_SERVERS_ID ? null : id, node: null })} onSelectTab={tab => navigate({ tab: tab === "interfaces" ? null : tab })} onInspectBfd={() => navigate({ tab: "bfd", q: null })} onResetContext={() => navigate({ server: null, tab: null, q: null, node: null })} />
|
||||
}
|
||||
function OspfPageContent({ search, selectedNodeId, onSearch, onSelectNode, filterServerId, activeTab, contextError, onSelectServer, onSelectTab, onResetContext }: { search: string; selectedNodeId: string | null; onSearch: (value: string) => void; onSelectNode: (id: string | null) => void; filterServerId: string; activeTab: OspfTab; contextError: string | null; onSelectServer: (id: string) => void; onSelectTab: (tab: OspfTab) => void; onResetContext: () => void }) {
|
||||
function OspfPageContent({ search, selectedNodeId, onSearch, onSelectNode, filterServerId, activeTab, contextError, onSelectServer, onSelectTab, onInspectBfd, onResetContext }: { search: string; selectedNodeId: string | null; onSearch: (value: string) => void; onSelectNode: (id: string | null) => void; filterServerId: string; activeTab: OspfTab; contextError: string | null; onSelectServer: (id: string) => void; onSelectTab: (tab: OspfTab) => void; onInspectBfd: () => void; onResetContext: () => void }) {
|
||||
const { mode, backendUrl } = useDataSource()
|
||||
const isLive = mode === "live"
|
||||
|
||||
@@ -1272,6 +1274,7 @@ function OspfPageContent({ search, selectedNodeId, onSearch, onSelectNode, filte
|
||||
const scopedNeighbors = unavailable ? [] : filterServerId === ALL_SERVERS_ID ? neighbors : neighbors.filter(n => n.localRouter === filterServerId)
|
||||
const scopedBfdSessions = unavailable ? [] : filterServerId === ALL_SERVERS_ID ? bfdSessions : bfdSessions.filter(b => b.serverId === filterServerId)
|
||||
const scopedRoutes = unavailable ? [] : filterServerId === ALL_SERVERS_ID ? routes : routes.filter(r => r.serverId === filterServerId)
|
||||
const bfdConflicts = ospfBfdConflicts(scopedNeighbors, scopedItems, scopedBfdSessions)
|
||||
const query = search.trim().toLocaleLowerCase("ru")
|
||||
const matches = (...fields: (string | number | null | undefined)[]) => !query || fields.some(field => String(field ?? "").toLocaleLowerCase("ru").includes(query))
|
||||
const displayItems = scopedItems.filter(i => matches(i.routerLabel, i.interfaceName, i.area, i.type))
|
||||
@@ -1350,6 +1353,7 @@ function OspfPageContent({ search, selectedNodeId, onSearch, onSelectNode, filte
|
||||
<div className="flex flex-col gap-5">
|
||||
|
||||
{unavailable && <Alert variant="warning"><AlertCircleIcon /><AlertTitle>Контекст OSPF недоступен</AlertTitle><AlertDescription>{contextError ?? `Сервер ${filterServerId} отсутствует среди доступных устройств.`}<Button type="button" variant="outline" size="sm" disabled={writeBusy} onClick={onResetContext}>Сбросить контекст OSPF</Button></AlertDescription></Alert>}
|
||||
{bfdConflicts.length > 0 && <Alert variant="warning"><AlertCircleIcon /><AlertTitle>OSPF Full при недоступном BFD</AlertTitle><AlertDescription>Последний опрос: {bfdConflicts.map(n => `${n.localLabel} · ${n.localIface}`).join("; ")} — OSPF Full, BFD не Up. Проверьте канал: Full не подтверждает работу BFD.<Button type="button" variant="outline" size="sm" disabled={writeBusy} onClick={() => { if (!operationBusy.current) onInspectBfd() }}>Проверить BFD</Button></AlertDescription></Alert>}
|
||||
<DataPageToolbar search={search} onSearchChange={onSearch} searchPlaceholder="Поиск в текущем разделе OSPF…" countLabel={viewIncomplete ? "Данные неизвестны" : `${visibleCount} из ${scopeCount}`} actions={search ? <Button type="button" variant="ghost" size="sm" onClick={() => onSearch("")}>Сбросить поиск</Button> : undefined} />
|
||||
{/* data source banner */}
|
||||
{isLive && loading && (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# UX/UI: протокол внешней приёмки 12.5
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.152 — WireGuard IPv6 static lifecycle/create/PATCH/history/delete и single-address RSC/conf export/import.29 real API cases, native handshake/Ping3/3×2,33 disabled-server API/SQL cases всех трёх типов с zero ROS contacts,56 backend tests/профили GRE и контейнеров/live maps,10 E2E/types/ESLint/builds/984 parity/live PC/mobile passed. Runtime backend/frontend ux-wg152 healthy;12.5 открыт. Следующий153 — OSPF/BFD sustained gate: BFD-only loss при сохранённых OSPF Hello на собственных GRE, восстановление и independent cleanup.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.153 — предупреждение Full/BFD Down с точным device/interface/peer binding и переходом к BFD без потери device context.51 native rounds/30s подтвердили поздние Full+active при BFD Down; sustained route gate не гарантирован, а не ошибочно принят. Recovery/Ping3/3×2/10 baseline collections×2/cleanup,3 unit/9 E2E/2 real source UI/2 deployed smoke/types/ESLint/frontend build passed. Runtime backend ux-wg152/frontend ux-ospf153 healthy;12.5 открыт. Следующий154 — OSPFv3 IPv6 routes: добавить оба route catalogs с family-safe IDs и проверить собственную GRE IPv6 пару.
|
||||
|
||||
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).
|
||||
|
||||
@@ -696,7 +696,7 @@ flowchart LR
|
||||
|
||||
## 12.5.77 — основной блок IPsec (2026-10-09)
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.152 — WireGuard IPv6 static lifecycle/create/PATCH/history/delete и single-address RSC/conf export/import.29 real API cases, native handshake/Ping3/3×2,33 disabled-server API/SQL cases всех трёх типов с zero ROS contacts,56 backend tests/профили GRE и контейнеров/live maps,10 E2E/types/ESLint/builds/984 parity/live PC/mobile passed. Runtime backend/frontend ux-wg152 healthy;12.5 открыт. Следующий153 — OSPF/BFD sustained gate: BFD-only loss при сохранённых OSPF Hello на собственных GRE, восстановление и independent cleanup.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.153 — предупреждение Full/BFD Down с точным device/interface/peer binding и переходом к BFD без потери device context.51 native rounds/30s подтвердили поздние Full+active при BFD Down; sustained route gate не гарантирован, а не ошибочно принят. Recovery/Ping3/3×2/10 baseline collections×2/cleanup,3 unit/9 E2E/2 real source UI/2 deployed smoke/types/ESLint/frontend build passed. Runtime backend ux-wg152/frontend ux-ospf153 healthy;12.5 открыт. Следующий154 — OSPFv3 IPv6 routes: добавить оба route catalogs с family-safe IDs и проверить собственную GRE IPv6 пару.
|
||||
|
||||
Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md).
|
||||
|
||||
@@ -1669,3 +1669,17 @@ Runtime backend/frontend ux-wg152 healthy; deployed live read-only catalog/creat
|
||||
Протоколы: [native/cleanup](ux-ui/acceptance/wireguard-ipv6-native-2026-10-11.json), [API/history/import/export](ux-ui/acceptance/wireguard-ipv6-api-history-2026-10-11.json), [33 SQL/API gates](ux-ui/acceptance/network-disabled-sql-2026-10-11.json), [до исправления getter](ux-ui/acceptance/wireguard-ipv6-before-gate-api-2026-10-11.json), [compiled](ux-ui/acceptance/wireguard-ipv6-compiled-2026-10-11.json), [live UI](ux-ui/acceptance/wireguard-ipv6-smoke-2026-10-11.json).
|
||||
|
||||
Следующий153 — sustained OSPF/BFD-only gate и recovery на собственных GRE;12.5 остаётся открытым.
|
||||
|
||||
## 12.5.153 — граница OSPF/BFD и предупреждение конфликта состояний (2026-10-11)
|
||||
|
||||
В существующей OSPF странице ReUI/Frame/base-nova добавлено предупреждение последнего опроса: OSPF Full при наблюдаемом BFD Down/AdminDown. Correlation требует точный server/interface/neighbor IP, explicit active/useBfd=true, одну direct multihop=false BFD session и свежие данные; чужое устройство/интерфейс/peer, duplicate sessions, unknown/multihop/inactive/non-BFD template не создают вывод. Native Full/route states и правила RouterOS не меняются. Переход Проверить BFD сохраняет server/node context и атомарно снимает search, чтобы найденная сессия была видна. Референс остаётся существующий ReUI Data Grid/Frame, новые vendor components не устанавливались.
|
||||
|
||||
На обоих CHR собственные GRE198.18.153.0/30 и OSPFv2 loopbacks198.18.253.1/32↔2/32, hello1s/dead20s, BFD200ms×3. Два own firewall правила на CHR2 блокировали только UDP3784 input/output на own GRE с exact private src/dst. Protocol89/ICMP не блокировались; OSPF Hello отдельным packet capture не измерялся.51 native rounds около30s: BFD Down наблюдался, в поздних samples после20s оба OSPF neighbors Full и own route active. Это подтверждает отсутствие гарантированного постоянного route gate при BFD-only ACL loss; непрерывность каждого пакета/мгновенного состояния не заявляется. Data plane initial/fault/recovery Ping3/3×2. После удаления fault — BFD Up/Full/active, затем собственные firewall/OSPF/BFD/IP/bridge/GRE objects удалены.10 static collections×2 совпали с baseline; filter/BFD config order также сравнивался. Default/public routes и пароли сохранены.
|
||||
|
||||
UI native positive проверена в source Next dev3133 с настоящим backend8000, без JSON mocks и browser mutations:1440/320 показывают alert+native Full; переход ведёт к реальному Down, сохраняет server и очищает q. Скриншоты [1440](ux-ui/screens/ospf-bfd-conflict153-1440-2026-10-11.png), [320](ux-ui/screens/ospf-bfd-conflict153-320-2026-10-11.png); мобильный экран визуально проверен.3 unit cases,9 controlled E2E с recovery/foreign/non-BFD/unknown и previous data-cache scenarios, source types/ESLint passed. Read-only deployed PC/mobile smoke после cleanup подтвердил отсутствие ложного alert.
|
||||
|
||||
Frontend production build прошёл с окончательным source context; frontend ux-ospf153 развёрнут, backend ux-wg152/PG healthy. Первоначальная SCP сессия истекла в ожидании пароля; первый frontend candidate был собран без delta и не развёртывался. Context пересинхронизирован/хеш проверен, финальная сборка повторена и принята. Backend code/build не менялись, broad regression не повторялась. Только собственный завершённый container6a521d… удалён после exact-ID/state check; background main polling продолжался, собственная SQL база не создавалась.
|
||||
|
||||
Правила конфигурации сверены с [MikroTik BFD](https://manual.mikrotik.com/docs/user-guides/routing-and-networking-protocols/unicast/bfd/). Протоколы: [native51 samples/recovery/cleanup](ux-ui/acceptance/ospf-bfd-sustained-2026-10-11.json), [real source UI](ux-ui/acceptance/ospf-bfd-live-source-2026-10-11.json), [deployed smoke](ux-ui/acceptance/ospf-bfd-deployed-smoke-2026-10-11.json).
|
||||
|
||||
Границы: sustained BFD-only gate не гарантирован на RouterOS7.24.5; программа показывает реально наблюдаемый конфликт и не навязывает новые network rules. IPv6/scale/independent WAN/continuous packet loss/SLA не приняты этим блоком. Следующий154 — OSPFv3 IPv6 routes; существующий catalog читает только /ip/route, требуется family-safe /ipv6/route.12.5 открыт.
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
# План реализации UX/UI по пятичасовым окнам
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.152 — WireGuard IPv6 static lifecycle/create/PATCH/history/delete и single-address RSC/conf export/import.29 real API cases, native handshake/Ping3/3×2,33 disabled-server API/SQL cases всех трёх типов с zero ROS contacts,56 backend tests/профили GRE и контейнеров/live maps,10 E2E/types/ESLint/builds/984 parity/live PC/mobile passed. Runtime backend/frontend ux-wg152 healthy;12.5 открыт. Следующий153 — OSPF/BFD sustained gate: BFD-only loss при сохранённых OSPF Hello на собственных GRE, восстановление и independent cleanup.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.153 — предупреждение Full/BFD Down с точным device/interface/peer binding и переходом к BFD без потери device context.51 native rounds/30s подтвердили поздние Full+active при BFD Down; sustained route gate не гарантирован, а не ошибочно принят. Recovery/Ping3/3×2/10 baseline collections×2/cleanup,3 unit/9 E2E/2 real source UI/2 deployed smoke/types/ESLint/frontend build passed. Runtime backend ux-wg152/frontend ux-ospf153 healthy;12.5 открыт. Следующий154 — OSPFv3 IPv6 routes: добавить оба route catalogs с family-safe IDs и проверить собственную GRE IPv6 пару.
|
||||
|
||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-10. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||
|
||||
## Актуальная точка продолжения — 2026-10-10
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.152 — WireGuard IPv6 static lifecycle/create/PATCH/history/delete и single-address RSC/conf export/import.29 real API cases, native handshake/Ping3/3×2,33 disabled-server API/SQL cases всех трёх типов с zero ROS contacts,56 backend tests/профили GRE и контейнеров/live maps,10 E2E/types/ESLint/builds/984 parity/live PC/mobile passed. Runtime backend/frontend ux-wg152 healthy;12.5 открыт. Следующий153 — OSPF/BFD sustained gate: BFD-only loss при сохранённых OSPF Hello на собственных GRE, восстановление и independent cleanup.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.153 — предупреждение Full/BFD Down с точным device/interface/peer binding и переходом к BFD без потери device context.51 native rounds/30s подтвердили поздние Full+active при BFD Down; sustained route gate не гарантирован, а не ошибочно принят. Recovery/Ping3/3×2/10 baseline collections×2/cleanup,3 unit/9 E2E/2 real source UI/2 deployed smoke/types/ESLint/frontend build passed. Runtime backend ux-wg152/frontend ux-ospf153 healthy;12.5 открыт. Следующий154 — OSPFv3 IPv6 routes: добавить оба route catalogs с family-safe IDs и проверить собственную GRE IPv6 пару.
|
||||
|
||||
Этапы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-11: завершён12.5.152 — WireGuard IPv6 static lifecycle/create/PATCH/history/delete и single-address RSC/conf export/import.29 real API cases, native handshake/Ping3/3×2,33 disabled-server API/SQL cases всех трёх типов с zero ROS contacts,56 backend tests/профили GRE и контейнеров/live maps,10 E2E/types/ESLint/builds/984 parity/live PC/mobile passed. Runtime backend/frontend ux-wg152 healthy;12.5 открыт. Следующий153 — OSPF/BFD sustained gate: BFD-only loss при сохранённых OSPF Hello на собственных GRE, восстановление и independent cleanup.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.153 — предупреждение Full/BFD Down с точным device/interface/peer binding и переходом к BFD без потери device context.51 native rounds/30s подтвердили поздние Full+active при BFD Down; sustained route gate не гарантирован, а не ошибочно принят. Recovery/Ping3/3×2/10 baseline collections×2/cleanup,3 unit/9 E2E/2 real source UI/2 deployed smoke/types/ESLint/frontend build passed. Runtime backend ux-wg152/frontend ux-ospf153 healthy;12.5 открыт. Следующий154 — OSPFv3 IPv6 routes: добавить оба route catalogs с family-safe IDs и проверить собственную GRE IPv6 пару.
|
||||
|
||||
Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md).
|
||||
+16
-2
@@ -1,6 +1,6 @@
|
||||
# UX/UI: журнал реализации
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.152 — WireGuard IPv6 static lifecycle/create/PATCH/history/delete и single-address RSC/conf export/import.29 real API cases, native handshake/Ping3/3×2,33 disabled-server API/SQL cases всех трёх типов с zero ROS contacts,56 backend tests/профили GRE и контейнеров/live maps,10 E2E/types/ESLint/builds/984 parity/live PC/mobile passed. Runtime backend/frontend ux-wg152 healthy;12.5 открыт. Следующий153 — OSPF/BFD sustained gate: BFD-only loss при сохранённых OSPF Hello на собственных GRE, восстановление и independent cleanup.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.153 — предупреждение Full/BFD Down с точным device/interface/peer binding и переходом к BFD без потери device context.51 native rounds/30s подтвердили поздние Full+active при BFD Down; sustained route gate не гарантирован, а не ошибочно принят. Recovery/Ping3/3×2/10 baseline collections×2/cleanup,3 unit/9 E2E/2 real source UI/2 deployed smoke/types/ESLint/frontend build passed. Runtime backend ux-wg152/frontend ux-ospf153 healthy;12.5 открыт. Следующий154 — OSPFv3 IPv6 routes: добавить оба route catalogs с family-safe IDs и проверить собственную GRE IPv6 пару.
|
||||
|
||||
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
||||
|
||||
@@ -36,7 +36,21 @@
|
||||
| 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–152 и ограничения ниже. Runtime backend ux-month149/frontend ux-sessions150. |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–153 и ограничения ниже. Runtime backend ux-month149/frontend ux-sessions150. |
|
||||
|
||||
## 12.5.153 — граница OSPF/BFD и предупреждение конфликта состояний (2026-10-11)
|
||||
|
||||
В существующей OSPF странице ReUI/Frame/base-nova добавлено предупреждение последнего опроса: OSPF Full при наблюдаемом BFD Down/AdminDown. Correlation требует точный server/interface/neighbor IP, explicit active/useBfd=true, одну direct multihop=false BFD session и свежие данные; чужое устройство/интерфейс/peer, duplicate sessions, unknown/multihop/inactive/non-BFD template не создают вывод. Native Full/route states и правила RouterOS не меняются. Переход Проверить BFD сохраняет server/node context и атомарно снимает search, чтобы найденная сессия была видна. Референс остаётся существующий ReUI Data Grid/Frame, новые vendor components не устанавливались.
|
||||
|
||||
На обоих CHR собственные GRE198.18.153.0/30 и OSPFv2 loopbacks198.18.253.1/32↔2/32, hello1s/dead20s, BFD200ms×3. Два own firewall правила на CHR2 блокировали только UDP3784 input/output на own GRE с exact private src/dst. Protocol89/ICMP не блокировались; OSPF Hello отдельным packet capture не измерялся.51 native rounds около30s: BFD Down наблюдался, в поздних samples после20s оба OSPF neighbors Full и own route active. Это подтверждает отсутствие гарантированного постоянного route gate при BFD-only ACL loss; непрерывность каждого пакета/мгновенного состояния не заявляется. Data plane initial/fault/recovery Ping3/3×2. После удаления fault — BFD Up/Full/active, затем собственные firewall/OSPF/BFD/IP/bridge/GRE objects удалены.10 static collections×2 совпали с baseline; filter/BFD config order также сравнивался. Default/public routes и пароли сохранены.
|
||||
|
||||
UI native positive проверена в source Next dev3133 с настоящим backend8000, без JSON mocks и browser mutations:1440/320 показывают alert+native Full; переход ведёт к реальному Down, сохраняет server и очищает q. Скриншоты [1440](ux-ui/screens/ospf-bfd-conflict153-1440-2026-10-11.png), [320](ux-ui/screens/ospf-bfd-conflict153-320-2026-10-11.png); мобильный экран визуально проверен.3 unit cases,9 controlled E2E с recovery/foreign/non-BFD/unknown и previous data-cache scenarios, source types/ESLint passed. Read-only deployed PC/mobile smoke после cleanup подтвердил отсутствие ложного alert.
|
||||
|
||||
Frontend production build прошёл с окончательным source context; frontend ux-ospf153 развёрнут, backend ux-wg152/PG healthy. Первоначальная SCP сессия истекла в ожидании пароля; первый frontend candidate был собран без delta и не развёртывался. Context пересинхронизирован/хеш проверен, финальная сборка повторена и принята. Backend code/build не менялись, broad regression не повторялась. Только собственный завершённый container6a521d… удалён после exact-ID/state check; background main polling продолжался, собственная SQL база не создавалась.
|
||||
|
||||
Правила конфигурации сверены с [MikroTik BFD](https://manual.mikrotik.com/docs/user-guides/routing-and-networking-protocols/unicast/bfd/). Протоколы: [native51 samples/recovery/cleanup](ux-ui/acceptance/ospf-bfd-sustained-2026-10-11.json), [real source UI](ux-ui/acceptance/ospf-bfd-live-source-2026-10-11.json), [deployed smoke](ux-ui/acceptance/ospf-bfd-deployed-smoke-2026-10-11.json).
|
||||
|
||||
Границы: sustained BFD-only gate не гарантирован на RouterOS7.24.5; программа показывает реально наблюдаемый конфликт и не навязывает новые network rules. IPv6/scale/independent WAN/continuous packet loss/SLA не приняты этим блоком. Следующий154 — OSPFv3 IPv6 routes; существующий catalog читает только /ip/route, требуется family-safe /ipv6/route.12.5 открыт.
|
||||
|
||||
## 12.5.152 — IPv6 lifecycle WireGuard и общий допуск выключенных серверов (2026-10-11)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Оставшаяся внешняя приёмка — 2026-10-11
|
||||
|
||||
Это актуальная матрица после 12.5.152. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||
Это актуальная матрица после 12.5.153. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||
|
||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-wg152`, frontend `ux-wg152`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-wg152`, frontend `ux-ospf153`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
||||
|
||||
| Раздел | Подтверждено | Осталось / условие завершения |
|
||||
| --- | --- | --- |
|
||||
@@ -13,12 +13,12 @@
|
||||
| WireGuard | Native handshake/data plane58, deletion60, live create/peer/disable/enable/delete62, mobile64, export/import67–74; native IPv6 ULA inner/allowedIps/handshake109; application static IPv6 lifecycle152 | Клиентские ОС и произвольные конфигурации, IPv6 outer/scale, from-pool/EUI-64 и multiple-address import/export, физический lost ACK и устойчивое восстановление; `.conf` с placeholders — шаблон, не принятый клиентский tunnel |
|
||||
| VXLAN | Собственная пара/private Ping/catalog/URL/export75–76; bridge/FDB/port loss/recovery107; IPv6 ULA inner по IPv4 outer108 | API приложения read-only: create/delete проверены native. IPv6 outer, масштаб/производительность, профильные mutation RBAC/concurrency отдельно не приняты |
|
||||
| IPsec | PSK и сертификатное шифрование77–82, active peer/online/mode-config, scoped NAT/group, partial/unknown/applied receipts, restore conflicts, JWT; full DN/специальные символы/online110; literal CN namespace guards и explicit FQDN111; certificate/PSK shared ID unknown/recovery112; multiple sessions controlled snapshots113; shared certificate rows/target guards114; preserve-certificate UI/native DELETE115; explicit deletion binding/PSK collision116; legacy export binding118; real duplicate DN sessions/Linux Ping/UI119; DN DER/ASCII tag и FQDN SAN native120; implicit unique DNS SAN/mixed IDs/API/UI121; короткий CHILD/IKE rekey/reconnect122; server pin и unbound same-CA certificate refusal123; own RSA Root/Intermediate/client chain/CRLs/IKE/reauth138; external revoked CRL new-handshake refusal/existing-session boundary137; certificate-bound malformed/signed expired CRL IKE refusal/recovery136; certificate-bound missing-CDP404/IKE refusal and recovery135; external HTTP CRL download/404/cache preservation134; isolated diagnostic buffers132; own ECDSA P-256/Ping/API export131 and final18×2 inventory; isolated same-key/CA time boundary with explicit AUTH_FAILED130; valid-renewal control timeout/clock/log observation129; original/renewed controls and time-invalid timeout observation128; CRL-issued cert/CA no-write delete guards127; own CRL-enabled valid/revoked control126; local revoked flag/CRL-disabled reconnect observation125; certificate reauth/CHILD absence boundary/UI124 | Реальные duplicate certificate-derived DN sessions приняты119; arbitrary custom PKI/OIDs/policies/path-length and missing/intermediate-revoked chain; native intermediate chain accepted138; ECDSA P-256 accepted131;128/129 timeout cause still unknown,130 time boundary accepted; periodic refresh; existing IKE survives short external-revocation observation137, automatic termination not guaranteed; direct CHR-to-CHR CRL HTTP failure cause134; reauth/CHILD loss принят124; длительный rekey/переходная потеря пакетов; прочие ID типы/ADDR4/manual DN/custom PKI; native edit identical matching rules rejected; клиентские Windows/macOS/iOS/Android, прочие DN форматы/custom OIDs/IKE ID namespaces, полная PKI и policy/profile/proposal restore, физический disconnect, durable retry/multi-instance, IPv6/maximum throughput |
|
||||
| OSPF/BFD | Real Full/own routes84–85, раздельные наблюдения BFD86, effective disabled/optimizer cost/partial/RBAC87, alternate path90 и CIDR91 | Sustained BFD-only gate не принят: в86 сосед мог вновь статьFull при доступныхHello. В90 переходный Ping18/40 с55% loss: бесшовность не принята. REST timing — наблюдаемая граница, не SLA; IPv6/scale/independent WAN открыты |
|
||||
| OSPF/BFD | Real Full/own routes84–85, раздельные наблюдения BFD86, effective disabled/optimizer cost/partial/RBAC87, alternate path90 и CIDR91 | BFD-only sustained route gate не гарантирован:153 подтвердил поздние Full/active при BFD Down в30s samples, UI предупреждение/recovery принято. В90 переходный Ping18/40 с55% loss: бесшовность не принята. REST timing — наблюдаемая граница, не SLA; IPv6/scale/independent WAN открыты |
|
||||
| BGP | Established83, exact /32 exchange/API/UI/administrative withdrawal92, BFD primary GRE loss/alternate/recovery93 | Hold timer/TCP loss безBFD принят104; packet loss в переходе, разные внешние peers/WAN policy, IPv6/scale. Два логических пути используют тот же public WAN; physical redundancy не принята |
|
||||
| Recursive routes | Production PUT/change/own history restore88, disabled guards, partial/unknown/applied outcomes, live формы/контекст | Автоматический rollback/retry, durable receipts и несколько экземпляров отсутствуют; PUT не является idempotent noop. Полная произвольная legacy catalog миграция не принята |
|
||||
| Diagnostics/terminal | Allowlist/native reads, Ping/trace/route/MTU/DNS, actual avg-rtt, disabled guards, JWT/live PC/mobile89; real default memory tail/log limits/API/UI133 | DNS использует backend resolver; MTU — ограниченная оценка, не гарантированный максимум. Stop ожидания не доказывает остановку RouterOS команды; arbitrary CLI и physical disconnect не приняты |
|
||||
| Portal/интеграции | Локальные и isolated JWT guards; UI/API error states в границах журналов | Настоящий Portal issuer/login/отзыв прав; RIPE SDK two-IP/no-fetch passed140, native IPv6 ULA flow pipeline passed145 (IPv4 transport), public IPv6 WAN/local licensed MaxMind/S3/container/certificate jobs и Gitea delivery требуют отдельных тестовых endpoints/аккаунтов. Не отправлять сообщения и не публиковать релиз без соответствующего поручения |
|
||||
| Общая приёмка | Локальная12.3.83; UI1244/context221/compiled984 parity139; профильные build/E2E/live проверки последующих блоков | Traffic initial live mock-id gate passed141; IPv6 special ranges/cache passed142; unknown RIPE coordinates passed143; IPv6 synthetic UDP/worker/SQL passed144; native CHR ULA/IPFIX/API/UI passed145; ICMPv6/IPv6 endpoint labels passed146; HTTP DTO validation passed147; scoped flow catalog/serverId guards passed148; strict monthly calendar passed149; Sessions labels passed150; application GRE static IPv6 lifecycle151 passed; WireGuard static IPv6 lifecycle152 и disabled SQL/API gates passed; следующий sustained OSPF/BFD153; последующие изменения проверять отдельно; scoped axe не означает полную WCAG сертификацию |
|
||||
| Общая приёмка | Локальная12.3.83; UI1244/context221/compiled984 parity139; профильные build/E2E/live проверки последующих блоков | Traffic initial live mock-id gate passed141; IPv6 special ranges/cache passed142; unknown RIPE coordinates passed143; IPv6 synthetic UDP/worker/SQL passed144; native CHR ULA/IPFIX/API/UI passed145; ICMPv6/IPv6 endpoint labels passed146; HTTP DTO validation passed147; scoped flow catalog/serverId guards passed148; strict monthly calendar passed149; Sessions labels passed150; application GRE static IPv6 lifecycle151 passed; WireGuard static IPv6 lifecycle152 и disabled SQL/API gates passed; OSPF/BFD boundary/warning153 passed; следующий OSPFv3 IPv6 routes154; последующие изменения проверять отдельно; scoped axe не означает полную WCAG сертификацию |
|
||||
|
||||
Доказательства и точные ограничения: [полная история этапа12](ux-ui-stage-12.md), [внешний протокол](ux-ui-external-acceptance.md), [BGP93](ux-ui/acceptance/bgp-failover-2026-10-10.json), [паспорт стенда](ux-ui-test-server.md). Невыполненные пункты не являются все блокерами данного лабораторного сценария: для выпуска необходимо явно определить требуемые конфигурации и принять их либо согласовать ограничение.
|
||||
|
||||
@@ -584,3 +584,17 @@ Runtime backend/frontend ux-wg152 healthy; deployed live read-only catalog/creat
|
||||
Протоколы: [native/cleanup](ux-ui/acceptance/wireguard-ipv6-native-2026-10-11.json), [API/history/import/export](ux-ui/acceptance/wireguard-ipv6-api-history-2026-10-11.json), [33 SQL/API gates](ux-ui/acceptance/network-disabled-sql-2026-10-11.json), [до исправления getter](ux-ui/acceptance/wireguard-ipv6-before-gate-api-2026-10-11.json), [compiled](ux-ui/acceptance/wireguard-ipv6-compiled-2026-10-11.json), [live UI](ux-ui/acceptance/wireguard-ipv6-smoke-2026-10-11.json).
|
||||
|
||||
Следующий153 — sustained OSPF/BFD-only gate и recovery на собственных GRE;12.5 остаётся открытым.
|
||||
|
||||
## 12.5.153 — граница OSPF/BFD и предупреждение конфликта состояний (2026-10-11)
|
||||
|
||||
В существующей OSPF странице ReUI/Frame/base-nova добавлено предупреждение последнего опроса: OSPF Full при наблюдаемом BFD Down/AdminDown. Correlation требует точный server/interface/neighbor IP, explicit active/useBfd=true, одну direct multihop=false BFD session и свежие данные; чужое устройство/интерфейс/peer, duplicate sessions, unknown/multihop/inactive/non-BFD template не создают вывод. Native Full/route states и правила RouterOS не меняются. Переход Проверить BFD сохраняет server/node context и атомарно снимает search, чтобы найденная сессия была видна. Референс остаётся существующий ReUI Data Grid/Frame, новые vendor components не устанавливались.
|
||||
|
||||
На обоих CHR собственные GRE198.18.153.0/30 и OSPFv2 loopbacks198.18.253.1/32↔2/32, hello1s/dead20s, BFD200ms×3. Два own firewall правила на CHR2 блокировали только UDP3784 input/output на own GRE с exact private src/dst. Protocol89/ICMP не блокировались; OSPF Hello отдельным packet capture не измерялся.51 native rounds около30s: BFD Down наблюдался, в поздних samples после20s оба OSPF neighbors Full и own route active. Это подтверждает отсутствие гарантированного постоянного route gate при BFD-only ACL loss; непрерывность каждого пакета/мгновенного состояния не заявляется. Data plane initial/fault/recovery Ping3/3×2. После удаления fault — BFD Up/Full/active, затем собственные firewall/OSPF/BFD/IP/bridge/GRE objects удалены.10 static collections×2 совпали с baseline; filter/BFD config order также сравнивался. Default/public routes и пароли сохранены.
|
||||
|
||||
UI native positive проверена в source Next dev3133 с настоящим backend8000, без JSON mocks и browser mutations:1440/320 показывают alert+native Full; переход ведёт к реальному Down, сохраняет server и очищает q. Скриншоты [1440](ux-ui/screens/ospf-bfd-conflict153-1440-2026-10-11.png), [320](ux-ui/screens/ospf-bfd-conflict153-320-2026-10-11.png); мобильный экран визуально проверен.3 unit cases,9 controlled E2E с recovery/foreign/non-BFD/unknown и previous data-cache scenarios, source types/ESLint passed. Read-only deployed PC/mobile smoke после cleanup подтвердил отсутствие ложного alert.
|
||||
|
||||
Frontend production build прошёл с окончательным source context; frontend ux-ospf153 развёрнут, backend ux-wg152/PG healthy. Первоначальная SCP сессия истекла в ожидании пароля; первый frontend candidate был собран без delta и не развёртывался. Context пересинхронизирован/хеш проверен, финальная сборка повторена и принята. Backend code/build не менялись, broad regression не повторялась. Только собственный завершённый container6a521d… удалён после exact-ID/state check; background main polling продолжался, собственная SQL база не создавалась.
|
||||
|
||||
Правила конфигурации сверены с [MikroTik BFD](https://manual.mikrotik.com/docs/user-guides/routing-and-networking-protocols/unicast/bfd/). Протоколы: [native51 samples/recovery/cleanup](ux-ui/acceptance/ospf-bfd-sustained-2026-10-11.json), [real source UI](ux-ui/acceptance/ospf-bfd-live-source-2026-10-11.json), [deployed smoke](ux-ui/acceptance/ospf-bfd-deployed-smoke-2026-10-11.json).
|
||||
|
||||
Границы: sustained BFD-only gate не гарантирован на RouterOS7.24.5; программа показывает реально наблюдаемый конфликт и не навязывает новые network rules. IPv6/scale/independent WAN/continuous packet loss/SLA не приняты этим блоком. Следующий154 — OSPFv3 IPv6 routes; существующий catalog читает только /ip/route, требуется family-safe /ipv6/route.12.5 открыт.
|
||||
+15
-1
@@ -1,6 +1,6 @@
|
||||
# Этап 12: итоговая приёмка UX/UI
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.152 — WireGuard IPv6 static lifecycle/create/PATCH/history/delete и single-address RSC/conf export/import.29 real API cases, native handshake/Ping3/3×2,33 disabled-server API/SQL cases всех трёх типов с zero ROS contacts,56 backend tests/профили GRE и контейнеров/live maps,10 E2E/types/ESLint/builds/984 parity/live PC/mobile passed. Runtime backend/frontend ux-wg152 healthy;12.5 открыт. Следующий153 — OSPF/BFD sustained gate: BFD-only loss при сохранённых OSPF Hello на собственных GRE, восстановление и independent cleanup.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.153 — предупреждение Full/BFD Down с точным device/interface/peer binding и переходом к BFD без потери device context.51 native rounds/30s подтвердили поздние Full+active при BFD Down; sustained route gate не гарантирован, а не ошибочно принят. Recovery/Ping3/3×2/10 baseline collections×2/cleanup,3 unit/9 E2E/2 real source UI/2 deployed smoke/types/ESLint/frontend build passed. Runtime backend ux-wg152/frontend ux-ospf153 healthy;12.5 открыт. Следующий154 — OSPFv3 IPv6 routes: добавить оба route catalogs с family-safe IDs и проверить собственную GRE IPv6 пару.
|
||||
|
||||
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
||||
|
||||
@@ -2974,3 +2974,17 @@ Runtime backend/frontend ux-wg152 healthy; deployed live read-only catalog/creat
|
||||
Протоколы: [native/cleanup](ux-ui/acceptance/wireguard-ipv6-native-2026-10-11.json), [API/history/import/export](ux-ui/acceptance/wireguard-ipv6-api-history-2026-10-11.json), [33 SQL/API gates](ux-ui/acceptance/network-disabled-sql-2026-10-11.json), [до исправления getter](ux-ui/acceptance/wireguard-ipv6-before-gate-api-2026-10-11.json), [compiled](ux-ui/acceptance/wireguard-ipv6-compiled-2026-10-11.json), [live UI](ux-ui/acceptance/wireguard-ipv6-smoke-2026-10-11.json).
|
||||
|
||||
Следующий153 — sustained OSPF/BFD-only gate и recovery на собственных GRE;12.5 остаётся открытым.
|
||||
|
||||
## 12.5.153 — граница OSPF/BFD и предупреждение конфликта состояний (2026-10-11)
|
||||
|
||||
В существующей OSPF странице ReUI/Frame/base-nova добавлено предупреждение последнего опроса: OSPF Full при наблюдаемом BFD Down/AdminDown. Correlation требует точный server/interface/neighbor IP, explicit active/useBfd=true, одну direct multihop=false BFD session и свежие данные; чужое устройство/интерфейс/peer, duplicate sessions, unknown/multihop/inactive/non-BFD template не создают вывод. Native Full/route states и правила RouterOS не меняются. Переход Проверить BFD сохраняет server/node context и атомарно снимает search, чтобы найденная сессия была видна. Референс остаётся существующий ReUI Data Grid/Frame, новые vendor components не устанавливались.
|
||||
|
||||
На обоих CHR собственные GRE198.18.153.0/30 и OSPFv2 loopbacks198.18.253.1/32↔2/32, hello1s/dead20s, BFD200ms×3. Два own firewall правила на CHR2 блокировали только UDP3784 input/output на own GRE с exact private src/dst. Protocol89/ICMP не блокировались; OSPF Hello отдельным packet capture не измерялся.51 native rounds около30s: BFD Down наблюдался, в поздних samples после20s оба OSPF neighbors Full и own route active. Это подтверждает отсутствие гарантированного постоянного route gate при BFD-only ACL loss; непрерывность каждого пакета/мгновенного состояния не заявляется. Data plane initial/fault/recovery Ping3/3×2. После удаления fault — BFD Up/Full/active, затем собственные firewall/OSPF/BFD/IP/bridge/GRE objects удалены.10 static collections×2 совпали с baseline; filter/BFD config order также сравнивался. Default/public routes и пароли сохранены.
|
||||
|
||||
UI native positive проверена в source Next dev3133 с настоящим backend8000, без JSON mocks и browser mutations:1440/320 показывают alert+native Full; переход ведёт к реальному Down, сохраняет server и очищает q. Скриншоты [1440](ux-ui/screens/ospf-bfd-conflict153-1440-2026-10-11.png), [320](ux-ui/screens/ospf-bfd-conflict153-320-2026-10-11.png); мобильный экран визуально проверен.3 unit cases,9 controlled E2E с recovery/foreign/non-BFD/unknown и previous data-cache scenarios, source types/ESLint passed. Read-only deployed PC/mobile smoke после cleanup подтвердил отсутствие ложного alert.
|
||||
|
||||
Frontend production build прошёл с окончательным source context; frontend ux-ospf153 развёрнут, backend ux-wg152/PG healthy. Первоначальная SCP сессия истекла в ожидании пароля; первый frontend candidate был собран без delta и не развёртывался. Context пересинхронизирован/хеш проверен, финальная сборка повторена и принята. Backend code/build не менялись, broad regression не повторялась. Только собственный завершённый container6a521d… удалён после exact-ID/state check; background main polling продолжался, собственная SQL база не создавалась.
|
||||
|
||||
Правила конфигурации сверены с [MikroTik BFD](https://manual.mikrotik.com/docs/user-guides/routing-and-networking-protocols/unicast/bfd/). Протоколы: [native51 samples/recovery/cleanup](ux-ui/acceptance/ospf-bfd-sustained-2026-10-11.json), [real source UI](ux-ui/acceptance/ospf-bfd-live-source-2026-10-11.json), [deployed smoke](ux-ui/acceptance/ospf-bfd-deployed-smoke-2026-10-11.json).
|
||||
|
||||
Границы: sustained BFD-only gate не гарантирован на RouterOS7.24.5; программа показывает реально наблюдаемый конфликт и не навязывает новые network rules. IPv6/scale/independent WAN/continuous packet loss/SLA не приняты этим блоком. Следующий154 — OSPFv3 IPv6 routes; существующий catalog читает только /ip/route, требуется family-safe /ipv6/route.12.5 открыт.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Тестовый сервер UX/UI — 2026-10-10
|
||||
|
||||
Сервер161.104.46.222: завершён12.5.152 — WireGuard IPv6 static lifecycle/create/PATCH/history/delete и single-address RSC/conf export/import.29 real API cases, native handshake/Ping3/3×2,33 disabled-server API/SQL cases всех трёх типов с zero ROS contacts,56 backend tests/профили GRE и контейнеров/live maps,10 E2E/types/ESLint/builds/984 parity/live PC/mobile passed. Runtime backend/frontend ux-wg152 healthy;12.5 открыт. Следующий153 — OSPF/BFD sustained gate: BFD-only loss при сохранённых OSPF Hello на собственных GRE, восстановление и independent cleanup.
|
||||
Сервер161.104.46.222: завершён12.5.153 — предупреждение Full/BFD Down с точным device/interface/peer binding и переходом к BFD без потери device context.51 native rounds/30s подтвердили поздние Full+active при BFD Down; sustained route gate не гарантирован, а не ошибочно принят. Recovery/Ping3/3×2/10 baseline collections×2/cleanup,3 unit/9 E2E/2 real source UI/2 deployed smoke/types/ESLint/frontend build passed. Runtime backend ux-wg152/frontend ux-ospf153 healthy;12.5 открыт. Следующий154 — OSPFv3 IPv6 routes: добавить оба route catalogs с family-safe IDs и проверить собственную GRE IPv6 пару.
|
||||
|
||||
| Параметр | Проверенное состояние |
|
||||
| --- | --- |
|
||||
@@ -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-wg152 и mmapp-test/frontend:ux-wg152; запущены |
|
||||
| Образы приложения | mmapp-test/backend:ux-wg152 и mmapp-test/frontend:ux-ospf153; запущены |
|
||||
|
||||
Compose SHA256:3052bd6ab5d9865f97605cebfb5ff27a4410cd3357b81153a65a87fb7c92582f. OptionalBACKEND_IMAGE_TAG позволяетобновлятьbackendотдельно. Локальный и удалённый файлы совпали. Шаблоны: [Compose](../deploy/docker-compose.test.yml), [env без секретов](../deploy/env.test.example).
|
||||
|
||||
@@ -1400,3 +1400,17 @@ Runtime backend/frontend ux-wg152 healthy; deployed live read-only catalog/creat
|
||||
Протоколы: [native/cleanup](ux-ui/acceptance/wireguard-ipv6-native-2026-10-11.json), [API/history/import/export](ux-ui/acceptance/wireguard-ipv6-api-history-2026-10-11.json), [33 SQL/API gates](ux-ui/acceptance/network-disabled-sql-2026-10-11.json), [до исправления getter](ux-ui/acceptance/wireguard-ipv6-before-gate-api-2026-10-11.json), [compiled](ux-ui/acceptance/wireguard-ipv6-compiled-2026-10-11.json), [live UI](ux-ui/acceptance/wireguard-ipv6-smoke-2026-10-11.json).
|
||||
|
||||
Следующий153 — sustained OSPF/BFD-only gate и recovery на собственных GRE;12.5 остаётся открытым.
|
||||
|
||||
## 12.5.153 — граница OSPF/BFD и предупреждение конфликта состояний (2026-10-11)
|
||||
|
||||
В существующей OSPF странице ReUI/Frame/base-nova добавлено предупреждение последнего опроса: OSPF Full при наблюдаемом BFD Down/AdminDown. Correlation требует точный server/interface/neighbor IP, explicit active/useBfd=true, одну direct multihop=false BFD session и свежие данные; чужое устройство/интерфейс/peer, duplicate sessions, unknown/multihop/inactive/non-BFD template не создают вывод. Native Full/route states и правила RouterOS не меняются. Переход Проверить BFD сохраняет server/node context и атомарно снимает search, чтобы найденная сессия была видна. Референс остаётся существующий ReUI Data Grid/Frame, новые vendor components не устанавливались.
|
||||
|
||||
На обоих CHR собственные GRE198.18.153.0/30 и OSPFv2 loopbacks198.18.253.1/32↔2/32, hello1s/dead20s, BFD200ms×3. Два own firewall правила на CHR2 блокировали только UDP3784 input/output на own GRE с exact private src/dst. Protocol89/ICMP не блокировались; OSPF Hello отдельным packet capture не измерялся.51 native rounds около30s: BFD Down наблюдался, в поздних samples после20s оба OSPF neighbors Full и own route active. Это подтверждает отсутствие гарантированного постоянного route gate при BFD-only ACL loss; непрерывность каждого пакета/мгновенного состояния не заявляется. Data plane initial/fault/recovery Ping3/3×2. После удаления fault — BFD Up/Full/active, затем собственные firewall/OSPF/BFD/IP/bridge/GRE objects удалены.10 static collections×2 совпали с baseline; filter/BFD config order также сравнивался. Default/public routes и пароли сохранены.
|
||||
|
||||
UI native positive проверена в source Next dev3133 с настоящим backend8000, без JSON mocks и browser mutations:1440/320 показывают alert+native Full; переход ведёт к реальному Down, сохраняет server и очищает q. Скриншоты [1440](ux-ui/screens/ospf-bfd-conflict153-1440-2026-10-11.png), [320](ux-ui/screens/ospf-bfd-conflict153-320-2026-10-11.png); мобильный экран визуально проверен.3 unit cases,9 controlled E2E с recovery/foreign/non-BFD/unknown и previous data-cache scenarios, source types/ESLint passed. Read-only deployed PC/mobile smoke после cleanup подтвердил отсутствие ложного alert.
|
||||
|
||||
Frontend production build прошёл с окончательным source context; frontend ux-ospf153 развёрнут, backend ux-wg152/PG healthy. Первоначальная SCP сессия истекла в ожидании пароля; первый frontend candidate был собран без delta и не развёртывался. Context пересинхронизирован/хеш проверен, финальная сборка повторена и принята. Backend code/build не менялись, broad regression не повторялась. Только собственный завершённый container6a521d… удалён после exact-ID/state check; background main polling продолжался, собственная SQL база не создавалась.
|
||||
|
||||
Правила конфигурации сверены с [MikroTik BFD](https://manual.mikrotik.com/docs/user-guides/routing-and-networking-protocols/unicast/bfd/). Протоколы: [native51 samples/recovery/cleanup](ux-ui/acceptance/ospf-bfd-sustained-2026-10-11.json), [real source UI](ux-ui/acceptance/ospf-bfd-live-source-2026-10-11.json), [deployed smoke](ux-ui/acceptance/ospf-bfd-deployed-smoke-2026-10-11.json).
|
||||
|
||||
Границы: sustained BFD-only gate не гарантирован на RouterOS7.24.5; программа показывает реально наблюдаемый конфликт и не навязывает новые network rules. IPv6/scale/independent WAN/continuous packet loss/SLA не приняты этим блоком. Следующий154 — OSPFv3 IPv6 routes; существующий catalog читает только /ip/route, требуется family-safe /ipv6/route.12.5 открыт.
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"date": "2026-10-11",
|
||||
"block": "12.5.153",
|
||||
"runtime": {
|
||||
"backend": "ux-wg152",
|
||||
"frontend": "ux-ospf153"
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"width": 1440,
|
||||
"status": 200,
|
||||
"api": [
|
||||
{
|
||||
"path": "/api/servers",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"path": "/api/ospf/catalog",
|
||||
"status": 200
|
||||
}
|
||||
],
|
||||
"pageErrors": [],
|
||||
"noOverflow": true,
|
||||
"noConflictAfterCleanup": true
|
||||
},
|
||||
{
|
||||
"width": 320,
|
||||
"status": 200,
|
||||
"api": [
|
||||
{
|
||||
"path": "/api/servers",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"path": "/api/ospf/catalog",
|
||||
"status": 200
|
||||
}
|
||||
],
|
||||
"pageErrors": [],
|
||||
"noOverflow": true,
|
||||
"noConflictAfterCleanup": true
|
||||
}
|
||||
],
|
||||
"bounds": [
|
||||
"Read-only deployed production frontend153/backend152 catalog after native own cleanup; warning correctly absent",
|
||||
"Positive Full/BFD Down source-preview3133 UI uses real deployed backend8000 and is recorded separately",
|
||||
"Native OSPFv2/BFD IPv4 inner over IPv4 GRE; no IPv6, physical WAN redundancy, continuous packet capture, SLA or throughput claim"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"date": "2026-10-11",
|
||||
"block": "12.5.153",
|
||||
"cases": [
|
||||
{
|
||||
"width": 1440,
|
||||
"errors": [],
|
||||
"api": [
|
||||
{
|
||||
"status": 200
|
||||
}
|
||||
],
|
||||
"nativeFullAndDownShown": true,
|
||||
"sourcePreview": true,
|
||||
"serverContextPreserved": true,
|
||||
"queryCleared": true
|
||||
},
|
||||
{
|
||||
"width": 320,
|
||||
"errors": [],
|
||||
"api": [
|
||||
{
|
||||
"status": 200
|
||||
}
|
||||
],
|
||||
"nativeFullAndDownShown": true,
|
||||
"sourcePreview": true,
|
||||
"serverContextPreserved": true,
|
||||
"queryCleared": true
|
||||
}
|
||||
],
|
||||
"bounds": [
|
||||
"Source Next dev3133 proxies real deployed backend8000; no mocked response and no browser mutation",
|
||||
"Production frontend build/deployment is checked separately after own native cleanup"
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Binary file not shown.
|
After Width: | Height: | Size: 149 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
+15
-1
@@ -1,12 +1,26 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { test } from "node:test"
|
||||
import { normalizeOspfState, normalizeBfdState, ospfNodeState } from "./ospf-state"
|
||||
import { normalizeOspfState, normalizeBfdState, ospfNodeState, ospfBfdConflicts } from "./ospf-state"
|
||||
test("RouterOS states keep transitional adjacency separate from failure", () => {
|
||||
assert.deepEqual(["full", "2-way", "ExStart", "exchange", "loading", "attempt", "init", "down"].map(normalizeOspfState), ["Full", "2-Way", "ExStart", "Exchange", "Loading", "Attempt", "Init", "Down"])
|
||||
assert.equal(normalizeOspfState("future-state"), "Unknown")
|
||||
assert.equal(normalizeBfdState(""), "Unknown")
|
||||
assert.equal(normalizeBfdState(" UP "), "Up")
|
||||
})
|
||||
|
||||
test("Full/BFD conflict requires fresh exact device, interface, peer, explicit active BFD and unique direct session", () => {
|
||||
const neighbor = { localRouter: "1", localIface: "gre-own", neighborAddress: "198.18.153.2", state: "Full" as const }
|
||||
const iface = { serverId: "1", interfaceName: "gre-own", active: true, useBfd: true }
|
||||
const session = { serverId: "1", iface: "gre-own", remoteAddr: "198.18.153.2", state: "Down" as const, multihop: false }
|
||||
assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [session]), [neighbor])
|
||||
assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [{ ...session, state: "AdminDown" }]), [neighbor])
|
||||
for (const s of [{ ...session, serverId: "2" }, { ...session, iface: "ether1" }, { ...session, remoteAddr: "198.18.153.3" }, { ...session, multihop: true }, { ...session, multihop: null }, { ...session, state: "Unknown" as const }, { ...session, state: "Up" as const }, { ...session, dataUnknown: true }]) assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [s]), [])
|
||||
assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [session, { ...session, state: "Up" }]), [])
|
||||
for (const i of [{ ...iface, useBfd: null }, { ...iface, useBfd: false }, { ...iface, active: false }, { ...iface, active: null }, { ...iface, dataUnknown: true }]) assert.deepEqual(ospfBfdConflicts([neighbor], [i], [session]), [])
|
||||
assert.deepEqual(ospfBfdConflicts([{ ...neighbor, dataUnknown: true }], [iface], [session]), [])
|
||||
assert.deepEqual(ospfBfdConflicts([{ ...neighbor, state: "Down" }], [iface], [session]), [])
|
||||
assert.deepEqual(ospfBfdConflicts([{ ...neighbor, neighborAddress: undefined }], [iface], [session]), [])
|
||||
})
|
||||
test("topology does not infer Down from missing or transitional evidence", () => {
|
||||
assert.equal(ospfNodeState([]), "none")
|
||||
assert.equal(ospfNodeState(["Down"]), "Down")
|
||||
|
||||
@@ -12,3 +12,18 @@ export function ospfNodeState(states: OspfNeighborState[]): "Full" | "2-Way" | "
|
||||
if (states.some(state => state !== "Down")) return "Pending"
|
||||
return "Down"
|
||||
}
|
||||
|
||||
/** Correlate only a single observed direct BFD session on an explicitly configured interface. */
|
||||
export function ospfBfdConflicts<T extends { localRouter: string; localIface: string; neighborAddress?: string; state: OspfNeighborState; dataUnknown?: boolean }>(
|
||||
neighbors: T[],
|
||||
interfaces: Array<{ serverId: string; interfaceName: string; useBfd?: boolean | null; active?: boolean | null; dataUnknown?: boolean }>,
|
||||
sessions: Array<{ serverId: string; iface: string; remoteAddr: string; state: BfdState; multihop?: boolean | null; dataUnknown?: boolean }>,
|
||||
): T[] {
|
||||
const ip = (value: string) => value.split("%")[0]?.toLowerCase() ?? ""
|
||||
return neighbors.filter(n => {
|
||||
if (n.dataUnknown || n.state !== "Full" || !n.neighborAddress || !n.localIface) return false
|
||||
if (!interfaces.some(i => !i.dataUnknown && i.active === true && i.useBfd === true && i.serverId === n.localRouter && i.interfaceName === n.localIface)) return false
|
||||
const matching = sessions.filter(s => !s.dataUnknown && s.multihop === false && s.serverId === n.localRouter && s.iface === n.localIface && ip(s.remoteAddr) === ip(n.neighborAddress!))
|
||||
return matching.length === 1 && (matching[0]!.state === "Down" || matching[0]!.state === "AdminDown")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { test, expect } from "@playwright/test"
|
||||
for (const width of [1440, 320]) {
|
||||
test(`OSPF Full/BFD Down: предупреждение, scope и recovery, ширина ${width}`, async ({ page }) => {
|
||||
await page.setViewportSize({ width, height: 1000 })
|
||||
let phase = "down"
|
||||
const base = { serverId: 1, serverName: "CHR 1", serverSite: "", serverCountry: "RU" }
|
||||
const neighbor = { ...base, id: "*n", address: "198.18.153.2", routerId: "198.18.253.2", instance: "own", area: "own", areaId: "0.0.0.0", interface: "gre-own", state: "Full", uptime: "1m", stateChanges: 1, priority: 1 }
|
||||
const iface = { ...base, id: "*i", instance: "own", area: "own", areaId: "0.0.0.0", interface: "gre-own", cost: 10, type: "ptp", disabled: false, inactive: false, priority: 1, helloInterval: 1, deadInterval: 20, useBfd: true }
|
||||
const bfd = { ...base, id: "*b", localAddr: "198.18.153.1", remoteAddr: "198.18.153.2", interface: "gre-own", state: "Down", uptime: "1s", multihop: false, multiplier: 3, txInterval: 200, rxInterval: 200, holdTime: null, packetsRx: 10, packetsTx: 20, stateChanges: 1 }
|
||||
const errors: string[] = []
|
||||
page.on("pageerror", e => errors.push(e.message))
|
||||
await page.route("**/health", route => route.fulfill({ json: { ok: true } }))
|
||||
await page.route("**/api/**", route => {
|
||||
const path = new URL(route.request().url()).pathname
|
||||
if (path === "/api/servers") return route.fulfill({ json: [1, 2].map(id => ({ id, name: "CHR " + id, host: "192.0.2." + id, country: "RU", enabled: true, status: "online" })) })
|
||||
if (path === "/api/ospf/catalog") return route.fulfill({ json: { neighbors: [neighbor], interfaces: [{ ...iface, useBfd: phase === "not-used" ? false : true }], instances: [], bfdSessions: [{ ...bfd, serverId: phase === "foreign" ? 2 : 1, state: phase === "up" ? "Up" : phase === "unknown" ? "Unknown" : "Down" }], routes: [], failures: [] } })
|
||||
return route.fulfill({ json: path === "/api/auth/config" ? { required: false } : {} })
|
||||
})
|
||||
await page.goto("/ospf?server=1&tab=neighbors&q=253")
|
||||
const alert = page.getByRole("alert").filter({ hasText: "OSPF Full при недоступном BFD" })
|
||||
await expect(alert).toBeVisible()
|
||||
await expect(alert).toContainText("CHR 1 · gre-own")
|
||||
await expect(page.locator("tr[data-row-id]").first()).toContainText("Full")
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
|
||||
await alert.getByRole("button", { name: "Проверить BFD" }).click()
|
||||
await expect.poll(() => new URL(page.url()).searchParams.get("tab")).toBe("bfd")
|
||||
expect(new URL(page.url()).searchParams.get("server")).toBe("1")
|
||||
expect(new URL(page.url()).searchParams.has("q")).toBe(false)
|
||||
await expect(page.locator("tr[data-row-id]").first()).toContainText("Down")
|
||||
for (const next of ["up", "foreign", "not-used", "unknown"]) {
|
||||
phase = next
|
||||
await page.getByRole("button", { name: "Обновить", exact: true }).click()
|
||||
await expect(alert).toHaveCount(0)
|
||||
}
|
||||
expect(errors).toEqual([])
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user