import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import { AdminApiClient } from "./api/client";
import type {
  AuditEvent,
  AuditSummary,
  AuthResult,
  Cluster,
  ClusterAdminSummary,
  ClusterAuthorityState,
  ClusterNode,
  ClusterNodeGroup,
  CreatedJoinToken,
  FabricServiceChannelAccessTelemetry,
  FabricServiceChannelBreadcrumbWindowPolicy,
  FabricServiceChannelRecoveryPolicy,
  FabricServiceChannelLeaseMaintenance,
  FabricServiceChannelReadiness,
  FabricServiceChannelRouteFeedbackObservation,
  FabricServiceChannelRouteRebuildAlertSilence,
  FabricServiceChannelRouteRebuildAttempt,
  FabricServiceChannelRouteRebuildFeedbackHealthBreakdown,
  FabricServiceChannelRouteRebuildHealthSummary,
  FabricServiceChannelRouteRebuildIncident,
  FabricServiceChannelRebuildSnapshotMaintenanceHealth,
  FabricServiceChannelRebuildSnapshotWarmup,
  FabricServiceChannelSchemaStatus,
  FabricTestingFlag,
  InstallationStatus,
  JoinRequest,
  InstallJoinBundle,
  MeshLink,
  MeshRouteIntent,
  NodeHeartbeat,
  NodeBridgeReplayPlan,
  NodeJoinToken,
  NodeSyntheticMeshConfig,
  NodeTelemetryObservation,
  NodeUpdatePlan,
  NodeUpdateStatus,
  NodeWorkloadDesiredState,
  Organization,
  OrganizationAdminSummary,
  OrganizationMembership,
  QoSPolicy,
  ReleaseVersion,
  Resource,
  RoleAssignment,
  StaleNodeRiskReport,
  UserAccount,
  VPNClientDiagnosticCommand,
  VPNClientDiagnosticStatus,
  VPNConnection,
  VPNConnectionLease,
  VPNPacketStats,
  WorkloadStatus,
} from "./types";

const storageKeys = {
  actorUserId: "rap.webAdmin.actorUserId",
  auth: "rap.webAdmin.auth",
  language: "rap.webAdmin.language",
  vpnDiagnosticDeviceId: "rap.webAdmin.vpnDiagnosticDeviceId",
};

type FabricRebuildLedgerFilters = {
  reporterNodeId: string;
  routeId: string;
  serviceClass: string;
  generation: string;
  feedbackSource: string;
  feedbackChannelId: string;
  feedbackViolationStatus: string;
  offset: number;
};

const defaultFabricRebuildLedgerFilters: FabricRebuildLedgerFilters = {
  reporterNodeId: "",
  routeId: "",
  serviceClass: "",
  generation: "",
  feedbackSource: "",
  feedbackChannelId: "",
  feedbackViolationStatus: "",
  offset: 0,
};

const fabricNodeRoleOptions = [
  "core-mesh",
  "entry-node",
  "relay-node",
  "update-cache",
];

const serviceWorkloadOptions = [
  "public-ingress",
  "admin-ingress",
  "core-mesh",
  "rdp-worker",
  "vnc-worker",
  "vpn-exit",
  "vpn-connector",
  "vpn-client",
  "ipv4-egress",
  "file-storage-cache",
  "update-cache",
  "video-relay",
];

const roleOptions = fabricNodeRoleOptions;

const roleDisplayNames: Record<string, string> = {
  "public-ingress": "Public HTTPS ingress",
  "admin-ingress": "Admin HTTPS ingress",
  "entry-node": "Fabric entry",
  "relay-node": "Fabric relay",
  "core-mesh": "Fabric core",
  "rdp-worker": "RDP worker",
  "vnc-worker": "VNC worker",
  "vpn-exit": "VPN exit",
  "vpn-connector": "VPN connector",
  "vpn-client": "VPN client node",
  "ipv4-egress": "IPv4 egress",
  "file-storage-cache": "Config store",
  "update-cache": "Update store",
  "video-relay": "Video relay",
};

const capabilityKeysByRole: Record<string, string[]> = {
  "public-ingress": ["can_accept_client_ingress", "fabric_service_channel_runtime"],
  "admin-ingress": ["can_accept_client_ingress", "fabric_service_channel_runtime"],
  "entry-node": ["can_accept_client_ingress"],
  "relay-node": ["mesh_rendezvous_relay_quic_contract", "mesh_peer_connection_manager"],
  "core-mesh": ["native_node_agent", "mesh_peer_connection_manager", "mesh_listener_diagnostics"],
  "rdp-worker": ["can_run_rdp_worker"],
  "vnc-worker": ["can_run_vnc_worker"],
  "vpn-exit": ["can_run_vpn_exit"],
  "vpn-connector": ["can_run_vpn_connector"],
  "vpn-client": ["can_run_vpn_client", "fabric_service_channel_required"],
  "ipv4-egress": ["can_egress_internet", "fabric_service_channel_required"],
  "file-storage-cache": ["can_run_file_cache"],
  "update-cache": ["can_run_update_cache"],
  "video-relay": ["can_run_video_relay"],
};

const views = [
  { id: "command", ru: "Обзор", en: "Command" },
  { id: "clusters", ru: "Кластеры", en: "Clusters" },
  { id: "cluster-settings", ru: "Настройки кластера", en: "Cluster Settings" },
  { id: "nodes", ru: "Узлы", en: "Nodes" },
  { id: "enrollment", ru: "Новый узел", en: "New Node" },
  { id: "functions", ru: "Функции", en: "Functions" },
  { id: "workloads", ru: "Сервисы", en: "Workloads" },
  { id: "fabric", ru: "Связи Fabric", en: "Fabric Links" },
  { id: "vpn", ru: "VPN Control", en: "VPN Control" },
  { id: "servers", ru: "Серверы", en: "Servers" },
  { id: "org-safe", ru: "Организации", en: "Organizations" },
  { id: "audit", ru: "Аудит", en: "Audit" },
] as const;

type ViewId = (typeof views)[number]["id"];
type Language = "ru" | "en";
type ConsoleMode = "admin" | "user";

const navGroups: Array<{ label: Record<Language, string>; views: ViewId[] }> = [
  { label: { ru: "Ферма", en: "Farm" }, views: ["command", "clusters", "cluster-settings", "nodes", "enrollment", "functions", "fabric"] },
  { label: { ru: "Сервисы", en: "Services" }, views: ["workloads", "vpn", "servers"] },
  { label: { ru: "Доступ", en: "Access" }, views: ["org-safe", "audit"] },
];

const viewsById = Object.fromEntries(views.map((view) => [view.id, view])) as Record<ViewId, (typeof views)[number]>;

type NodeInventoryEntry = {
  node: ClusterNode;
  memberships: Array<{ cluster: Cluster; node: ClusterNode }>;
};
type NodeInventoryTreeRow =
  | { kind: "group"; key: string; label: string; depth: number; count: number; groupId?: string }
  | { kind: "node"; key: string; entry: NodeInventoryEntry; depth: number };

type WebAdminSession = {
  userId: string;
  email: string;
  authSessionId: string;
  accessToken: string;
  refreshToken: string;
  accessTokenExpiresAt: string;
  refreshTokenExpiresAt: string;
};

function normalizeStoredSession(input: unknown): WebAdminSession | null {
  if (!input || typeof input !== "object") {
    return null;
  }
  const session = input as WebAdminSession;
  if (
    typeof session.userId !== "string" ||
    typeof session.email !== "string" ||
    typeof session.authSessionId !== "string" ||
    typeof session.accessToken !== "string" ||
    typeof session.refreshToken !== "string" ||
    typeof session.accessTokenExpiresAt !== "string" ||
    typeof session.refreshTokenExpiresAt !== "string"
  ) {
    return null;
  }
  if (!session.userId || !session.refreshToken) {
    return null;
  }
  return {
    userId: session.userId,
    email: session.email,
    authSessionId: session.authSessionId,
    accessToken: session.accessToken,
    refreshToken: session.refreshToken,
    accessTokenExpiresAt: session.accessTokenExpiresAt,
    refreshTokenExpiresAt: session.refreshTokenExpiresAt,
  };
}

function isTokenExpired(expiresAt: string): boolean {
  const expiresAtMs = Date.parse(expiresAt);
  return !Number.isFinite(expiresAtMs) || expiresAtMs <= Date.now();
}

function loadStoredSession(): WebAdminSession | null {
  try {
    const stored = localStorage.getItem(storageKeys.auth);
    if (!stored) {
      return null;
    }
    const parsed = normalizeStoredSession(JSON.parse(stored));
    if (!parsed || isTokenExpired(parsed.refreshTokenExpiresAt)) {
      return null;
    }
    return parsed;
  } catch {
    return null;
  }
}

type JoinTokenFormState = {
  ttlHours: number;
  maxUses: number;
  roles: string[];
  nodeName: string;
  nodeGroupId: string;
  ownershipType: string;
  purpose: string;
  installMode: string;
  dockerImage: string;
  dockerContainerName: string;
  dockerNetwork: string;
  windowsStartupMode: string;
  windowsInstallDir: string;
  windowsNodeAgentSHA256: string;
  linuxInstallDir: string;
  linuxNodeAgentSHA256: string;
  fabricListenAddr: string;
  fabricListenPortMode: string;
  fabricListenAutoPortStart: number;
  fabricListenAutoPortEnd: number;
  meshAdvertiseEndpoint: string;
  meshAdvertiseEndpoints: string;
  meshAdvertiseTransport: string;
  meshConnectivityMode: string;
  meshNATType: string;
  meshRegion: string;
  artifactEndpoints: string;
  dockerImageArtifactSHA256: string;
  pullImage: boolean;
  replace: boolean;
  syntheticRuntime: boolean;
};

const defaultJoinTokenForm: JoinTokenFormState = {
  ttlHours: 24,
  maxUses: 1,
  roles: ["core-mesh"],
  nodeName: "",
  nodeGroupId: "",
  ownershipType: "platform_managed",
  purpose: "",
  installMode: "docker",
  dockerImage: "rap-node-agent:0.2.353-sticky-fabric-control",
  dockerContainerName: "",
  dockerNetwork: "host",
  windowsStartupMode: "auto",
  windowsInstallDir: "",
  windowsNodeAgentSHA256: "",
  linuxInstallDir: "",
  linuxNodeAgentSHA256: "",
  fabricListenAddr: "",
  fabricListenPortMode: "auto",
  fabricListenAutoPortStart: 19131,
  fabricListenAutoPortEnd: 19231,
  meshAdvertiseEndpoint: "",
  meshAdvertiseEndpoints: "",
  meshAdvertiseTransport: "direct_quic",
  meshConnectivityMode: "private_lan",
  meshNATType: "none",
  meshRegion: "docker-test",
  artifactEndpoints: "",
  dockerImageArtifactSHA256: "",
  pullImage: false,
  replace: true,
  syntheticRuntime: false,
};

const copy = {
  ru: {
    productOwner: "Владелец продукта",
    controlPlane: "Панель управления",
    sideText: "Главная панель владельца платформы для кластеров, узлов, доверия, ролей и безопасного desired state.",
    signInTitle: "Вход",
    signInText: "Введите учетные данные.",
    bootstrapTitle: "Первый владелец",
    bootstrapText: "Пустая установка принимает только подписанную активацию продукта.",
    activationPayload: "Activation manifest JSON",
    activationSignature: "Подпись manifest",
    createOwner: "Создать владельца",
    creatingOwner: "Создание...",
    ownerCreated: "Владелец создан. Теперь можно войти.",
    installationLocked: "Установка уже активирована",
    insecureBootstrapDisabled: "Insecure bootstrap выключен. Нужна strict-активация с ключом продукта.",
    email: "Логин",
    password: "Пароль",
    language: "Язык",
    deviceLabel: "Устройство",
    rememberMe: "Запомнить меня",
    trustDevice: "Доверять этому устройству",
    signIn: "Войти",
    signingIn: "Вход...",
    logout: "Выйти",
    profile: "Профиль",
    refresh: "Обновить",
    refreshing: "Обновление...",
    autoRefresh: "Автообновление",
    lastRefresh: "Данные обновлены",
    activeCluster: "Активный кластер",
    slugLabel: "Технический код",
    slugHelp:
      "Slug — постоянный короткий технический идентификатор кластера для URL, скриптов, логов и интеграций. Его лучше не менять после создания.",
    clusterCatalog: "Каталог кластеров",
    clusterCatalogText: "Список реальных кластеров из Control/API слоя. Выберите активный кластер или раскройте карточку для подробностей.",
    makeActive: "Сделать активным",
    openSettings: "Открыть настройки",
    selected: "Выбран",
    createCluster: "Создать кластер",
    clusterDetails: "Подробнее",
    consoleTitle: "Панель владельца платформы",
    boundary:
      "Панель является сервисным интерфейсом управления. Внутри фермы transport остается QUIC/UDP-only.",
    noLoginError: "Войдите как владелец продукта или администратор платформы, чтобы загрузить панель.",
    accessDenied: "Доступ к этой панели запрещен.",
    sessionMode: "Режим сессии",
    sessionModeAdmin: "Админ",
    sessionModeUser: "Пользователь",
    sessionRefreshedAt: "Сессия обновлена",
    emptyLiveTitle: "Кластер пока пустой",
    emptyLiveText:
      "Это реальные данные, не заглушка: в выбранном кластере ещё нет одобренных node-agent узлов. Создайте join token, запустите rap-node-agent и подтвердите join request.",
    realDataNote:
      "Показываются только данные из PostgreSQL и Control/API слоя. Если значения нулевые, значит соответствующих узлов, ролей или сервисов пока нет.",
    signedInAs: "Вход выполнен",
    actorUser: "Actor user",
    testMode: "Тестирование",
    testModeText: "Включает тестовую телеметрию и синтетические наблюдения связей. Это не production mesh runtime.",
    platformTestFlag: "Тестирование сервера",
    nodeTelemetry: "Телеметрия узла",
    heartbeatHistory: "История heartbeat",
    noTelemetry: "Телеметрии пока нет",
    enableTelemetry: "Включить телеметрию",
    enableSyntheticLinks: "Включить тестовые связи",
    saveTestFlag: "Сохранить флаг",
    nodeManagement: "Управление узлом",
    nodeScope: "Область просмотра",
    currentClusterNodes: "Узлы активного кластера",
    allNodes: "Все узлы платформы",
    showAllPlatformNodes: "Показать все узлы платформы",
    currentClusterMembership: "Участие в активном кластере",
    clusterMemberships: "Участие по кластерам",
    notMemberOfActiveCluster: "не состоит",
    nodeIdentity: "Физическая идентичность узла",
    activeClusterScope: "Область активного кластера",
    activeClusterScopeText:
      "Один физический узел может состоять в нескольких кластерах. Функции фермы и desired-сервисы ниже относятся только к выбранному активному кластеру.",
    capabilityConfirmed: "способность подтверждена heartbeat",
    capabilityMissing: "способность не заявлена узлом",
    capabilityUnknown: "способность не подтверждена: нет heartbeat",
    nodeGlobalInventoryText:
      "Один физический узел показан один раз. Участие и функции фермы остаются кластерными: в разных кластерах этот же узел может иметь разные назначения.",
    nodeSearch: "Поиск узлов",
    groupNodesBy: "Группировать",
    groupByMembership: "по участию",
    groupByHealth: "по здоровью",
    groupByOwnership: "по владению",
    groupByClusterCount: "по числу кластеров",
    nodeGroups: "Группы узлов",
    nodeGroupTree: "Дерево групп",
    nodeGroupFilter: "Фильтр по группе",
    allNodeGroups: "Все группы",
    nodeGroupCreatePanel: "Создание группы",
    nodeGroupName: "Название группы",
    parentNodeGroup: "Родительская группа",
    rootNodeGroup: "Корень",
    ungroupedNodes: "Без группы",
    createNodeGroup: "Создать группу",
    createSubgroup: "Создать подгруппу",
    collapseGroup: "Свернуть",
    expandGroup: "Развернуть",
    assignNodeGroup: "Переместить в группу",
    removeFromNodeGroup: "Убрать из группы",
    connectExistingNode: "Подключить к активному кластеру",
    connectExistingNodeTitle: "Подключить существующий узел",
    connectExistingNodeText:
      "Будет создано или повторно включено участие конкретного физического узла в активном кластере. Функции ниже назначаются только в этом кластере.",
    connectWithRoles: "Подключить с функциями",
    nodeDetails: "Сведения",
    manageNode: "Настроить",
    nodeFunctions: "Функции узла",
    nodeFunctionsText:
      "Только функции инфраструктуры фермы: fabric core, вход, relay, обновления и config store. Сервисные workloads на этом уровне не назначаются.",
    rolePermission: "Разрешение",
    permissionGranted: "разрешено",
    permissionDenied: "нет разрешения",
    organizationScopeForEnable: "Область назначения",
    clusterWideRolePlaceholder: "функции узла всегда назначаются на весь кластер",
    desiredRuntime: "Желаемое состояние",
    observedRuntime: "Фактически",
    enableFunction: "Включить функцию",
    disableFunction: "Выключить функцию",
    close: "Закрыть",
    nodeBriefList: "Краткий список узлов",
    noActiveClusterMembership: "Узел не входит в активный кластер",
    nodeBriefListHelp:
      "Список сгруппирован деревом активного кластера. Полные сведения, управление, функции фермы, сервисы и статистика открываются из строки узла.",
    nodeSearchPlaceholder: "имя, ключ, кластер, статус",
    nodeGroupInventoryText:
      "Группы — это кластерная инвентарная структура. Перенос узла в группу меняет только его размещение внутри активного кластера, не функции и не членство.",
    nodeGroupCreated: "Группа узлов создана.",
    noNodesTitle: "Нет узлов",
    noNodesByFilter: "По текущему фильтру узлы не найдены.",
    cancel: "Отмена",
    alreadyMember: "Уже в активном кластере",
    revokedMembership: "Участие отозвано",
    addNode: "Подключить узел",
    addNodeText:
      "Подключение существующего физического узла к активному кластеру выполняется из списка узлов: включите общий режим и нажмите «Подключить к активному кластеру».",
    joinTokenTitle: "Создать новый узел",
    joinTokenText:
      "Панель выпускает одноразовый install token и signed join bundle. Дальше оператор запускает bundle-first install, узел входит в ферму через QUIC fabric и отправляет заявку на approval.",
    ttlHours: "Срок действия, часов",
    ttlHelp: "Через это время token станет недействительным, даже если им никто не воспользовался. Для ручного подключения обычно достаточно 1–24 часов.",
    maxUses: "Максимум использований",
    maxUsesHelp: "Сколько node-agent смогут использовать этот token. Самый безопасный вариант — 1 token на 1 новый узел.",
    tokenPurpose: "Назначение token",
    nodeOwnership: "Тип владения узлом",
    suggestedRoles: "Функции узла фермы",
    generatedScope: "Сгенерированная область действия",
    generatedScopeHelp:
      "JSON формируется автоматически из настроек выше. Оператор не должен писать его руками, чтобы не ошибиться синтаксисом или областью доступа.",
    manualApprovalRequired: "Подтверждение заявки вручную обязательно",
    nodeRoles: "Функции фермы",
    desiredServices: "Желаемые сервисы",
    observedServices: "Наблюдаемые сервисы",
    noRoles: "Функций пока нет",
    noServices: "Сервисов пока нет",
    manageInCluster: "Управлять в кластере",
    rolesAndServices: "Функции и сервисы",
    links: "Связи",
    fabricMap: "Карта трафика Fabric",
    fabricNodeLayer: "Узлы кластера",
    observedPeerLinks: "Наблюдаемые связи",
    placementIntent: "управляющее назначение",
    endpointName: "Название",
    publicEndpoint: "Публичный адрес",
    endpointType: "Тип входа",
    description: "Описание",
    routeScope: "Область маршрутов JSON",
    endpointNodes: "Назначенные узлы",
    assignEndpointNode: "Назначить узел",
    selectNode: "Выберите узел",
    assignedNodesEmpty: "Узлы пока не назначены",
    addressNotSet: "адрес не задан",
    descriptionNotSet: "описание не задано",
    servicePlacement: "Размещение сервисов",
    trafficFlow: "Потоки между узлами",
    organizationTestFlag: "Тестирование организации",
    organizationId: "ID организации",
    saveOrganizationFlag: "Сохранить флаг организации",
    noLinks: "Связей пока нет",
    recentHeartbeats: "Последние heartbeat",
    memory: "Память",
    cpu: "Процессор",
    processes: "Процессы",
  },
  en: {
    productOwner: "Product Owner",
    controlPlane: "Fabric control",
    sideText: "Full platform-owner panel for clusters, nodes, trust, placement, and safe service desired state.",
    signInTitle: "Sign in",
    signInText: "Enter your credentials.",
    bootstrapTitle: "First owner",
    bootstrapText: "An empty installation accepts only a signed product activation.",
    activationPayload: "Activation manifest JSON",
    activationSignature: "Manifest signature",
    createOwner: "Create owner",
    creatingOwner: "Creating...",
    ownerCreated: "Owner created. You can sign in now.",
    installationLocked: "Installation is already active",
    insecureBootstrapDisabled: "Insecure bootstrap is disabled. Strict product-key activation is required.",
    email: "Login",
    password: "Password",
    language: "Language",
    deviceLabel: "Device",
    rememberMe: "Remember me",
    trustDevice: "Trust this device",
    signIn: "Sign in",
    signingIn: "Signing in...",
    logout: "Logout",
    profile: "Profile",
    refresh: "Refresh",
    refreshing: "Refreshing...",
    autoRefresh: "Auto refresh",
    lastRefresh: "Data refreshed",
    activeCluster: "Active cluster",
    slugLabel: "Technical code",
    slugHelp:
      "Slug is a stable short technical identifier for URLs, scripts, logs, and integrations. It should generally not change after creation.",
    clusterCatalog: "Cluster catalog",
    clusterCatalogText: "Real clusters from the Control/API layer. Select the active cluster or expand a card for details.",
    makeActive: "Make active",
    openSettings: "Open settings",
    selected: "Selected",
    createCluster: "Create cluster",
    clusterDetails: "Details",
    consoleTitle: "Platform Owner Console",
    boundary: "The panel is a service management interface. Internal farm transport remains QUIC/UDP-only.",
    noLoginError: "Sign in as a product owner or platform administrator to load the panel.",
    accessDenied: "Access to this panel is denied.",
    sessionMode: "Session mode",
    sessionModeAdmin: "Admin",
    sessionModeUser: "User",
    sessionRefreshedAt: "Session refreshed",
    emptyLiveTitle: "Cluster has no live nodes yet",
    emptyLiveText:
      "These are real values, not placeholders: the selected cluster has no approved node-agent nodes yet. Create a join token, run rap-node-agent, and approve the join request.",
    realDataNote: "Only PostgreSQL and Control/API data is shown. Zero values mean the corresponding nodes, functions, or services do not exist yet.",
    signedInAs: "Signed in",
    actorUser: "Actor user",
    testMode: "Testing",
    testModeText: "Enables test telemetry and synthetic link observations. This is not production mesh runtime.",
    platformTestFlag: "Server testing",
    nodeTelemetry: "Node telemetry",
    heartbeatHistory: "Heartbeat history",
    noTelemetry: "No telemetry yet",
    enableTelemetry: "Enable telemetry",
    enableSyntheticLinks: "Enable test links",
    saveTestFlag: "Save flag",
    nodeManagement: "Node management",
    nodeScope: "View scope",
    currentClusterNodes: "Active cluster nodes",
    allNodes: "All platform nodes",
    showAllPlatformNodes: "Show all platform nodes",
    currentClusterMembership: "Active cluster membership",
    clusterMemberships: "Cluster memberships",
    notMemberOfActiveCluster: "not a member",
    nodeIdentity: "Physical node identity",
    activeClusterScope: "Active cluster scope",
    activeClusterScopeText:
      "One physical node may belong to multiple clusters. Farm functions and desired services below belong only to the selected active cluster.",
    capabilityConfirmed: "capability confirmed by heartbeat",
    capabilityMissing: "capability not reported by node",
    capabilityUnknown: "capability unconfirmed: no heartbeat",
    nodeGlobalInventoryText:
      "Each physical node is shown once. Membership and farm functions remain cluster-scoped, so the same node may have different assignments in different clusters.",
    nodeSearch: "Node search",
    groupNodesBy: "Group by",
    groupByMembership: "membership",
    groupByHealth: "health",
    groupByOwnership: "ownership",
    groupByClusterCount: "cluster count",
    nodeGroups: "Node groups",
    nodeGroupTree: "Group tree",
    nodeGroupFilter: "Group filter",
    allNodeGroups: "All groups",
    nodeGroupCreatePanel: "Create group",
    nodeGroupName: "Group name",
    parentNodeGroup: "Parent group",
    rootNodeGroup: "Root",
    ungroupedNodes: "Ungrouped",
    createNodeGroup: "Create group",
    createSubgroup: "Create subgroup",
    collapseGroup: "Collapse",
    expandGroup: "Expand",
    assignNodeGroup: "Move to group",
    removeFromNodeGroup: "Remove from group",
    connectExistingNode: "Connect to active cluster",
    connectExistingNodeTitle: "Connect existing node",
    connectExistingNodeText:
      "This creates or re-enables membership for one concrete physical node in the active cluster. The functions below are assigned only in this cluster.",
    connectWithRoles: "Connect with functions",
    nodeDetails: "Details",
    manageNode: "Configure",
    nodeFunctions: "Node functions",
    nodeFunctionsText:
      "Farm infrastructure only: fabric core, entry, relay, update store, and config store. Service workloads are not assigned at node level.",
    rolePermission: "Permission",
    permissionGranted: "granted",
    permissionDenied: "not allowed",
    organizationScopeForEnable: "Assignment scope",
    clusterWideRolePlaceholder: "node functions are always cluster-wide",
    desiredRuntime: "Desired state",
    observedRuntime: "Observed",
    enableFunction: "Enable function",
    disableFunction: "Disable function",
    close: "Close",
    nodeBriefList: "Compact node list",
    noActiveClusterMembership: "Node is not a member of the active cluster",
    nodeBriefListHelp:
      "The list is grouped as the active cluster tree. Full details, management, farm functions, services, and statistics open from the node row.",
    nodeSearchPlaceholder: "name, key, cluster, status",
    nodeGroupInventoryText:
      "Groups are a cluster inventory structure. Moving a node to a group changes only its placement inside the active cluster, not functions or membership.",
    nodeGroupCreated: "Node group created.",
    noNodesTitle: "No nodes",
    noNodesByFilter: "No nodes match the current filter.",
    cancel: "Cancel",
    alreadyMember: "Already in active cluster",
    revokedMembership: "Membership revoked",
    addNode: "Add node",
    addNodeText:
      "Connect an existing physical node to the active cluster from the node list: enable platform-wide view and click “Connect to active cluster”.",
    joinTokenTitle: "Create new node",
    joinTokenText:
      "The panel issues a one-time install token and a signed join bundle. Then the operator runs the bundle-first install, the node joins through QUIC fabric, and the platform owner approves the request.",
    ttlHours: "Lifetime, hours",
    ttlHelp: "After this time the token becomes invalid even if unused. For manual enrollment, 1–24 hours is usually enough.",
    maxUses: "Maximum uses",
    maxUsesHelp: "How many node-agents may use this token. The safest default is one token for one new node.",
    tokenPurpose: "Token purpose",
    nodeOwnership: "Node ownership type",
    suggestedRoles: "Farm node functions",
    generatedScope: "Generated scope",
    generatedScopeHelp:
      "JSON is generated automatically from the settings above. Operators should not hand-write it and risk syntax or access-scope mistakes.",
    manualApprovalRequired: "Manual request approval is required",
    nodeRoles: "Farm functions",
    desiredServices: "Desired services",
    observedServices: "Observed services",
    noRoles: "No functions yet",
    noServices: "No services yet",
    manageInCluster: "Manage in cluster",
    rolesAndServices: "Functions and services",
    links: "Links",
    fabricMap: "Fabric traffic map",
    fabricNodeLayer: "Cluster nodes",
    observedPeerLinks: "Observed links",
    placementIntent: "control/API placement",
    endpointName: "Name",
    publicEndpoint: "Public endpoint",
    endpointType: "Entry type",
    description: "Description",
    routeScope: "Route scope JSON",
    endpointNodes: "Assigned nodes",
    assignEndpointNode: "Assign node",
    selectNode: "Select node",
    assignedNodesEmpty: "No nodes assigned yet",
    addressNotSet: "address not set",
    descriptionNotSet: "description not set",
    servicePlacement: "Service placement",
    trafficFlow: "Node traffic flows",
    organizationTestFlag: "Organization testing",
    organizationId: "Organization ID",
    saveOrganizationFlag: "Save organization flag",
    noLinks: "No links yet",
    recentHeartbeats: "Recent heartbeats",
    memory: "Memory",
    cpu: "CPU",
    processes: "Processes",
  },
} satisfies Record<Language, Record<string, string>>;

function normalizeAuthResult(result: AuthResult): WebAdminSession {
  const userId = result.user.id || result.user.ID || "";
  const email = result.user.email || result.user.Email || "";
  const authSessionId = result.auth_session.id || result.auth_session.ID || "";
  return {
    userId,
    email,
    authSessionId,
    accessToken: result.tokens.access_token,
    refreshToken: result.tokens.refresh_token,
    accessTokenExpiresAt: result.tokens.access_token_expires_at,
    refreshTokenExpiresAt: result.tokens.refresh_token_expires_at,
  };
}

async function resolveConsoleMode(clientByUser: AdminApiClient): Promise<ConsoleMode | null> {
  try {
    await clientByUser.listClusterSummaries();
    return "admin";
  } catch {
    try {
      await Promise.all([clientByUser.listOrganizations(), clientByUser.listResources()]);
      return "user";
    } catch {
      return null;
    }
  }
}

export function App() {
  const [authRestorationAttempted, setAuthRestorationAttempted] = useState(false);
  const [rememberSession, setRememberSession] = useState(() => !!loadStoredSession());
  const [session, setSession] = useState<WebAdminSession | null>(() => loadStoredSession());
  const [consoleMode, setConsoleMode] = useState<ConsoleMode | null>(null);
  const [sessionRefreshedAt, setSessionRefreshedAt] = useState("");
  const [language, setLanguage] = useState<Language>(() => (localStorage.getItem(storageKeys.language) === "en" ? "en" : "ru"));
  const [actorUserId, setActorUserId] = useState(session?.userId ?? localStorage.getItem(storageKeys.actorUserId) ?? "");
  const [loginForm, setLoginForm] = useState({
    email: "",
    password: "",
    deviceLabel: "Панель владельца платформы",
    trustDevice: true,
    rememberMe: true,
    showPassword: false,
  });
  const [installationStatus, setInstallationStatus] = useState<InstallationStatus | null>(null);
  const [bootstrapForm, setBootstrapForm] = useState({
    email: "",
    password: "",
    activationPayload: "",
    activationSignature: "",
  });
  const [activeView, setActiveView] = useState<ViewId>("command");
  const [selectedClusterId, setSelectedClusterId] = useState("");

  const [clusters, setClusters] = useState<Cluster[]>([]);
  const [clusterSummaries, setClusterSummaries] = useState<ClusterAdminSummary[]>([]);
  const [authority, setAuthority] = useState<ClusterAuthorityState | null>(null);
  const [nodes, setNodes] = useState<ClusterNode[]>([]);
  const [nodeGroups, setNodeGroups] = useState<ClusterNodeGroup[]>([]);
  const [allNodesByCluster, setAllNodesByCluster] = useState<Record<string, ClusterNode[]>>({});
  const [joinRequests, setJoinRequests] = useState<JoinRequest[]>([]);
  const [joinTokens, setJoinTokens] = useState<NodeJoinToken[]>([]);
  const [releaseVersions, setReleaseVersions] = useState<ReleaseVersion[]>([]);
  const [staleNodeRiskReport, setStaleNodeRiskReport] = useState<StaleNodeRiskReport | null>(null);
  const [bridgeReplayPlansByNode, setBridgeReplayPlansByNode] = useState<Record<string, NodeBridgeReplayPlan>>({});
  const [nodeUpdatePlansByNode, setNodeUpdatePlansByNode] = useState<Record<string, NodeUpdatePlan>>({});
  const [nodeUpdateStatusesByNode, setNodeUpdateStatusesByNode] = useState<Record<string, NodeUpdateStatus[]>>({});
  const [rolesByNode, setRolesByNode] = useState<Record<string, RoleAssignment[]>>({});
  const [desiredWorkloadsByNode, setDesiredWorkloadsByNode] = useState<Record<string, NodeWorkloadDesiredState[]>>({});
  const [workloadsByNode, setWorkloadsByNode] = useState<Record<string, WorkloadStatus[]>>({});
  const [heartbeatsByNode, setHeartbeatsByNode] = useState<Record<string, NodeHeartbeat[]>>({});
  const [telemetryByNode, setTelemetryByNode] = useState<Record<string, NodeTelemetryObservation[]>>({});
  const [meshLinks, setMeshLinks] = useState<MeshLink[]>([]);
  const [routeIntents, setRouteIntents] = useState<MeshRouteIntent[]>([]);
  const [syntheticMeshConfigsByNode, setSyntheticMeshConfigsByNode] = useState<Record<string, NodeSyntheticMeshConfig>>({});
  const [fabricRouteFeedback, setFabricRouteFeedback] = useState<FabricServiceChannelRouteFeedbackObservation[]>([]);
  const [fabricRebuildAttempts, setFabricRebuildAttempts] = useState<FabricServiceChannelRouteRebuildAttempt[]>([]);
  const [fabricRebuildHealth, setFabricRebuildHealth] = useState<FabricServiceChannelRouteRebuildHealthSummary | null>(null);
  const [fabricRebuildSilences, setFabricRebuildSilences] = useState<FabricServiceChannelRouteRebuildAlertSilence[]>([]);
  const [fabricReadiness, setFabricReadiness] = useState<FabricServiceChannelReadiness | null>(null);
  const [fabricSchemaStatus, setFabricSchemaStatus] = useState<FabricServiceChannelSchemaStatus | null>(null);
  const [fabricSnapshotHealth, setFabricSnapshotHealth] = useState<FabricServiceChannelRebuildSnapshotMaintenanceHealth | null>(null);
  const [fabricSnapshotWarmup, setFabricSnapshotWarmup] = useState<FabricServiceChannelRebuildSnapshotWarmup | null>(null);
  const [fabricLeaseMaintenance, setFabricLeaseMaintenance] = useState<FabricServiceChannelLeaseMaintenance | null>(null);
  const [fabricAccessTelemetry, setFabricAccessTelemetry] = useState<FabricServiceChannelAccessTelemetry | null>(null);
  const [fabricRebuildIncidents, setFabricRebuildIncidents] = useState<FabricServiceChannelRouteRebuildIncident[]>([]);
  const [fabricRebuildLedgerDeep, setFabricRebuildLedgerDeep] = useState(false);
  const [fabricRebuildLedgerFilters, setFabricRebuildLedgerFilters] = useState<FabricRebuildLedgerFilters>(defaultFabricRebuildLedgerFilters);
  const [fabricRecoveryPolicy, setFabricRecoveryPolicy] = useState<FabricServiceChannelRecoveryPolicy | null>(null);
  const [fabricBreadcrumbWindowPolicy, setFabricBreadcrumbWindowPolicy] = useState<FabricServiceChannelBreadcrumbWindowPolicy | null>(null);
  const [qosPolicies, setQosPolicies] = useState<QoSPolicy[]>([]);
  const [testingFlags, setTestingFlags] = useState<FabricTestingFlag[]>([]);
  const [vpnConnections, setVPNConnections] = useState<VPNConnection[]>([]);
  const [vpnLeases, setVPNLeases] = useState<Record<string, VPNConnectionLease | null>>({});
  const [vpnPacketStats, setVPNPacketStats] = useState<Record<string, VPNPacketStats>>({});
  const [vpnDiagnosticDeviceId, setVPNDiagnosticDeviceId] = useState(() => localStorage.getItem(storageKeys.vpnDiagnosticDeviceId) || "");
  const [vpnClientDiagnostics, setVPNClientDiagnostics] = useState<VPNClientDiagnosticStatus[]>([]);
  const [vpnClientDiagnostic, setVPNClientDiagnostic] = useState<VPNClientDiagnosticStatus | null>(null);
  const [lastVPNDiagnosticCommand, setLastVPNDiagnosticCommand] = useState<VPNClientDiagnosticCommand | null>(null);
  const [organizations, setOrganizations] = useState<Organization[]>([]);
  const [users, setUsers] = useState<UserAccount[]>([]);
  const [resources, setResources] = useState<Resource[]>([]);
  const [membershipsByOrg, setMembershipsByOrg] = useState<Record<string, OrganizationMembership[]>>({});
  const [audit, setAudit] = useState<AuditEvent[]>([]);
  const [auditFocusNodeId, setAuditFocusNodeId] = useState("");
  const [auditFocusNodeLabel, setAuditFocusNodeLabel] = useState("");
  const [fabricDrilldownAudit, setFabricDrilldownAudit] = useState<AuditEvent[]>([]);
  const [fabricDrilldownAuditSummary, setFabricDrilldownAuditSummary] = useState<AuditSummary | null>(null);
  const [lastDataRefreshAt, setLastDataRefreshAt] = useState("");
  const [liveTransport, setLiveTransport] = useState<"sse" | "poll">("poll");

  const [organizationId, setOrganizationId] = useState("");
  const [organizationSummary, setOrganizationSummary] = useState<OrganizationAdminSummary | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  const [notice, setNotice] = useState("");

  const [clusterForm, setClusterForm] = useState({ slug: "", name: "", region: "" });
  const [clusterSettingsForm, setClusterSettingsForm] = useState({ name: "", status: "active", region: "", metadataJson: "{}" });
  const [nodeGroupForm, setNodeGroupForm] = useState({ name: "", parentGroupId: "" });
  const [fabricRecoveryPolicyForm, setFabricRecoveryPolicyForm] = useState({
    hysteresisPenalty: "150",
    promotionMinSamples: "64",
    demotionFailureThreshold: "1",
    demotionDropThreshold: "1",
    demotionSlowThreshold: "1",
    demotionRebuildEnabled: true,
    demotionFencedEnabled: true,
  });
  const [fabricBreadcrumbWindowPolicyForm, setFabricBreadcrumbWindowPolicyForm] = useState({
    currentWindowSeconds: "1800",
    historyWindowSeconds: "86400",
  });
  const [joinTokenForm, setJoinTokenForm] = useState<JoinTokenFormState>(defaultJoinTokenForm);
  const [lastJoinToken, setLastJoinToken] = useState<CreatedJoinToken | null>(null);
  const [lastJoinBundles, setLastJoinBundles] = useState<{
    docker?: InstallJoinBundle | null;
    linux_binary?: InstallJoinBundle | null;
    windows_service?: InstallJoinBundle | null;
  }>({});
  const [authorityForm, setAuthorityForm] = useState({ authorityState: "authoritative", mutationMode: "normal", notes: "" });
  const [nodeViewScope, setNodeViewScope] = useState<"cluster" | "all">("cluster");
  const [allNodeSearch, setAllNodeSearch] = useState("");
  const [nodeGroupFilterId, setNodeGroupFilterId] = useState("");
  const [collapsedNodeGroupKeys, setCollapsedNodeGroupKeys] = useState<string[]>([]);
  const [allNodeGroupBy, setAllNodeGroupBy] = useState<"membership" | "health" | "ownership" | "cluster_count">("membership");
  const [attachNodeDialog, setAttachNodeDialog] = useState<{ node: ClusterNode; memberships: Array<{ cluster: Cluster; node: ClusterNode }> } | null>(null);
  const [attachNodeRoles, setAttachNodeRoles] = useState<string[]>([]);
  const [nodeInfoDialog, setNodeInfoDialog] = useState<NodeInventoryEntry | null>(null);
  const [nodeInfoMode, setNodeInfoMode] = useState<"details" | "manage">("details");
  const [nodeRoleDrafts, setNodeRoleDrafts] = useState<Record<string, string>>({});
  const [nodeWorkloadDrafts, setNodeWorkloadDrafts] = useState<Record<string, string>>({});
  const [fabricListenerDrafts, setFabricListenerDrafts] = useState<
    Record<
      string,
      {
        listenAddr: string;
        mode: string;
        autoRange: string;
        advertiseEndpoint: string;
        endpointCandidates: string;
        advertiseTransport: string;
        connectivity: string;
        nat: string;
        region: string;
      }
    >
  >({});
  const [nodeTestingDrafts, setNodeTestingDrafts] = useState<Record<string, { telemetry: boolean; links: boolean }>>({});
  const [testingOrgId, setTestingOrgId] = useState("");
  const [testingOrgDraft, setTestingOrgDraft] = useState({ telemetry: true, links: true });
  const [workloadForm, setWorkloadForm] = useState({
    nodeId: "",
    serviceType: "rdp-worker",
    desiredState: "enabled",
    runtimeMode: "container",
    version: "",
    configJson: "{}",
    environmentJson: "{}",
  });
  const [vpnForm, setVPNForm] = useState({
    organizationId: "",
    name: "",
    protocolFamily: "generic",
    desiredState: "disabled",
    credentialRef: "",
    targetEndpointJson: "{}",
    allowedNodePolicyJson: `{"mode":"explicit","node_ids":[]}`,
    routingUsageJson: "[]",
    routePolicyJson: "{}",
    qosPolicyJson: "{}",
    placementPolicyJson: "{}",
  });
  const [organizationForm, setOrganizationForm] = useState({ slug: "", name: "" });
  const [userForm, setUserForm] = useState({ email: "", password: "", platformRole: "user" });
  const [membershipForm, setMembershipForm] = useState({ organizationId: "", userId: "", roleId: "org_member" });
  const [resourceSecretDialog, setResourceSecretDialog] = useState<Resource | null>(null);
  const [resourceSecretForm, setResourceSecretForm] = useState({ username: "", password: "", domain: "" });
  const [standardGuardSmokeResult, setstandardGuardSmokeResult] = useState("");
  const [standardGuardSmokeCheckedAt, setstandardGuardSmokeCheckedAt] = useState("");
  const [resourceForm, setResourceForm] = useState({
    organizationId: "",
    name: "",
    address: "",
    protocol: "rdp",
    routeMode: "vpn_exit",
    entryNode: "",
    exitNode: "",
    tags: "",
    username: "",
    password: "",
    domain: "",
  });
  const [androidClientVersion, setAndroidClientVersion] = useState("");
  const [androidClientPublishedAt, setAndroidClientPublishedAt] = useState("");
  const [androidClientVersionedPath, setAndroidClientVersionedPath] = useState("");
  const androidClientDefaultLatestFilename = "rap-android-vpn-latest-release.apk";
  const [androidClientLatestPath, setAndroidClientLatestPath] = useState(androidClientDefaultLatestFilename);

  const client = useMemo(() => new AdminApiClient({ actorUserId }), [actorUserId]);
  const authClient = useMemo(() => new AdminApiClient({ actorUserId: "" }), []);
  const clusterScopeRequestSeq = useRef(0);
  const autoRefreshInFlight = useRef(false);
  const t = copy[language];
  const selectedCluster = clusters.find((cluster) => cluster.id === selectedClusterId) || null;
  const selectedSummary = clusterSummaries.find((summary) => summary.cluster_id === selectedClusterId) || null;
  const portalDownloadBaseUrl = useMemo(() => (typeof window === "undefined" ? "" : window.location.origin), []);
  const resolvePortalDownloadPath = useCallback((artifactPath: string | undefined, fallbackName: string) => {
    if (!artifactPath) {
      return fallbackName;
    }
    const normalized = artifactPath.trim();
    if (!normalized) {
      return fallbackName;
    }
    if (/^https?:\/\//i.test(normalized) || normalized.startsWith("/")) {
      if (normalized.startsWith("/")) {
        return normalized.substring(1);
      }
      return normalized;
    }
    if (normalized.startsWith("downloads/")) {
      return normalized;
    }
    return `downloads/${normalized.replace(/^\.\/+/, "").replace(/^\/+/, "")}`;
  }, []);

  const portalAndroidLatestName = resolvePortalDownloadPath(androidClientLatestPath, androidClientDefaultLatestFilename);
  const portalAndroidVersionedName = androidClientVersionedPath
    ? resolvePortalDownloadPath(androidClientVersionedPath, portalAndroidLatestName)
    : portalAndroidLatestName;
  const portalAndroidArtifactPath = androidClientVersionedPath ? portalAndroidVersionedName : portalAndroidLatestName;
  const portalAndroidDownloadHref = /^https?:\/\//i.test(portalAndroidArtifactPath)
    ? portalAndroidArtifactPath
    : `${portalDownloadBaseUrl}/${portalAndroidArtifactPath}`;
  const androidVPNDownloadUrl = `${portalAndroidDownloadHref}${
    androidClientPublishedAt ? `?_v=${encodeURIComponent(androidClientPublishedAt)}` : ""
  }`;
  const joinTokenScope = useMemo(() => buildJoinTokenScope(joinTokenForm), [joinTokenForm]);
  const lastJoinTokenInstallForm = useMemo(
    () => (lastJoinToken ? joinTokenFormFromScope(lastJoinToken.scope, joinTokenForm) : joinTokenForm),
    [lastJoinToken, joinTokenForm],
  );
  const activeJoinBundle = useMemo(() => {
    if (joinTokenForm.installMode === "windows_service") {
      return lastJoinBundles.windows_service || null;
    }
    if (joinTokenForm.installMode === "linux_binary") {
      return lastJoinBundles.linux_binary || null;
    }
    return lastJoinBundles.docker || null;
  }, [joinTokenForm.installMode, lastJoinBundles]);
  const allNodeInventory = useMemo(() => {
    const grouped = new Map<
      string,
      {
        node: ClusterNode;
        memberships: Array<{ cluster: Cluster; node: ClusterNode }>;
      }
    >();

    for (const cluster of clusters) {
      for (const node of allNodesByCluster[cluster.id] || []) {
        const current = grouped.get(node.id);
        if (current) {
          current.memberships.push({ cluster, node });
          if ((node.last_seen_at || "") > (current.node.last_seen_at || "")) {
            current.node = node;
          }
        } else {
          grouped.set(node.id, { node, memberships: [{ cluster, node }] });
        }
      }
    }

    return Array.from(grouped.values()).sort((left, right) => left.node.name.localeCompare(right.node.name));
  }, [allNodesByCluster, clusters]);
  const groupedAllNodeInventory = useMemo(
    () => groupNodeInventory(allNodeInventory, selectedClusterId, allNodeSearch, allNodeGroupBy, language),
    [allNodeInventory, allNodeGroupBy, allNodeSearch, language, selectedClusterId],
  );
  const nodeInventoryByNodeId = useMemo(
    () => Object.fromEntries(allNodeInventory.map((entry) => [entry.node.id, entry])),
    [allNodeInventory],
  );
  const visibleNodeInventory = useMemo(() => {
    const normalizedSearch = allNodeSearch.trim().toLowerCase();
    const allowedGroupIds = nodeGroupFilterId ? new Set([nodeGroupFilterId, ...descendantGroupIds(nodeGroupFilterId, nodeGroups)]) : null;
    return allNodeInventory.filter((entry) => {
      const hasActiveClusterMembership = entry.memberships.some((membership) => membership.cluster.id === selectedClusterId);
      if (nodeViewScope !== "all" && !hasActiveClusterMembership) {
        return false;
      }
      if (allowedGroupIds) {
        const activeMembership = entry.memberships.find((membership) => membership.cluster.id === selectedClusterId);
        if (!activeMembership?.node.node_group_id || !allowedGroupIds.has(activeMembership.node.node_group_id)) {
          return false;
        }
      }
      return !normalizedSearch || nodeInventoryMatches(entry, normalizedSearch);
    });
  }, [allNodeInventory, allNodeSearch, nodeGroupFilterId, nodeGroups, nodeViewScope, selectedClusterId]);

  const persistSession = useCallback((nextSession: WebAdminSession | null, remember = false) => {
    if (nextSession && remember) {
      localStorage.setItem(storageKeys.auth, JSON.stringify(nextSession));
      localStorage.setItem(storageKeys.actorUserId, nextSession.userId);
      setRememberSession(true);
      return;
    }
    setRememberSession(false);
    localStorage.removeItem(storageKeys.auth);
    localStorage.removeItem(storageKeys.actorUserId);
  }, []);

  const updateAndroidPortalMetadata = useCallback(async () => {
    try {
      const manifestUrl = `${portalDownloadBaseUrl}/downloads/rap-android-vpn-build.json?_cb=${Date.now()}`;
      const response = await fetch(manifestUrl, { cache: "no-store" });
      if (!response.ok) {
        setAndroidClientVersion("");
        setAndroidClientPublishedAt(new Date().toISOString());
        setAndroidClientVersionedPath("");
        setAndroidClientLatestPath(androidClientDefaultLatestFilename);
        return;
      }
      const payload = (await response.json()) as {
        version?: { name?: string };
        published?: { timestamp_utc?: string; path?: string };
        release_paths?: {
          latest?: string;
          versioned?: string;
        };
      };
      setAndroidClientVersion(payload.version?.name || "");
      setAndroidClientPublishedAt(payload.published?.timestamp_utc || "");
      setAndroidClientVersionedPath(payload.release_paths?.versioned || "");
      setAndroidClientLatestPath(payload.published?.path || payload.release_paths?.latest || androidClientDefaultLatestFilename);
    } catch {
      setAndroidClientVersion("");
      setAndroidClientPublishedAt(new Date().toISOString());
      setAndroidClientVersionedPath("");
      setAndroidClientLatestPath(androidClientDefaultLatestFilename);
    }
  }, [portalDownloadBaseUrl]);

  const visibleNodeTreeRows = useMemo(
    () => buildNodeInventoryTreeRows(visibleNodeInventory, nodeGroups, selectedClusterId, t, new Set(collapsedNodeGroupKeys)),
    [collapsedNodeGroupKeys, nodeGroups, selectedClusterId, t, visibleNodeInventory],
  );
  const standardCleanupBlockedAuditEvents = useMemo(
    () =>
      audit
        .filter((event) => event.event_type === "fabric_standard_cleanup.blocked")
        .slice(0, 4),
    [audit],
  );
  const visibleAuditEvents = useMemo(
    () =>
      auditFocusNodeId
        ? audit.filter((event) => auditEventMatchesNode(event, auditFocusNodeId))
        : audit,
    [audit, auditFocusNodeId],
  );
  const focusBlockerNode = useCallback(
    (nodeId: string, mode: "details" | "manage") => {
      const entry = nodeInventoryByNodeId[nodeId];
      if (!entry) {
        return;
      }
      setActiveView("nodes");
      setNodeViewScope("all");
      setNodeGroupFilterId("");
      setAllNodeSearch(entry.node.name || entry.node.node_key);
      setNodeInfoDialog(entry);
      setNodeInfoMode(mode);
    },
    [nodeInventoryByNodeId],
  );
  const focusNodeAuditTrail = useCallback(
    (nodeId: string) => {
      const entry = nodeInventoryByNodeId[nodeId];
      setAuditFocusNodeId(nodeId);
      setAuditFocusNodeLabel(entry?.node.name || entry?.node.node_key || nodeId);
      setActiveView("audit");
    },
    [nodeInventoryByNodeId],
  );
  const fabricDrilldownAuditEvents = useMemo(
    () => fabricDrilldownAudit.slice(0, 8),
    [fabricDrilldownAudit],
  );

  useEffect(() => {
    if (authRestorationAttempted) {
      return;
    }
    setAuthRestorationAttempted(true);

    const storedSession = loadStoredSession();
    if (!storedSession) {
      return;
    }

    if (isTokenExpired(storedSession.refreshTokenExpiresAt)) {
      localStorage.removeItem(storageKeys.auth);
      localStorage.removeItem(storageKeys.actorUserId);
      setRememberSession(false);
      return;
    }

    const attemptRestore = async () => {
      try {
        const result = await authClient.refresh({
          refreshToken: storedSession.refreshToken,
        });
        const restored = normalizeAuthResult(result);
        if (!restored.userId || !restored.authSessionId) {
          throw new Error("Не удалось восстановить сессию.");
        }

        const accessClient = new AdminApiClient({ actorUserId: restored.userId });
        const mode = await resolveConsoleMode(accessClient);
        if (!mode) {
          throw new Error("Доступ к этой панели запрещен.");
        }
        setActorUserId(restored.userId);
        persistSession(restored, true);
        setSession(restored);
        setSessionRefreshedAt(new Date().toISOString());
        setLoginForm((previous) => ({ ...previous, email: restored.email }));
        setConsoleMode(mode);
      } catch {
        localStorage.removeItem(storageKeys.auth);
        localStorage.removeItem(storageKeys.actorUserId);
        setRememberSession(false);
        setSessionRefreshedAt("");
        setSession(null);
        setActorUserId("");
        setConsoleMode(null);
      }
    };

    void attemptRestore();
  }, [authClient, authRestorationAttempted, persistSession]);

  useEffect(() => {
    let cancelled = false;
    authClient
      .getInstallationStatus()
      .then((status) => {
        if (!cancelled) {
          setInstallationStatus(status);
        }
      })
      .catch((err) => {
        if (!cancelled) {
          setError(err instanceof Error ? err.message : "Не удалось загрузить статус установки.");
        }
      });
    return () => {
      cancelled = true;
    };
  }, [authClient]);

  useEffect(() => {
    if (!selectedCluster) {
      setClusterSettingsForm({ name: "", status: "active", region: "", metadataJson: "{}" });
      return;
    }
    setClusterSettingsForm({
      name: selectedCluster.name,
      status: selectedCluster.status || "active",
      region: selectedCluster.region || "",
      metadataJson: JSON.stringify(selectedCluster.metadata || {}, null, 2),
    });
  }, [selectedCluster]);

  useEffect(() => {
    setNodeGroupFilterId("");
    setNodeGroupForm({ name: "", parentGroupId: "" });
    setCollapsedNodeGroupKeys([]);
  }, [selectedClusterId]);

  useEffect(() => {
    setAttachNodeDialog(null);
    setAttachNodeRoles([]);
  }, [selectedClusterId]);

  useEffect(() => {
    localStorage.setItem(storageKeys.language, language);
    if (session) {
      localStorage.setItem(`${storageKeys.language}.${session.userId}`, language);
    }
    if (!session || !rememberSession) {
      localStorage.removeItem(storageKeys.auth);
      localStorage.removeItem(storageKeys.actorUserId);
    }
  }, [language, rememberSession, session]);

  useEffect(() => {
    if (!session) {
      return;
    }
    const userLanguage = localStorage.getItem(`${storageKeys.language}.${session.userId}`);
    if (userLanguage === "ru" || userLanguage === "en") {
      setLanguage(userLanguage);
    }
  }, [session?.userId]);

  useEffect(() => {
    if (session) {
      void refreshAll();
    }
    // First load only. The operator keeps refresh timing explicit after that.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [session?.userId]);

  useEffect(() => {
    if (!session || consoleMode !== "admin" || !selectedClusterId) {
      return;
    }
    let cancelled = false;
    const tick = () => {
      if (cancelled || loading || autoRefreshInFlight.current || document.visibilityState === "hidden") {
        return;
      }
      autoRefreshInFlight.current = true;
      refreshLiveData(selectedClusterId)
        .catch((err) => {
          if (!cancelled) {
            setError(err instanceof Error ? err.message : "Не удалось автообновить данные панели.");
          }
        })
        .finally(() => {
          autoRefreshInFlight.current = false;
        });
    };
    let eventSource: EventSource | null = null;
    if (typeof window.EventSource === "function") {
      eventSource = new EventSource(client.clusterEventsURL(selectedClusterId));
      eventSource.onopen = () => {
        if (!cancelled) {
          setLiveTransport("sse");
        }
      };
      eventSource.onerror = () => {
        if (!cancelled) {
          setLiveTransport("poll");
        }
      };
      eventSource.addEventListener("cluster.changed", tick);
    }
    const interval = window.setInterval(tick, eventSource ? 30_000 : 10_000);
    return () => {
      cancelled = true;
      eventSource?.close();
      window.clearInterval(interval);
    };
  }, [client, consoleMode, loading, selectedClusterId, session?.userId]);

  async function refreshAll(preferredClusterId = selectedClusterId) {
    if (!actorUserId.trim()) {
      setError(t.noLoginError);
      return;
    }
    if (consoleMode === "user") {
      await refreshUserPortal();
      return;
    }
    setLoading(true);
    setError("");
    setNotice("");
    try {
      const [loadedClusters, loadedSummaries, loadedOrganizations, loadedUsers, loadedResources] = await Promise.all([
        client.listClusters(),
        client.listClusterSummaries(),
        client.listOrganizations(),
        client.listUsers(),
        client.listResources(),
      ]);
      setClusters(loadedClusters);
      setClusterSummaries(loadedSummaries);
      setOrganizations(loadedOrganizations);
      setUsers(loadedUsers);
      setResources(loadedResources);
      if (!organizationId && loadedOrganizations[0]?.id) {
        setOrganizationId(loadedOrganizations[0].id);
      }
      setMembershipForm((previous) => ({ ...previous, organizationId: previous.organizationId || loadedOrganizations[0]?.id || "" }));
      setResourceForm((previous) => ({ ...previous, organizationId: previous.organizationId || loadedOrganizations[0]?.id || "" }));
      const membershipEntries = await Promise.all(
        loadedOrganizations.map(async (org) => [org.id, await client.listOrganizationMemberships(org.id)] as const),
      );
      setMembershipsByOrg(Object.fromEntries(membershipEntries));
      const allNodeEntries = await Promise.all(loadedClusters.map(async (cluster) => [cluster.id, await client.listNodes(cluster.id)] as const));
      setAllNodesByCluster(Object.fromEntries(allNodeEntries));
      const clusterId = preferredClusterId || loadedClusters[0]?.id || "";
      setSelectedClusterId(clusterId);
      if (clusterId) {
        await loadClusterScope(clusterId);
      }
      setLastDataRefreshAt(new Date().toISOString());
    } catch (err) {
      setError(err instanceof Error ? err.message : "Неизвестная ошибка панели управления платформой.");
    } finally {
      setLoading(false);
    }
  }

  async function refreshUserPortal() {
    if (!actorUserId.trim()) {
      setError("Войдите, чтобы загрузить личный кабинет.");
      return;
    }
    setLoading(true);
    setError("");
    setNotice("");
    try {
      await updateAndroidPortalMetadata();
      const [loadedOrganizations, loadedResources] = await Promise.all([client.listOrganizations(), client.listResources()]);
      setOrganizations(loadedOrganizations);
      setResources(loadedResources);
      if (!organizationId && loadedOrganizations[0]?.id) {
        setOrganizationId(loadedOrganizations[0].id);
      }
      const membershipEntries = await Promise.all(
        loadedOrganizations.map(async (org) => [org.id, await client.listOrganizationMemberships(org.id)] as const),
      );
      setMembershipsByOrg(Object.fromEntries(membershipEntries));
      setLastDataRefreshAt(new Date().toISOString());
    } catch (err) {
      setError(err instanceof Error ? err.message : "Не удалось загрузить личный кабинет.");
    } finally {
      setLoading(false);
    }
  }

  async function refreshLiveData(clusterId: string) {
    if (!actorUserId.trim()) {
      return;
    }
    const [loadedSummaries, loadedNodes, loadedOrganizations, loadedUsers, loadedResources] = await Promise.all([
      client.listClusterSummaries(),
      client.listNodes(clusterId),
      client.listOrganizations(),
      client.listUsers(),
      client.listResources(),
    ]);
    setClusterSummaries(loadedSummaries);
    setOrganizations(loadedOrganizations);
    setUsers(loadedUsers);
    setResources(loadedResources);
    setAllNodesByCluster((previous) => ({ ...previous, [clusterId]: loadedNodes }));
    await loadClusterScope(clusterId, { preserveEditableForms: true });
    setLastDataRefreshAt(new Date().toISOString());
  }

  async function loadClusterScope(clusterId: string, options: { preserveEditableForms?: boolean } = {}) {
    const requestSeq = ++clusterScopeRequestSeq.current;
    const rebuildLedgerLimit = fabricRebuildLedgerDeep ? 20 : 10;
    const rebuildLedgerOffset = fabricRebuildLedgerDeep ? fabricRebuildLedgerFilters.offset : 0;
    const rebuildLedgerInput = {
      reporterNodeId: fabricRebuildLedgerFilters.reporterNodeId || undefined,
      routeId: fabricRebuildLedgerFilters.routeId || undefined,
      serviceClass: fabricRebuildLedgerFilters.serviceClass || undefined,
      generation: fabricRebuildLedgerFilters.generation || undefined,
      feedbackSource: fabricRebuildLedgerFilters.feedbackSource || undefined,
      feedbackChannelId: fabricRebuildLedgerFilters.feedbackChannelId || undefined,
      feedbackViolationStatus: fabricRebuildLedgerFilters.feedbackViolationStatus || undefined,
      limit: rebuildLedgerLimit,
      offset: rebuildLedgerOffset,
      enrichment: fabricRebuildLedgerDeep ? ("deep" as const) : ("summary" as const),
    };
    const [
      loadedNodes,
      loadedNodeGroups,
      loadedJoinRequests,
      loadedJoinTokens,
      loadedReleaseVersions,
      loadedStaleNodeRiskReport,
      loadedAuthority,
      loadedAudit,
      loadedFabricDrilldownAuditResult,
      loadedMeshLinks,
      loadedRouteIntents,
      loadedFabricRouteFeedback,
      loadedFabricRebuildAttempts,
      loadedFabricRebuildHealth,
      loadedFabricRebuildSilences,
      loadedFabricReadiness,
      loadedFabricSchemaStatus,
      loadedFabricSnapshotHealth,
      loadedFabricLeaseMaintenance,
      loadedFabricAccessTelemetry,
      loadedFabricRebuildIncidents,
      loadedFabricRecoveryPolicy,
      loadedFabricBreadcrumbWindowPolicy,
      loadedQosPolicies,
      loadedVPNConnections,
      loadedTestingFlags,
    ] =
      await Promise.all([
        client.listNodes(clusterId),
        client.listNodeGroups(clusterId),
        client.listJoinRequests(clusterId),
        client.listJoinTokens(clusterId),
        client.listReleaseVersions(clusterId, "rap-node-agent", "dev"),
        client.getStaleNodeRiskReport(clusterId),
        client.getClusterAuthority(clusterId),
        client.listAudit(clusterId),
        client.getFabricServiceChannelRebuildInvestigationBreadcrumbs(clusterId, { limit: 20 }),
        client.listMeshLinks(clusterId),
        client.listRouteIntents(clusterId),
        client.listFabricServiceChannelRouteFeedback(clusterId, { includeExpired: true }),
        client.listFabricServiceChannelRouteRebuildAttempts(clusterId, rebuildLedgerInput),
        client.getFabricServiceChannelRouteRebuildHealthSummary(clusterId, { limit: 5 }),
        client.listFabricServiceChannelRouteRebuildAlertSilences(clusterId),
        client.getFabricServiceChannelReadiness(clusterId, { limit: 5 }),
        client.getFabricServiceChannelSchemaStatus(clusterId),
        client.getFabricServiceChannelRebuildSnapshotMaintenanceHealth(clusterId, { limit: 50, minAgeSeconds: 60, heartbeatThreshold: 2 }),
        client.getFabricServiceChannelLeaseMaintenance(clusterId, { limit: 20, includeExpired: true }),
        client.getFabricServiceChannelAccessTelemetry(clusterId, { limit: 20 }),
        client.listFabricServiceChannelRouteRebuildIncidents(clusterId, { limit: 5 }),
        client.getFabricServiceChannelRecoveryPolicy(clusterId),
        client.getFabricServiceChannelBreadcrumbWindowPolicy(clusterId),
        client.listQoSPolicies(clusterId),
        client.listVPNConnections(clusterId),
        client.listFabricTestingFlags(),
      ]);
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setNodes(loadedNodes);
    setNodeGroups(loadedNodeGroups);
    setJoinRequests(loadedJoinRequests);
    setJoinTokens(loadedJoinTokens);
    setReleaseVersions(loadedReleaseVersions);
    setStaleNodeRiskReport(loadedStaleNodeRiskReport);
    setAuthority(loadedAuthority);
    if (!options.preserveEditableForms) {
      setAuthorityForm({
        authorityState: loadedAuthority.authority_state,
        mutationMode: loadedAuthority.mutation_mode,
        notes: loadedAuthority.notes || "",
      });
    }
    setAudit(loadedAudit);
    setFabricDrilldownAudit(loadedFabricDrilldownAuditResult.events);
    setFabricDrilldownAuditSummary(loadedFabricDrilldownAuditResult.summary || null);
    setMeshLinks(loadedMeshLinks);
    setRouteIntents(loadedRouteIntents);
    setFabricRouteFeedback(loadedFabricRouteFeedback);
    setFabricRebuildAttempts(loadedFabricRebuildAttempts);
    setFabricRebuildHealth(loadedFabricRebuildHealth);
    setFabricRebuildSilences(loadedFabricRebuildSilences);
    setFabricReadiness(loadedFabricReadiness);
    setFabricSchemaStatus(loadedFabricSchemaStatus);
    setFabricSnapshotHealth(loadedFabricSnapshotHealth);
    setFabricLeaseMaintenance(loadedFabricLeaseMaintenance);
    setFabricAccessTelemetry(loadedFabricAccessTelemetry);
    setFabricRebuildIncidents(loadedFabricRebuildIncidents);
    setFabricRecoveryPolicy(loadedFabricRecoveryPolicy);
    setFabricBreadcrumbWindowPolicy(loadedFabricBreadcrumbWindowPolicy);
    if (!options.preserveEditableForms) {
      setFabricBreadcrumbWindowPolicyForm({
        currentWindowSeconds: String(loadedFabricBreadcrumbWindowPolicy.current_window_seconds || 1800),
        historyWindowSeconds: String(loadedFabricBreadcrumbWindowPolicy.history_window_seconds || 86400),
      });
    }
    setFabricRecoveryPolicyForm({
      hysteresisPenalty: String(loadedFabricRecoveryPolicy.hysteresis_penalty),
      promotionMinSamples: String(loadedFabricRecoveryPolicy.promotion_min_samples),
      demotionFailureThreshold: String(loadedFabricRecoveryPolicy.demotion_failure_threshold),
      demotionDropThreshold: String(loadedFabricRecoveryPolicy.demotion_drop_threshold),
      demotionSlowThreshold: String(loadedFabricRecoveryPolicy.demotion_slow_threshold),
      demotionRebuildEnabled: loadedFabricRecoveryPolicy.demotion_rebuild_enabled,
      demotionFencedEnabled: loadedFabricRecoveryPolicy.demotion_fenced_enabled,
    });
    setQosPolicies(loadedQosPolicies);
    setVPNConnections(loadedVPNConnections);
    setTestingFlags(loadedTestingFlags);
    const diagnostics = await client.listVPNClientDiagnosticStatuses(clusterId);
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setVPNClientDiagnostics(diagnostics);
    const selectedDiagnostic =
      diagnostics.find((item) => item.device_id === vpnDiagnosticDeviceId.trim()) ||
      diagnostics[0] ||
      null;
    setVPNClientDiagnostic(selectedDiagnostic);
    if (!vpnDiagnosticDeviceId.trim() && selectedDiagnostic) {
      setVPNDiagnosticDeviceId(selectedDiagnostic.device_id);
      localStorage.setItem(storageKeys.vpnDiagnosticDeviceId, selectedDiagnostic.device_id);
    }

    const roleEntries = await Promise.all(loadedNodes.map(async (node) => [node.id, await client.listNodeRoles(clusterId, node.id)] as const));
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setRolesByNode(Object.fromEntries(roleEntries));

    const desiredEntries = await Promise.all(loadedNodes.map(async (node) => [node.id, await client.listDesiredWorkloads(clusterId, node.id)] as const));
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setDesiredWorkloadsByNode(Object.fromEntries(desiredEntries));

    const workloadEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.listWorkloadStatuses(clusterId, node.id)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setWorkloadsByNode(Object.fromEntries(workloadEntries));

    const heartbeatEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.listNodeHeartbeats(clusterId, node.id, 60)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setHeartbeatsByNode(Object.fromEntries(heartbeatEntries));

    const replayReadyNodeIds = loadedStaleNodeRiskReport.nodes
      .filter((node) => node.recovery_bridge_replay_ready)
      .map((node) => node.node_id);
    if (replayReadyNodeIds.length > 0) {
      const bridgeReplayEntries = await Promise.all(
        replayReadyNodeIds.map(async (nodeId) => [nodeId, await client.getNodeBridgeReplayPlan(clusterId, nodeId)] as const),
      );
      if (requestSeq !== clusterScopeRequestSeq.current) {
        return;
      }
      setBridgeReplayPlansByNode(Object.fromEntries(bridgeReplayEntries));
    } else {
      setBridgeReplayPlansByNode({});
    }

    const updatePlanEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.getNodeUpdatePlan(clusterId, node.id, { currentVersion: node.reported_version })] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setNodeUpdatePlansByNode(Object.fromEntries(updatePlanEntries));

    const updateStatusEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.listNodeUpdateStatuses(clusterId, node.id, 80)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setNodeUpdateStatusesByNode(Object.fromEntries(updateStatusEntries));

    const telemetryEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.listNodeTelemetry(clusterId, node.id, 120)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setTelemetryByNode(Object.fromEntries(telemetryEntries));

    const syntheticMeshConfigEntries = await Promise.all(
      loadedNodes.map(async (node) => [node.id, await client.getNodeSyntheticMeshConfig(clusterId, node.id)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setSyntheticMeshConfigsByNode(Object.fromEntries(syntheticMeshConfigEntries));

    const leaseEntries = await Promise.all(
      loadedVPNConnections.map(async (connection) => [connection.id, await client.getActiveVPNLease(clusterId, connection.id)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setVPNLeases(Object.fromEntries(leaseEntries));

    const vpnPacketStatEntries = await Promise.all(
      loadedVPNConnections.map(async (connection) => [connection.id, await client.getVPNPacketStats(clusterId, connection.id)] as const),
    );
    if (requestSeq !== clusterScopeRequestSeq.current) {
      return;
    }
    setVPNPacketStats(Object.fromEntries(vpnPacketStatEntries));
  }

  async function loadFabricRebuildLedger(nextDeep = fabricRebuildLedgerDeep, nextFilters = fabricRebuildLedgerFilters) {
    if (!selectedClusterId) {
      return;
    }
    setLoading(true);
    setError("");
    setNotice("");
    try {
      const attempts = await client.listFabricServiceChannelRouteRebuildAttempts(selectedClusterId, {
        reporterNodeId: nextFilters.reporterNodeId || undefined,
        routeId: nextFilters.routeId || undefined,
        serviceClass: nextFilters.serviceClass || undefined,
        generation: nextFilters.generation || undefined,
        feedbackSource: nextFilters.feedbackSource || undefined,
        feedbackChannelId: nextFilters.feedbackChannelId || undefined,
        feedbackViolationStatus: nextFilters.feedbackViolationStatus || undefined,
        limit: nextDeep ? 20 : 10,
        offset: nextDeep ? nextFilters.offset : 0,
        enrichment: nextDeep ? "deep" : "summary",
      });
      setFabricRebuildLedgerDeep(nextDeep);
      setFabricRebuildLedgerFilters(nextFilters);
      setFabricRebuildAttempts(attempts);
      setNotice(nextDeep ? "Deep rebuild ledger loaded." : "Fast rebuild ledger loaded.");
    } catch (err) {
      setError(err instanceof Error ? err.message : "Не удалось загрузить rebuild ledger.");
    } finally {
      setLoading(false);
    }
  }

  async function refreshFabricRebuildDiagnostics() {
    if (!selectedClusterId) {
      return;
    }
    const [health, silences, readiness, schemaStatus, snapshotHealth, leaseMaintenance, accessTelemetry, incidents, drilldownAudit, breadcrumbWindowPolicy] = await Promise.all([
      client.getFabricServiceChannelRouteRebuildHealthSummary(selectedClusterId, { limit: 5 }),
      client.listFabricServiceChannelRouteRebuildAlertSilences(selectedClusterId),
      client.getFabricServiceChannelReadiness(selectedClusterId, { limit: 5 }),
      client.getFabricServiceChannelSchemaStatus(selectedClusterId),
      client.getFabricServiceChannelRebuildSnapshotMaintenanceHealth(selectedClusterId, { limit: 50, minAgeSeconds: 60, heartbeatThreshold: 2 }),
      client.getFabricServiceChannelLeaseMaintenance(selectedClusterId, { limit: 20, includeExpired: true }),
      client.getFabricServiceChannelAccessTelemetry(selectedClusterId, { limit: 20 }),
      client.listFabricServiceChannelRouteRebuildIncidents(selectedClusterId, { limit: 5 }),
      client.getFabricServiceChannelRebuildInvestigationBreadcrumbs(selectedClusterId, { limit: 20 }),
      client.getFabricServiceChannelBreadcrumbWindowPolicy(selectedClusterId),
    ]);
    setFabricRebuildHealth(health);
    setFabricRebuildSilences(silences);
    setFabricReadiness(readiness);
    setFabricSchemaStatus(schemaStatus);
    setFabricSnapshotHealth(snapshotHealth);
    setFabricLeaseMaintenance(leaseMaintenance);
    setFabricAccessTelemetry(accessTelemetry);
    setFabricRebuildIncidents(incidents);
    setFabricDrilldownAudit(drilldownAudit.events);
    setFabricDrilldownAuditSummary(drilldownAudit.summary || null);
    setFabricBreadcrumbWindowPolicy(breadcrumbWindowPolicy);
    setFabricBreadcrumbWindowPolicyForm({
      currentWindowSeconds: String(breadcrumbWindowPolicy.current_window_seconds || 1800),
      historyWindowSeconds: String(breadcrumbWindowPolicy.history_window_seconds || 86400),
    });
  }

  async function warmupFabricRebuildSnapshots() {
    if (!selectedClusterId) {
      return;
    }
    try {
      setLoading(true);
      const warmup = await client.warmupFabricServiceChannelRebuildSnapshots(selectedClusterId, { limit: 10, staleAfterSeconds: 60 });
      setFabricSnapshotWarmup(warmup);
      await refreshFabricRebuildDiagnostics();
      setNotice(`Snapshot warmup: warmed ${warmup.warmed_count}, fresh ${warmup.already_fresh_count}, errors ${warmup.error_count}.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Не удалось прогреть rebuild snapshots.");
    } finally {
      setLoading(false);
    }
  }

  async function cleanupFabricServiceChannelLeases() {
    if (!selectedClusterId) {
      return;
    }
    try {
      setLoading(true);
      const result = await client.cleanupFabricServiceChannelLeases(selectedClusterId, { limit: 100 });
      setFabricLeaseMaintenance(result);
      setNotice(`Service-channel lease cleanup: deleted ${result.deleted_expired_count || 0}, active ${result.active_count}, expired ${result.expired_count}.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Не удалось очистить service-channel leases.");
    } finally {
      setLoading(false);
    }
  }

  async function openFabricRebuildIncidentDeepLedger(incident: FabricServiceChannelRouteRebuildIncident) {
    const filters = {
      reporterNodeId: incident.reporter_node_id,
      routeId: incident.route_id,
      serviceClass: incident.service_class,
      generation: incident.generation || "",
      feedbackSource: "",
      feedbackChannelId: incident.channel_id || "",
      feedbackViolationStatus: "",
      offset: 0,
    };
    await client.recordFabricServiceChannelRouteRebuildInvestigation(selectedClusterId, {
      reporterNodeId: incident.reporter_node_id,
      routeId: incident.route_id,
      serviceClass: incident.service_class,
      generation: incident.generation || "",
      guardStatus: incident.guard_status,
      incidentId: incident.fingerprint,
    });
    const drilldownAudit = await client.getFabricServiceChannelRebuildInvestigationBreadcrumbs(selectedClusterId, { limit: 20 });
    setFabricDrilldownAudit(drilldownAudit.events);
    setFabricDrilldownAuditSummary(drilldownAudit.summary || null);
    setFabricRebuildLedgerFilters(filters);
    await loadFabricRebuildLedger(true, filters);
  }

  function fabricRebuildIncidentsForFeedbackBreakdown(item: FabricServiceChannelRouteRebuildFeedbackHealthBreakdown) {
    const reporterNodeIDs = new Set(item.affected_reporter_node_ids || []);
    const routeIDs = new Set(item.affected_route_ids || []);
    return fabricRebuildIncidents.filter((incident) => {
      const channelMatches = !item.feedback_channel_id || incident.channel_id === item.feedback_channel_id;
      const reporterMatches = reporterNodeIDs.size === 0 || reporterNodeIDs.has(incident.reporter_node_id);
      const routeMatches = routeIDs.size === 0 || routeIDs.has(incident.route_id);
      return channelMatches && reporterMatches && routeMatches;
    });
  }

  function fabricFeedbackBreakdownForAuditEvent(event: AuditEvent) {
    const payload = objectField(event.payload) || {};
    const feedbackSource = stringField(payload, "feedback_source", "");
    const feedbackChannelID = stringField(payload, "feedback_channel_id", "");
    const feedbackViolationStatus = stringField(payload, "feedback_violation_status", "");
    const reporterNodeID = stringField(payload, "reporter_node_id", "");
    const routeID = stringField(payload, "route_id", "");
    if (!feedbackSource && !feedbackChannelID && !feedbackViolationStatus) {
      return null;
    }
    return (
      (fabricRebuildHealth?.feedback_breakdowns || []).find((item) => {
        if (feedbackSource && item.feedback_source !== feedbackSource) {
          return false;
        }
        if (feedbackChannelID && item.feedback_channel_id !== feedbackChannelID) {
          return false;
        }
        if (feedbackViolationStatus && item.feedback_violation_status !== feedbackViolationStatus) {
          return false;
        }
        if (reporterNodeID && !(item.affected_reporter_node_ids || []).includes(reporterNodeID)) {
          return false;
        }
        if (routeID && !(item.affected_route_ids || []).includes(routeID)) {
          return false;
        }
        return true;
      }) || null
    );
  }

  function fabricRebuildIncidentForAuditEvent(event: AuditEvent) {
    const payload = objectField(event.payload) || {};
    const reporterNodeID = stringField(payload, "reporter_node_id", "");
    const routeID = stringField(payload, "route_id", event.target_type === "fabric_service_channel_route_rebuild_incident" ? event.target_id || "" : "");
    const serviceClass = stringField(payload, "service_class", "");
    const generation = stringField(payload, "generation", "");
    const guardStatus = stringField(payload, "guard_status", "");
    return (
      fabricRebuildIncidents.find((incident) => {
        if (reporterNodeID && incident.reporter_node_id !== reporterNodeID) {
          return false;
        }
        if (routeID && incident.route_id !== routeID) {
          return false;
        }
        if (serviceClass && incident.service_class !== serviceClass) {
          return false;
        }
        if (generation && incident.generation !== generation) {
          return false;
        }
        if (guardStatus && incident.guard_status !== guardStatus) {
          return false;
        }
        return Boolean(reporterNodeID || routeID || serviceClass || generation || guardStatus);
      }) || null
    );
  }

  async function openFabricRebuildFeedbackBreakdownLedger(item: FabricServiceChannelRouteRebuildFeedbackHealthBreakdown) {
    const filters = {
      ...defaultFabricRebuildLedgerFilters,
      feedbackSource: item.feedback_source || "",
      feedbackChannelId: item.feedback_channel_id || "",
      feedbackViolationStatus: item.feedback_violation_status || "",
      offset: 0,
    };
    await client.recordFabricServiceChannelRouteRebuildInvestigation(selectedClusterId, {
      reporterNodeId: (item.affected_reporter_node_ids || [])[0] || "",
      routeId: (item.affected_route_ids || [])[0] || "",
      feedbackSource: item.feedback_source || "",
      feedbackChannelId: item.feedback_channel_id || "",
      feedbackViolationStatus: item.feedback_violation_status || "",
      drilldownSource: "rebuild_health_feedback_breakdown",
      reason: "operator opened rebuild-health feedback breakdown ledger",
    });
    const drilldownAudit = await client.getFabricServiceChannelRebuildInvestigationBreadcrumbs(selectedClusterId, { limit: 20 });
    setFabricDrilldownAudit(drilldownAudit.events);
    setFabricDrilldownAuditSummary(drilldownAudit.summary || null);
    setActiveView("fabric");
    setFabricRebuildLedgerFilters(filters);
    await loadFabricRebuildLedger(true, filters);
  }

  async function silenceFabricRebuildIncident(incident: FabricServiceChannelRouteRebuildIncident) {
    await client.silenceFabricServiceChannelRouteRebuildAlert(selectedClusterId, {
      incidentSource: incident.incident_source || "",
      channelId: incident.channel_id || "",
      reporterNodeId: incident.reporter_node_id,
      routeId: incident.route_id,
      guardStatus: incident.guard_status || "unknown",
      generation: incident.generation || "",
      reason: "operator acknowledged rebuild incident",
      ttlSeconds: 21600,
    });
    await refreshFabricRebuildDiagnostics();
  }

  async function unsilenceFabricRebuildAlert(silence: FabricServiceChannelRouteRebuildAlertSilence) {
    await client.unsilenceFabricServiceChannelRouteRebuildAlert(
      selectedClusterId,
      silence.id,
      "operator removed rebuild alert silence",
    );
    await refreshFabricRebuildDiagnostics();
  }

  function clearClusterScope() {
    setNodes([]);
    setNodeGroups([]);
    setJoinRequests([]);
    setJoinTokens([]);
    setReleaseVersions([]);
    setStaleNodeRiskReport(null);
    setBridgeReplayPlansByNode({});
    setNodeUpdatePlansByNode({});
    setAuthority(null);
    setRolesByNode({});
    setDesiredWorkloadsByNode({});
    setWorkloadsByNode({});
    setHeartbeatsByNode({});
    setNodeUpdateStatusesByNode({});
    setTelemetryByNode({});
    setMeshLinks([]);
    setRouteIntents([]);
    setSyntheticMeshConfigsByNode({});
    setFabricRouteFeedback([]);
    setFabricRebuildAttempts([]);
    setFabricRebuildHealth(null);
    setFabricRebuildSilences([]);
    setFabricReadiness(null);
    setFabricSchemaStatus(null);
    setFabricSnapshotWarmup(null);
    setFabricRebuildIncidents([]);
    setFabricRebuildLedgerDeep(false);
    setFabricRebuildLedgerFilters(defaultFabricRebuildLedgerFilters);
    setQosPolicies([]);
    setTestingFlags([]);
    setVPNConnections([]);
    setVPNLeases({});
    setVPNPacketStats({});
    setVPNClientDiagnostics([]);
    setVPNClientDiagnostic(null);
    setOrganizations([]);
    setUsers([]);
    setResources([]);
    setMembershipsByOrg({});
    setAudit([]);
    setFabricDrilldownAudit([]);
    setFabricDrilldownAuditSummary(null);
  }

  async function runAction(action: () => Promise<unknown>, success: string) {
    setLoading(true);
    setError("");
    setNotice("");
    try {
      await action();
      setNotice(success);
      await refreshAll();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Действие не выполнено.");
    } finally {
      setLoading(false);
    }
  }

  async function runFabricStandardCleanupGuardSmoke() {
    if (!selectedClusterId || !staleNodeRiskReport || staleNodeRiskReport.summary.blocked_nodes < 1) {
      setstandardGuardSmokeResult("Guard smoke сейчас недоступен: в отчете нет blocker-узлов для controlled blocked-check.");
      setstandardGuardSmokeCheckedAt(new Date().toISOString());
      return;
    }
    setLoading(true);
    setError("");
    setNotice("");
    setstandardGuardSmokeResult("");
    try {
      const smokeVersion = `0.2.402-guard-smoke-${Date.now()}`;
      await client.createReleaseVersion(selectedClusterId, {
        product: "rap-node-agent",
        version: smokeVersion,
        channel: "stable",
        status: "active",
        changelog: "UI smoke check for fabric standard cleanup guard",
        artifacts: [
          {
            os: "linux",
            arch: "amd64",
            installType: "docker",
            kind: "image",
            url: "fabric-artifact://guard-smoke/rap-node-agent.tar",
            sha256: "sha256-guard-smoke",
            sizeBytes: 123,
            metadata: {},
          },
        ],
      });
      setstandardGuardSmokeResult(
        "Smoke unexpectedly succeeded. Guard should have blocked breaking release creation while stale recovery-risk nodes remain.",
      );
    } catch (err) {
      setstandardGuardSmokeResult(err instanceof Error ? err.message : "Guard smoke failed with a non-Error response.");
    } finally {
      setstandardGuardSmokeCheckedAt(new Date().toISOString());
      setLoading(false);
    }
  }

  async function refreshVPNClientDiagnostic() {
    if (!selectedClusterId) {
      setVPNClientDiagnostic(null);
      return;
    }
    const diagnostics = await client.listVPNClientDiagnosticStatuses(selectedClusterId);
    setVPNClientDiagnostics(diagnostics);
    const selectedDeviceId = vpnDiagnosticDeviceId.trim() || diagnostics[0]?.device_id || "";
    if (selectedDeviceId) {
      localStorage.setItem(storageKeys.vpnDiagnosticDeviceId, selectedDeviceId);
      setVPNDiagnosticDeviceId(selectedDeviceId);
    }
    const diagnostic =
      diagnostics.find((item) => item.device_id === selectedDeviceId) ||
      (selectedDeviceId ? await client.getVPNClientDiagnosticStatus(selectedClusterId, selectedDeviceId) : null);
    setVPNClientDiagnostic(diagnostic);
    setNotice(diagnostic ? "Диагностика VPN-клиента обновлена." : "Диагностика VPN-клиента не найдена.");
  }

  async function sendVPNDiagnosticCommand(command: Record<string, unknown>, label: string) {
    if (!selectedClusterId) {
      setError("Выбери кластер перед отправкой команды.");
      return;
    }
    const deviceId = vpnDiagnosticDeviceId.trim();
    if (!deviceId) {
      setError("Укажи Android device id или выбери найденный клиент.");
      return;
    }
    setLoading(true);
    setError("");
    setNotice("");
    try {
      const queued = await client.enqueueVPNClientDiagnosticCommand(selectedClusterId, deviceId, command);
      setLastVPNDiagnosticCommand(queued);
      setNotice(`${label}: команда поставлена в очередь. Клиент заберет ее через диагностический канал.`);
      window.setTimeout(() => {
        void refreshVPNClientDiagnostic();
      }, 3500);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Команда VPN-клиенту не отправлена.");
    } finally {
      setLoading(false);
    }
  }

  async function handleLogin() {
    setLoading(true);
    setError("");
    setNotice("");
    try {
      const result = await authClient.login({
        email: loginForm.email,
        password: loginForm.password,
        deviceLabel: loginForm.deviceLabel,
        trustDevice: loginForm.trustDevice,
      });
      const nextSession = normalizeAuthResult(result);
      if (!nextSession.userId || !nextSession.authSessionId) {
        throw new Error("Ответ входа не содержит пользователя или сессию.");
      }
      const accessClient = new AdminApiClient({ actorUserId: nextSession.userId });
      let nextMode: ConsoleMode = "admin";
      try {
        await accessClient.listClusterSummaries();
        nextMode = "admin";
      } catch {
        try {
          const [loadedOrganizations, loadedResources] = await Promise.all([accessClient.listOrganizations(), accessClient.listResources()]);
          setOrganizations(loadedOrganizations);
          setResources(loadedResources);
          if (loadedOrganizations[0]?.id) {
            setOrganizationId(loadedOrganizations[0].id);
          }
          const membershipEntries = await Promise.all(
            loadedOrganizations.map(async (org) => [org.id, await accessClient.listOrganizationMemberships(org.id)] as const),
          );
          setMembershipsByOrg(Object.fromEntries(membershipEntries));
          nextMode = "user";
        } catch {
          try {
            await authClient.revokeAuthSession({
              userId: nextSession.userId,
              authSessionId: nextSession.authSessionId,
              reason: "public_ingress_access_denied",
            });
          } catch {
            // Authentication succeeded, but no accessible workspace was found.
          }
          throw new Error(t.accessDenied);
        }
      }
      setRememberSession(loginForm.rememberMe);
      persistSession(nextSession, loginForm.rememberMe);
      setSession(nextSession);
      setActorUserId(nextSession.userId);
      setLoginForm((previous) => ({ ...previous, email: nextSession.email, password: "" }));
      setSessionRefreshedAt(new Date().toISOString());
      setConsoleMode(nextMode);
      setNotice(`${t.signedInAs}: ${nextSession.email}`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Вход не выполнен.");
    } finally {
      setLoading(false);
    }
  }

  async function handleBootstrapOwner() {
    setLoading(true);
    setError("");
    setNotice("");
    try {
      let activationPayload: unknown;
      if (installationStatus?.strict_authority) {
        if (!bootstrapForm.activationPayload.trim() || !bootstrapForm.activationSignature.trim()) {
          throw new Error(t.bootstrapText);
        }
        activationPayload = JSON.parse(bootstrapForm.activationPayload);
      }
      const result = await authClient.bootstrapOwner({
        email: bootstrapForm.email,
        password: bootstrapForm.password,
        activationPayload,
        activationSignature: bootstrapForm.activationSignature,
      });
      setInstallationStatus(result.installation);
      setLoginForm({ ...loginForm, email: bootstrapForm.email, password: bootstrapForm.password });
      setNotice(t.ownerCreated);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Создание владельца не выполнено.");
    } finally {
      setLoading(false);
    }
  }

  async function handleLogout() {
    const previous = session;
    setSession(null);
    setRememberSession(false);
    setSessionRefreshedAt("");
    persistSession(null);
    setConsoleMode(null);
    setActorUserId("");
    setClusters([]);
    setClusterSummaries([]);
    clearClusterScope();
    setAllNodesByCluster({});
    setSelectedClusterId("");
    if (previous?.userId && previous.authSessionId) {
      try {
        await authClient.revokeAuthSession({
          userId: previous.userId,
          authSessionId: previous.authSessionId,
          reason: "platform_owner_console_logout",
        });
      } catch {
        // The local session is already cleared. Backend revoke failure should not trap the operator in the UI.
      }
    }
  }

  async function switchCluster(clusterId: string) {
    setSelectedClusterId(clusterId);
    clearClusterScope();
    setLoading(true);
    setError("");
    setNotice("");
    try {
      await loadClusterScope(clusterId);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Не удалось загрузить кластер.");
    } finally {
      setLoading(false);
    }
  }

  const pendingJoinCount = joinRequests.filter((request) => request.status === "pending").length;
  const healthyNodeCount = nodes.filter((node) => node.health_status === "healthy").length;
  const riskyNodeCount = nodes.filter((node) => node.health_status !== "healthy" || node.membership_status !== "active").length;
  const freshNodeCount = nodes.filter((node) => nodeSignalFreshness(node, (heartbeatsByNode[node.id] || [])[0]).state === "fresh").length;
  const staleSignalNodeCount = nodes.filter((node) => {
    const state = nodeSignalFreshness(node, (heartbeatsByNode[node.id] || [])[0]).state;
    return state === "stale" || state === "no_signal";
  }).length;
  const rescueHoldNodeCount = nodes.filter((node) => nodeUpdaterSummary(nodeUpdateStatusesByNode[node.id] || []).reason === "fabric_executor_upgrade_required").length;
  const activeRoleCount = Object.values(rolesByNode)
    .flat()
    .filter((role) => role.status === "active" && isFabricNodeRole(role.role)).length;
  const platformTestingFlag = testingFlags.find((flag) => flag.scope_type === "platform" && !flag.scope_id) || null;
  const organizationTestingFlag =
    testingFlags.find((flag) => flag.scope_type === "organization" && flag.scope_id === testingOrgId && (!flag.cluster_id || flag.cluster_id === selectedClusterId)) ||
    null;
  const syntheticMeshConfigs = Object.values(syntheticMeshConfigsByNode);
  const syntheticConfigEnabledCount = syntheticMeshConfigs.filter((config) => config.enabled).length;
  const syntheticRouteCount = syntheticMeshConfigs.reduce((sum, config) => sum + config.routes.length, 0);
  const syntheticPeerEndpointCount = syntheticMeshConfigs.reduce((sum, config) => sum + Object.keys(config.peer_endpoints || {}).length, 0);
  const syntheticCandidateCount = syntheticMeshConfigs.reduce((sum, config) => sum + countPeerEndpointCandidates(config), 0);
  const syntheticPeerDirectoryCount = syntheticMeshConfigs.reduce((sum, config) => sum + (config.peer_directory?.length ?? 0), 0);
  const syntheticRecoverySeedCount = syntheticMeshConfigs.reduce((sum, config) => sum + (config.recovery_seeds?.length ?? 0), 0);
  const productionForwardingConfigCount = syntheticMeshConfigs.filter((config) => config.production_forwarding).length;
  const webIngressReceiverCluster = webIngressReceiverClusterSummary(nodes, heartbeatsByNode);
  const routeIntentActive = routeIntents.filter((item) => routeIntentLifecycle(item) === "active");
  const routeIntentExpired = routeIntents.filter((item) => routeIntentLifecycle(item) === "expired");
  const routeIntentDisabled = routeIntents.filter((item) => routeIntentLifecycle(item) === "disabled");
  const fabricRouteFeedbackVisible = fabricRouteFeedback.filter((item) => {
    const expiresAt = Date.parse(item.expires_at || "");
    const retryUntil = Date.parse(item.retry_cooldown_until || "");
    return (Number.isFinite(expiresAt) && expiresAt > Date.now()) || (Number.isFinite(retryUntil) && retryUntil > Date.now());
  });
  const fabricFeedbackFenced = fabricRouteFeedbackVisible.filter((item) => item.feedback_status === "fenced");
  const fabricFeedbackDegraded = fabricRouteFeedbackVisible.filter((item) => item.feedback_status === "degraded");
  const fabricFeedbackHealthy = fabricRouteFeedbackVisible.filter((item) => item.feedback_status === "healthy");
  const fabricFeedbackRecovered = fabricRouteFeedbackVisible.filter((item) => item.recovery_state === "recovered" || item.recovery_hysteresis_active);
  const fabricFeedbackPromoted = fabricRouteFeedbackVisible.filter((item) => item.recovery_promoted);
  const fabricFeedbackDemoted = fabricRouteFeedbackVisible.filter((item) => item.recovery_demoted);
  const fabricFeedbackRetryCooldown = fabricRouteFeedbackVisible.filter((item) => item.feedback_status === "operator_retry_cooldown" || item.retry_cooldown_until);
  const fabricRouteDecisions = syntheticMeshConfigs.flatMap((config) => config.route_path_decisions?.decisions || []);
  const fabricNoAlternateDecisions = fabricRouteDecisions.filter((decision) => decision.decision_source === "service_channel_feedback_no_alternate");
  const fabricReplacementDecisions = fabricRouteDecisions.filter((decision) => decision.decision_source === "service_channel_feedback_replacement");
  const fabricRebuildDecisions = fabricRouteDecisions.filter((decision) => decision.rebuild_status);
  const fabricRebuildAppliedDecisions = fabricRebuildDecisions.filter((decision) => decision.rebuild_status === "applied");
  const fabricRebuildAppliedAttempts = fabricRebuildAttempts.filter((attempt) => attempt.rebuild_status === "applied");
  const fabricRebuildPendingAttempts = fabricRebuildAttempts.filter((attempt) => attempt.rebuild_status && attempt.rebuild_status !== "applied");
  const fabricRebuildGuardAlerts = fabricRebuildAttempts.filter((attempt) => attempt.guard_severity === "bad");
  const fabricRecoveryHysteresisDecisions = fabricRouteDecisions.filter((decision) => (decision.score_reasons || []).includes("service_channel_recovery_hysteresis"));
  const fabricRecoveryPromotedDecisions = fabricRouteDecisions.filter((decision) => (decision.score_reasons || []).includes("service_channel_recovery_promoted"));
  const fabricRecoveryDemotedDecisions = fabricRouteDecisions.filter((decision) => (decision.score_reasons || []).includes("service_channel_recovery_demoted"));
  const bootstrapRequired = installationStatus?.bootstrapped === false;
  const bootstrapBlocked = bootstrapRequired && !installationStatus?.strict_authority && !installationStatus?.insecure_bootstrap_allowed;
  const sessionModeLabel = consoleMode === "admin" ? t.sessionModeAdmin : t.sessionModeUser;

  if (!session) {
    return (
      <main className="loginShell">
        {installationStatus && (
          <section className="loginCard">
            <h1>{installationStatus.bootstrapped ? t.installationLocked : t.bootstrapTitle}</h1>
            <StateLine label="Authority" value={`${installationStatus.authority_mode}/${installationStatus.authority_state}`} />
            <StateLine label="Strict" value={installationStatus.strict_authority ? "enabled" : "standard"} />
            {installationStatus.root_fingerprint && <StateLine label="Root key" value={shortId(installationStatus.root_fingerprint)} />}
          </section>
        )}

        {bootstrapRequired ? (
          <section className="loginCard">
            <h1>{t.bootstrapTitle}</h1>
            <p className="loginHint">{bootstrapBlocked ? t.insecureBootstrapDisabled : t.bootstrapText}</p>
            <label>
              {t.email}
              <input
                value={bootstrapForm.email}
                onChange={(event) => setBootstrapForm({ ...bootstrapForm, email: event.target.value })}
                autoComplete="username"
              />
            </label>
            <label>
              {t.password}
              <input
                value={bootstrapForm.password}
                onChange={(event) => setBootstrapForm({ ...bootstrapForm, password: event.target.value })}
                type="password"
                autoComplete="new-password"
              />
            </label>
            {installationStatus?.strict_authority && (
              <>
                <label>
                  {t.activationPayload}
                  <textarea
                    value={bootstrapForm.activationPayload}
                    onChange={(event) => setBootstrapForm({ ...bootstrapForm, activationPayload: event.target.value })}
                    spellCheck={false}
                  />
                </label>
                <label>
                  {t.activationSignature}
                  <input
                    value={bootstrapForm.activationSignature}
                    onChange={(event) => setBootstrapForm({ ...bootstrapForm, activationSignature: event.target.value })}
                    spellCheck={false}
                  />
                </label>
              </>
            )}

            {error && <div className="errorPanel">{error}</div>}
            {notice && <div className="noticePanel">{notice}</div>}

            <button
              className="primary wide"
              onClick={() => void handleBootstrapOwner()}
              disabled={
                loading ||
                bootstrapBlocked ||
                !bootstrapForm.email ||
                bootstrapForm.password.length < 12 ||
                (installationStatus?.strict_authority && (!bootstrapForm.activationPayload || !bootstrapForm.activationSignature))
              }
            >
              {loading ? t.creatingOwner : t.createOwner}
            </button>
          </section>
        ) : (
          <section className="loginCard">
            <h1>{t.signInTitle}</h1>
            <label>
              {t.email}
              <input
                value={loginForm.email}
                onChange={(event) => setLoginForm({ ...loginForm, email: event.target.value.trim() })}
                autoComplete="username"
                autoCapitalize="none"
                autoCorrect="off"
                spellCheck={false}
              />
            </label>
            <label>
              {t.password}
              <input
                value={loginForm.password}
                onChange={(event) => setLoginForm({ ...loginForm, password: event.target.value })}
                type={loginForm.showPassword ? "text" : "password"}
                autoComplete="current-password"
                autoCapitalize="none"
                autoCorrect="off"
                spellCheck={false}
                onKeyDown={(event) => {
                  if (event.key === "Enter") {
                    void handleLogin();
                  }
                }}
              />
            </label>
            <label className="checkLine">
              <input
                type="checkbox"
                checked={loginForm.showPassword}
                onChange={(event) => setLoginForm({ ...loginForm, showPassword: event.target.checked })}
              />
              Показать пароль
            </label>
            <label className="checkLine">
              <input
                type="checkbox"
                checked={loginForm.trustDevice}
                onChange={(event) => setLoginForm({ ...loginForm, trustDevice: event.target.checked })}
              />
              {t.trustDevice}
            </label>
            <label className="checkLine">
              <input
                type="checkbox"
                checked={loginForm.rememberMe}
                onChange={(event) => setLoginForm({ ...loginForm, rememberMe: event.target.checked })}
              />
              {t.rememberMe}
            </label>

            {error && <div className="errorPanel">{error}</div>}
            {notice && <div className="noticePanel">{notice}</div>}

            <button className="primary wide" onClick={() => void handleLogin()} disabled={loading || !loginForm.email || !loginForm.password}>
              {loading ? t.signingIn : t.signIn}
            </button>
          </section>
        )}
      </main>
    );
  }

  if (session && !consoleMode) {
    return (
      <main className="loginShell">
        <section className="loginCard">
          <p>{loading ? t.lastRefresh : "Восстанавливаем сессию..."}</p>
        </section>
      </main>
    );
  }

  if (consoleMode === "user") {
    const activeOrganization = organizations.find((org) => org.id === organizationId) || organizations[0] || null;
    const visibleResources = activeOrganization ? resources.filter((resource) => resource.organization_id === activeOrganization.id) : resources;
    const activeMembership = activeOrganization
      ? (membershipsByOrg[activeOrganization.id] || []).find((membership) => membership.user_id === session.userId)
      : null;
    const protocolCounts = visibleResources.reduce<Record<string, number>>((acc, resource) => {
      acc[resource.protocol] = (acc[resource.protocol] || 0) + 1;
      return acc;
    }, {});
    return (
      <main className="portalShell">
        <aside className="portalRail">
          <div className="brandMark">RAP</div>
          <p className="sideKicker">Личный кабинет</p>
          <h1>Мой доступ</h1>
          <p className="sideText">Установки, доступные серверы и состояние рабочей области пользователя.</p>
          <StateLine label={t.sessionMode} value={`${sessionModeLabel} • ${sessionRefreshedAt ? formatTime(sessionRefreshedAt) : "н/д"}`} />
          <StateLine label={t.actorUser} value={session.email} />
          <button className="ghost" onClick={() => void handleLogout()} disabled={loading}>
            {t.logout}
          </button>
        </aside>
        <section className="portalWorkspace">
          <header className="portalTop">
            <div>
              <p className="eyebrow">Secure Access Fabric</p>
              <h2>{activeOrganization?.name || "Личный кабинет"}</h2>
              <p className="muted">{session.email}</p>
            </div>
            <label>
              Организация
              <select value={activeOrganization?.id || ""} onChange={(event) => setOrganizationId(event.target.value)}>
                {organizations.map((org) => (
                  <option key={org.id} value={org.id}>
                    {org.name}
                  </option>
                ))}
              </select>
            </label>
            <button className="primary" onClick={() => void refreshUserPortal()} disabled={loading}>
              {loading ? t.refreshing : t.refresh}
            </button>
          </header>

          {error && <div className="errorPanel">{error}</div>}
          {notice && <div className="noticePanel">{notice}</div>}

          <section className="grid three">
            <Metric label="Организации" value={organizations.length} tone="steel" />
            <Metric label="Серверы" value={visibleResources.length} tone="green" />
            <Metric label="Установки" value={2} tone="amber" />
          </section>

          <section className="grid two">
            <article className="card">
              <div className="cardHead">
                <div>
                  <h3>Установки</h3>
                  <p className="muted">
                    {androidClientVersion ? `Актуальная версия Android: ${androidClientVersion}` : "Скачивайте актуальные клиенты только отсюда, чтобы не ловить старую сборку."}
                  </p>
                </div>
                <span className="status active">latest</span>
              </div>
              <div className="portalInstallList">
                <a className="installTile primaryInstall" href={androidVPNDownloadUrl}>
                  <strong>Android VPN</strong>
                  <span>Последняя сборка RAP HOME VPN для телефона</span>
                  <small>{androidClientVersionedPath || portalAndroidArtifactPath}</small>
                </a>
                <a className="installTile" href={`${portalDownloadBaseUrl}/downloads/rap-windows-rdp-client-latest-win-x64.zip`}>
                  <strong>Windows RDP клиент</strong>
                  <span>Клиент удаленного рабочего стола, когда нужен доступ к серверам</span>
                  <small>latest win-x64</small>
                </a>
              </div>
            </article>

            <article className="card">
              <h3>Профиль</h3>
              <StateLine label="Пользователь" value={session.email} />
              <StateLine label="Роль в организации" value={activeMembership?.role_id || "участник"} />
              <StateLine label="Организация" value={activeOrganization?.name || "нет"} />
              <StateLine label="Последнее обновление" value={lastDataRefreshAt ? formatDate(lastDataRefreshAt) : "нет"} />
            </article>

            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>Доступные серверы</h3>
                  <p className="muted">Список ресурсов, которые уже разрешены пользователю через организацию.</p>
                </div>
              </div>
              <DataTable
                columns={["имя", "адрес", "протокол", "секрет", "передача файлов"]}
                rows={visibleResources.map((resource) => [
                  resource.name,
                  resource.address,
                  resource.protocol,
                  resource.has_secret ? "настроен" : "нет",
                  statusLabel(resource.file_transfer_mode || "disabled"),
                ])}
              />
            </article>

            <article className="card">
              <h3>Сервисы</h3>
              <DataTable columns={["тип", "количество"]} rows={Object.entries(protocolCounts).map(([protocol, count]) => [protocol, String(count)])} />
            </article>

            <article className="card">
              <h3>Что здесь будет дальше</h3>
              <div className="portalRoadmap">
                <span>Устройства и доверенные входы</span>
                <span>Активные VPN-сессии</span>
                <span>Обновление профиля VPN без ручных ключей</span>
                <span>Самостоятельная смена пароля</span>
              </div>
            </article>
          </section>
        </section>
      </main>
    );
  }

  return (
    <main className="consoleShell">
      <aside className="sideRail">
        <div className="brandMark">SAF</div>
        <p className="sideKicker">{t.productOwner}</p>
        <h1>{t.controlPlane}</h1>
        <p className="sideText">{t.sideText}</p>
        <nav className="railNav">
          {navGroups.map((group) => (
            <div className="railNavGroup" key={group.label.en}>
              <span className="railNavLabel">{group.label[language]}</span>
              {group.views.map((viewId) => {
                const view = viewsById[viewId];
                return (
                  <button
                    key={view.id}
                    className={activeView === view.id ? "active" : ""}
                    aria-current={activeView === view.id ? "page" : undefined}
                    onClick={() => setActiveView(view.id)}
                  >
                    {view[language]}
                  </button>
                );
              })}
            </div>
          ))}
        </nav>
      </aside>

      <section className="workspace">
        <header className="topBar">
          <div>
            <p className="eyebrow">Secure Access Fabric</p>
            <h2>{selectedCluster ? selectedCluster.name : t.consoleTitle}</h2>
            <p className="muted">{t.boundary}</p>
          </div>
          <div className="clusterPicker">
            <label>
              {t.activeCluster}
              <select value={selectedClusterId} onChange={(event) => void switchCluster(event.target.value)}>
                {clusters.map((cluster) => (
                  <option key={cluster.id} value={cluster.id}>
                    {cluster.name}
                  </option>
                ))}
              </select>
            </label>
            <span>
              {t.slugLabel}: {selectedCluster?.slug || "н/д"}
            </span>
          </div>
          <button className="primary" onClick={() => void refreshAll()} disabled={loading}>
            {loading ? t.refreshing : t.refresh}
          </button>
          <div className="refreshStatus">
            <strong>{t.autoRefresh}</strong>
            <span>{lastDataRefreshAt ? `${t.lastRefresh}: ${formatTime(lastDataRefreshAt)} / ${liveTransport.toUpperCase()}` : liveTransport.toUpperCase()}</span>
          </div>
          <div className="profilePanel">
            <strong>{t.profile}</strong>
            <span>{session.email}</span>
            <span>
              {t.sessionMode}: {sessionModeLabel} | {t.sessionRefreshedAt}: {sessionRefreshedAt ? formatTime(sessionRefreshedAt) : "н/д"}
            </span>
            <label>
              {t.language}
              <select value={language} onChange={(event) => setLanguage(event.target.value as Language)}>
                <option value="ru">Русский</option>
                <option value="en">{language === "ru" ? "Английский" : "English"}</option>
              </select>
            </label>
            <button className="ghost" onClick={() => void handleLogout()} disabled={loading}>
              {t.logout}
            </button>
          </div>
        </header>

        {error && <div className="errorPanel">{error}</div>}
        {notice && <div className="noticePanel">{notice}</div>}
        {selectedCluster && nodes.length === 0 && (
          <div className="noticePanel">
            <strong>{t.emptyLiveTitle}.</strong> {t.emptyLiveText}
          </div>
        )}

        {activeView === "command" && (
          <section className="grid five">
            <Metric label="Кластеры" value={clusters.length} tone="steel" />
            <Metric label="Узлы в области" value={nodes.length} tone="green" />
            <Metric label="Здоровые узлы" value={healthyNodeCount} tone="green" />
            <Metric label="Ожидают подключения" value={pendingJoinCount} tone="amber" />
            <Metric label="Рискованные состояния" value={riskyNodeCount} tone="red" />

            <article className="card span3">
              <h3>Общее состояние кластеров</h3>
              <DataTable
                columns={["кластер", "authority", "ключ", "режим изменений", "узлы", "заявки", "функции", "последний сигнал"]}
                rows={clusterSummaries.map((summary) => [
                  summary.name,
                  summary.authority_state,
                  shortId(summary.cluster_key_fingerprint),
                  summary.mutation_mode,
                  `${summary.healthy_node_count}/${summary.node_count}`,
                  String(summary.pending_join_count),
                  String(summary.active_role_assignment_count),
                  formatDate(summary.last_node_seen_at),
                ])}
              />
            </article>

            <article className="card span2">
              <h3>Authority выбранного кластера</h3>
              {authority ? (
                <div className="stateList">
                  <StateLine label="Authority" value={authority.authority_state} />
                  <StateLine label="Режим изменений" value={authority.mutation_mode} />
                  <StateLine label="Терм" value={String(authority.term)} />
                  <StateLine label="Cluster key" value={shortId(selectedSummary?.cluster_key_fingerprint)} />
                  <StateLine label="Обновлено" value={formatDate(authority.updated_at)} />
                </div>
              ) : (
                <EmptyState title="Нет состояния authority" text="Выберите кластер, чтобы загрузить состояние authority." />
              )}
            </article>

            <article className="card span2">
              <h3>Граница платформы</h3>
              <p className="muted">
                Эта панель предназначена для владельца продукта / владельца платформы. Панели организаций должны использовать безопасные
                проекции и не раскрывать mesh internals, peer cache, route cache, секреты или данные других tenants.
              </p>
            </article>

            <article className="card span3">
              <h3>Текущие сигналы кластера</h3>
              <div className="signalStrip">
                <Signal label="Функции фермы" value={String(activeRoleCount)} />
                <Signal label="Отчеты сервисов" value={String(Object.values(workloadsByNode).filter((items) => items.length > 0).length)} />
                <Signal label="Наблюдения связей" value={String(meshLinks.length)} />
                <Signal label="Synthetic configs" value={`${syntheticConfigEnabledCount}/${nodes.length}`} />
              </div>
            </article>
          </section>
        )}

        {activeView === "clusters" && (
          <section className="grid two">
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>{t.clusterCatalog}</h3>
                  <p className="muted">{t.clusterCatalogText}</p>
                </div>
                <span className="pill">{clusterCountLabel(clusters.length, language)}</span>
              </div>
              <div className="clusterCatalog">
                {clusters.map((cluster) => {
                  const summary = clusterSummaries.find((item) => item.cluster_id === cluster.id);
                  const isSelected = cluster.id === selectedClusterId;
                  return (
                    <article key={cluster.id} className={`clusterCard ${isSelected ? "selected" : ""}`}>
                      <div className="clusterCardMain">
                        <div>
                          <p className="eyebrow">{cluster.region || "регион не задан"}</p>
                          <h4>{cluster.name}</h4>
                          <p className="muted">
                            {t.slugLabel}: <strong>{cluster.slug}</strong>
                          </p>
                        </div>
                        <div className="clusterCardActions">
                          <Status value={cluster.status} />
                          {isSelected ? (
                            <span className="pill good">{t.selected}</span>
                          ) : (
                            <button onClick={() => void switchCluster(cluster.id)}>{t.makeActive}</button>
                          )}
                          <button
                            className="ghost"
                            onClick={() => {
                              void switchCluster(cluster.id);
                              setActiveView("cluster-settings");
                            }}
                          >
                            {t.openSettings}
                          </button>
                        </div>
                      </div>

                      <div className="signalStrip compact">
                        <Signal label="Узлы" value={summary ? `${summary.healthy_node_count}/${summary.node_count}` : "н/д"} />
                        <Signal label="Заявки" value={String(summary?.pending_join_count ?? "н/д")} />
                        <Signal label="Функции" value={String(summary?.active_role_assignment_count ?? "н/д")} />
                        <Signal label="Последний сигнал" value={formatDate(summary?.last_node_seen_at)} />
                      </div>

                      <details>
                        <summary>{t.clusterDetails}</summary>
                        <div className="stateList">
                          <StateLine label="ID" value={cluster.id} />
                          <StateLine label={t.slugLabel} value={cluster.slug} />
                          <StateLine label="Статус" value={statusLabel(cluster.status)} />
                          <StateLine label="Authority" value={summary ? `${summary.authority_state}/${summary.mutation_mode}` : "неизвестно"} />
                          <StateLine label="Создан" value={formatDate(cluster.created_at)} />
                          <StateLine label="Обновлен" value={formatDate(cluster.updated_at || cluster.created_at)} />
                        </div>
                      </details>
                    </article>
                  );
                })}
                {clusters.length === 0 && <EmptyState title="Кластеров нет" text="Создайте первый кластер, затем подключите стартовый node-agent." />}
              </div>
            </article>

            <article className="card">
              <h3>{t.createCluster}</h3>
              <FormGrid>
                <label>
                  {t.slugLabel}
                  <input value={clusterForm.slug} onChange={(event) => setClusterForm({ ...clusterForm, slug: event.target.value })} />
                </label>
                <label>
                  Название
                  <input value={clusterForm.name} onChange={(event) => setClusterForm({ ...clusterForm, name: event.target.value })} />
                </label>
                <label>
                  Регион
                  <input value={clusterForm.region} onChange={(event) => setClusterForm({ ...clusterForm, region: event.target.value })} />
                </label>
              </FormGrid>
              <p className="muted">{t.slugHelp}</p>
              <button
                className="primary"
                disabled={!clusterForm.slug || !clusterForm.name}
                onClick={() =>
                  void runAction(async () => {
                    await client.createCluster({ slug: clusterForm.slug, name: clusterForm.name, region: clusterForm.region || null });
                    setClusterForm({ slug: "", name: "", region: "" });
                  }, "Кластер создан.")
                }
              >
                {t.createCluster}
              </button>
            </article>

            <article className="card">
              <h3>Что такое технический код?</h3>
              <p className="muted">{t.slugHelp}</p>
              <p className="muted">
                Для человека основное поле — название. Для системы и операторов — технический код. Он нужен, чтобы сценарии, логи и будущие
                endpoint-адреса не зависели от переименования кластера.
              </p>
            </article>
          </section>
        )}

        {activeView === "cluster-settings" && (
          <section className="grid two">
            {!selectedCluster && <EmptyState title="Кластер не выбран" text="Выберите активный кластер, чтобы открыть настройки." />}

            {selectedCluster && (
              <>
                <article className="card">
                  <h3>Identity кластера</h3>
                  <p className="muted">Базовые параметры хранятся в PostgreSQL. Slug остается неизменяемым идентификатором для операторов и скриптов.</p>
                  <FormGrid>
                    <label>
                      ID
                      <input value={selectedCluster.id} readOnly />
                    </label>
                    <label>
                      Slug
                      <input value={selectedCluster.slug} readOnly />
                    </label>
                    <label>
                      Название
                      <input
                        value={clusterSettingsForm.name}
                        onChange={(event) => setClusterSettingsForm({ ...clusterSettingsForm, name: event.target.value })}
                      />
                    </label>
                    <label>
                      Статус
                      <select
                        value={clusterSettingsForm.status}
                        onChange={(event) => setClusterSettingsForm({ ...clusterSettingsForm, status: event.target.value })}
                      >
                        <option value="active">active, работает</option>
                        <option value="disabled">disabled, отключен</option>
                      </select>
                    </label>
                    <label>
                      Регион
                      <input
                        value={clusterSettingsForm.region}
                        onChange={(event) => setClusterSettingsForm({ ...clusterSettingsForm, region: event.target.value })}
                        placeholder="например ru-msk-1"
                      />
                    </label>
                    <label>
                      Обновлен
                      <input value={formatDate(selectedCluster.updated_at || selectedCluster.created_at)} readOnly />
                    </label>
                  </FormGrid>
                  <label className="wideLabel">
                    Metadata JSON
                    <textarea
                      value={clusterSettingsForm.metadataJson}
                      onChange={(event) => setClusterSettingsForm({ ...clusterSettingsForm, metadataJson: event.target.value })}
                      rows={8}
                      spellCheck={false}
                    />
                  </label>
                  <button
                    className="primary"
                    disabled={!clusterSettingsForm.name.trim()}
                    onClick={() =>
                      confirmHighRisk("Сохранить базовые настройки кластера") &&
                      void runAction(async () => {
                        const metadata = parseJSONObject(clusterSettingsForm.metadataJson || "{}", "Metadata JSON");
                        await client.updateCluster(selectedCluster.id, {
                          name: clusterSettingsForm.name,
                          status: clusterSettingsForm.status,
                          region: clusterSettingsForm.region || null,
                          metadata,
                        });
                      }, "Настройки кластера сохранены.")
                    }
                  >
                    Сохранить настройки кластера
                  </button>
                </article>

                <article className="card">
                  <h3>Authority и режим изменений</h3>
                  <p className="muted">Эта секция защищает кластер от split-brain: minority/read-only сегменты не должны принимать изменения политик.</p>
                  <div className="stateGrid">
                    <StateLine label="Authority" value={authority?.authority_state || "неизвестно"} />
                    <StateLine label="Mutation mode" value={authority?.mutation_mode || "неизвестно"} />
                    <StateLine label="Term" value={String(authority?.term ?? "н/д")} />
                    <StateLine label="Cluster key" value={shortId(selectedSummary?.cluster_key_fingerprint)} />
                    <StateLine label="Последнее изменение" value={formatDate(authority?.updated_at)} />
                  </div>
                  <FormGrid>
                    <label>
                      Состояние authority
                      <select
                        value={authorityForm.authorityState}
                        onChange={(event) => setAuthorityForm({ ...authorityForm, authorityState: event.target.value })}
                      >
                        <option value="authoritative">authoritative, основной</option>
                        <option value="minority">minority, меньшинство</option>
                        <option value="isolated">isolated, изолирован</option>
                        <option value="recovery">recovery, восстановление</option>
                      </select>
                    </label>
                    <label>
                      Режим изменений
                      <select value={authorityForm.mutationMode} onChange={(event) => setAuthorityForm({ ...authorityForm, mutationMode: event.target.value })}>
                        <option value="normal">normal, обычный</option>
                        <option value="read_only">read_only, только чтение</option>
                        <option value="recovery_override">recovery_override, восстановление</option>
                      </select>
                    </label>
                    <label>
                      Примечание
                      <input value={authorityForm.notes} onChange={(event) => setAuthorityForm({ ...authorityForm, notes: event.target.value })} />
                    </label>
                  </FormGrid>
                  <button
                    disabled={!selectedClusterId}
                    onClick={() =>
                      confirmHighRisk("Изменить authority state кластера") &&
                      void runAction(
                        () =>
                          client.updateClusterAuthority(selectedClusterId, {
                            authorityState: authorityForm.authorityState,
                            mutationMode: authorityForm.mutationMode,
                            notes: authorityForm.notes,
                          }),
                        "Authority кластера обновлен.",
                      )
                    }
                  >
                    Обновить authority
                  </button>
                </article>

                <article className="card">
                  <h3>Safety / quorum</h3>
                  <div className="stateGrid">
                    <StateLine label="Узлы" value={String(selectedSummary?.node_count ?? nodes.length)} />
                    <StateLine label="Healthy" value={String(selectedSummary?.healthy_node_count ?? healthyNodeCount)} />
                    <StateLine label="Pending join" value={String(selectedSummary?.pending_join_count ?? joinRequests.filter((item) => item.status === "pending").length)} />
                    <StateLine label="Последний узел" value={formatDate(selectedSummary?.last_node_seen_at)} />
                  </div>
                  <p className="muted">
                    Минимальный размер, quorum policy и split-brain rules пока не имеют отдельного runtime-переключателя. Сейчас защита выполняется через
                    authority/mutation mode, explicit node approval и аудит.
                  </p>
                </article>

                <article className="card">
                  <h3>Telemetry / testing</h3>
                  <div className="stateGrid">
                    <StateLine label="Telemetry flag" value={platformTestingFlag?.telemetry_enabled ? "включен" : "выключен"} />
                    <StateLine label="Synthetic links" value={platformTestingFlag?.synthetic_links_enabled ? "включены" : "выключены"} />
                    <StateLine label="Хранение истории, часов" value={String(platformTestingFlag?.history_retention_hours ?? "н/д")} />
                  </div>
                  <p className="muted">
                    Это тестовый контур наблюдаемости: heartbeat/telemetry реальные, а связи Fabric сейчас synthetic. Production mesh traffic здесь пока не
                    отображается.
                  </p>
                </article>

                <article className="card">
                  <h3>Storage / updates</h3>
                  <div className="stateGrid">
                    <StateLine label="Update store" value={`${nodesWithRole("update-cache", rolesByNode).length} cache node(s)`} />
                    <StateLine label="Config store" value={`${nodesWithRole("file-storage-cache", rolesByNode).length} cache node(s)`} />
                    <StateLine
                      label="Standard cleanup"
                      value={staleNodeRiskReport?.fabric_standard_cleanup_allowed ? "allowed" : staleNodeRiskReport ? "blocked" : "n/a"}
                    />
                    <StateLine
                      label="Stale nodes"
                      value={
                        staleNodeRiskReport
                          ? `${staleNodeRiskReport.summary.stale_nodes} stale / ${staleNodeRiskReport.summary.blocked_nodes} blockers`
                          : "н/д"
                      }
                    />
                  </div>
                  {staleNodeRiskReport && (
                    <div className="stack compact">
                      <div className="membershipList">
                        <span className={`pill ${staleNodeRiskReport.fabric_standard_cleanup_allowed ? "good" : "bad"}`}>
                          {staleNodeRiskReport.fabric_standard_cleanup_allowed ? "fabric standard cleanup allowed" : "fabric standard cleanup blocked"}
                        </span>
                        <span className="pill">nodes {staleNodeRiskReport.summary.total_nodes}</span>
                        <span className={`pill ${staleNodeRiskReport.summary.stale_nodes > 0 ? "warn" : "good"}`}>
                          stale {staleNodeRiskReport.summary.stale_nodes}
                        </span>
                        <span className={`pill ${staleNodeRiskReport.summary.blocked_nodes > 0 ? "bad" : "good"}`}>
                          blockers {staleNodeRiskReport.summary.blocked_nodes}
                        </span>
                        {staleNodeRiskReport.bridge_hold_required && <span className="pill bad">bridge hold active</span>}
                        {(staleNodeRiskReport.blocked_operations || []).map((operation) => (
                          <span key={operation} className="pill bad">
                            {operation}
                          </span>
                        ))}
                        {(staleNodeRiskReport.summary.artifact_gap_nodes || 0) > 0 && (
                          <span className="pill bad">artifact gap {staleNodeRiskReport.summary.artifact_gap_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.unknown_profile_nodes || 0) > 0 && (
                          <span className="pill warn">profile unknown {staleNodeRiskReport.summary.unknown_profile_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.waiting_update_status_nodes || 0) > 0 && (
                          <span className="pill warn">waiting status {staleNodeRiskReport.summary.waiting_update_status_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.unknown_version_nodes || 0) > 0 && (
                          <span className="pill warn">version unknown {staleNodeRiskReport.summary.unknown_version_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.direct_peer_alert_nodes || 0) > 0 && (
                          <span className="pill bad">direct peer alert {staleNodeRiskReport.summary.direct_peer_alert_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.area_diversity_alert_nodes || 0) > 0 && (
                          <span className="pill warn">area diversity {staleNodeRiskReport.summary.area_diversity_alert_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.independent_ingress_alert_nodes || 0) > 0 && (
                          <span className="pill warn">independent ingress {staleNodeRiskReport.summary.independent_ingress_alert_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.directory_dissemination_alert_nodes || 0) > 0 && (
                          <span className="pill warn">
                            full directory {staleNodeRiskReport.summary.directory_dissemination_alert_nodes}
                          </span>
                        )}
                        {(staleNodeRiskReport.summary.updater_subscription_alert_nodes || 0) > 0 && (
                          <span className="pill bad">
                            updater subscription {staleNodeRiskReport.summary.updater_subscription_alert_nodes}
                          </span>
                        )}
                        {(staleNodeRiskReport.summary.updater_wake_unsupported_nodes || 0) > 0 && (
                          <span className="pill bad">
                            updater wake unsupported {staleNodeRiskReport.summary.updater_wake_unsupported_nodes}
                          </span>
                        )}
                        {(staleNodeRiskReport.summary.updater_runtime_missing_nodes || 0) > 0 && (
                          <span className="pill bad">
                            updater runtime missing {staleNodeRiskReport.summary.updater_runtime_missing_nodes}
                          </span>
                        )}
                        {(staleNodeRiskReport.summary.standard_updater_line_nodes || 0) > 0 && (
                          <span className="pill bad">
                            updater line {staleNodeRiskReport.summary.standard_updater_line_nodes}
                          </span>
                        )}
                        {(staleNodeRiskReport.summary.staged_self_update_pending_nodes || 0) > 0 && (
                          <span className="pill bad">
                            staged self-update {staleNodeRiskReport.summary.staged_self_update_pending_nodes}
                          </span>
                        )}
                        {(staleNodeRiskReport.summary.post_update_heartbeat_gap_nodes || 0) > 0 && (
                          <span className="pill bad">
                            post-update heartbeat gap {staleNodeRiskReport.summary.post_update_heartbeat_gap_nodes}
                          </span>
                        )}
                        {(staleNodeRiskReport.summary.standard_control_dependency_nodes || 0) > 0 && (
                          <span className="pill bad">control dependency {staleNodeRiskReport.summary.standard_control_dependency_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.registry_candidate_only_nodes || 0) > 0 && (
                          <span className="pill warn">registry candidate-only {staleNodeRiskReport.summary.registry_candidate_only_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.standard_recovery_contract_nodes || 0) > 0 && (
                          <span className="pill bad">recovery contract {staleNodeRiskReport.summary.standard_recovery_contract_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.recovery_bridge_required_nodes || 0) > 0 && (
                          <span className="pill bad">recovery bridge {staleNodeRiskReport.summary.recovery_bridge_required_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.recovery_bridge_replay_ready_nodes || 0) > 0 && (
                          <span className="pill warn">bridge replay ready {staleNodeRiskReport.summary.recovery_bridge_replay_ready_nodes}</span>
                        )}
                        {(staleNodeRiskReport.summary.waiting_recovery_heartbeat_nodes || 0) > 0 && (
                          <span className="pill info">waiting heartbeat {staleNodeRiskReport.summary.waiting_recovery_heartbeat_nodes}</span>
                        )}
                      </div>
                      {staleNodeRiskReport.summary.blocked_nodes > 0 ? (
                        <div className="stack compact">
                          {staleNodeRiskReport.bridge_hold_required && (
                            <p className="muted">
                              {(() => {
                                const bridgeHoldNodeCount =
                                  (staleNodeRiskReport.bridge_hold_node_ids || []).length ||
                                  staleNodeRiskReport.summary.recovery_bridge_required_nodes ||
                                  0;
                                const bridgeHoldReasons = staleNodeRiskReport.bridge_hold_reasons || [];
                                return (
                                  <>
                              Recovery gate active: fabric recovery must complete for{" "}
                              {bridgeHoldNodeCount} node(s)
                              {bridgeHoldReasons.length > 0 ? ` until ${bridgeHoldReasons.join(", ")} is cleared.` : "."}
                                  </>
                                );
                              })()}
                            </p>
                          )}
                          {staleNodeRiskReport.nodes
                            .filter((node) => node.blocked)
                            .slice(0, 4)
                            .map((node) => {
                              const bridgeReplayPlan = bridgeReplayPlansByNode[node.node_id];
                              const productSummary = node.products
                                .map((product) => {
                                  const artifact = product.compatible_artifact_found
                                    ? product.matching_release_version || "ok"
                                    : "missing";
                                  return `${product.product}: ${artifact}`;
                                })
                                .join(" | ");
                              return (
                                <div key={node.node_id} className="stateList">
                                  <StateLine label="Blocker" value={`${node.name} (${statusLabel(node.health_status)})`} />
                                  <StateLine label="Area" value={node.area || "unknown"} />
                                  <StateLine label="Last seen" value={formatDate(node.last_seen_at)} />
                                  <StateLine label="Recovery readiness" value={staleNodeRecoveryReadiness(node)} />
                                  <StateLine
                                    label="Direct QUIC peers"
                                    value={
                                      node.direct_peer_alert
                                        ? `${node.direct_peer_ready_count || 0}/${node.direct_peer_target_count || 3} ready, deficit ${node.direct_peer_deficit || 0}`
                                        : `${node.direct_peer_ready_count || 0}/${node.direct_peer_target_count || 3} ready`
                                    }
                                  />
                                  <StateLine
                                    label="Cross-area direct peers"
                                    value={
                                      node.area_diversity_alert
                                        ? `${node.external_area_ready_count || 0}/${node.required_external_area_count || 0} external area(s) ready`
                                        : `${node.external_area_ready_count || 0}/${node.required_external_area_count || 0} external area(s) ready`
                                    }
                                  />
                                  <StateLine
                                    label="Direct-ready areas"
                                    value={(node.direct_ready_areas || []).length > 0 ? (node.direct_ready_areas || []).join(", ") : "none"}
                                  />
                                  <StateLine label="Area diversity" value={node.area_diversity_alert ? "alert" : "clear"} />
                                  <StateLine
                                    label="Independent ingress"
                                    value={
                                      node.independent_ingress_alert
                                        ? `${node.independent_ingress_count || 0}/${node.required_independent_ingress_count || 0} ready (alert)`
                                        : `${node.independent_ingress_count || 0}/${node.required_independent_ingress_count || 0} ready`
                                    }
                                  />
                                  <StateLine
                                    label="Full node directory"
                                    value={
                                      node.full_directory_expected
                                        ? `${node.known_peer_directory_count || 0}/${node.expected_directory_count || 0} peers known${
                                            node.directory_dissemination_alert ? " (alert)" : ""
                                          }`
                                        : "not required"
                                    }
                                  />
                                  <StateLine
                                    label="Updater subscription"
                                    value={node.updater_subscription_alert ? "alert: heartbeat outruns updater status" : "clear"}
                                  />
                                    <StateLine
                                      label="Local updater wake"
                                      value={node.updater_wake_unsupported ? "unsupported on current node-agent" : "supported or not required"}
                                    />
                                    <StateLine
                                      label="Updater runtime"
                                      value={node.updater_runtime_missing ? "missing in heartbeat/runtime telemetry" : "present or not required"}
                                    />
                                    <StateLine
                                      label="Updater line"
                                      value={node.standard_updater_line ? "standard line: heartbeat alive but updater path is still pre-wake/runtime" : "current or not required"}
                                    />
                                  <StateLine
                                    label="Staged self-update"
                                    value={node.staged_self_update_pending ? "pending: staged replacement still waiting for next updater cycle" : "clear"}
                                  />
                                  <StateLine
                                    label="Post-update heartbeat"
                                    value={node.post_update_heartbeat_gap ? "gap detected after reported update success" : "clear"}
                                  />
                                  <StateLine label="Connectivity alert" value={node.direct_peer_alert ? "active" : "clear"} />
                                  <StateLine
                                    label="standard control dependency"
                                    value={node.standard_control_dependency ? node.standard_control_url || "active" : "clear"}
                                  />
                                  <StateLine
                                    label="Registry runtime"
                                    value={`${node.registry_runtime_status || "unknown"} / services ${node.resolved_service_count || 0}`}
                                  />
                                  <StateLine label="Recovery gate" value={node.recovery_bridge_required ? "required" : "not required"} />
                                  <StateLine label="Recovery replay" value={node.recovery_bridge_replay_ready ? "ready" : "not ready"} />
                                  <StateLine
                                    label="Recovery hold"
                                    value={node.recovery_bridge_required ? "active: fabric recovery must complete" : "not active"}
                                  />
                                  <StateLine
                                    label="Recovery actions"
                                    value={(node.recovery_bridge_actions || []).length > 0 ? (node.recovery_bridge_actions || []).join(", ") : "none"}
                                  />
                                  {bridgeReplayPlan && bridgeReplayPlan.products && bridgeReplayPlan.products.length > 0 && (
                                    <>
                                      <StateLine
                                        label="Replay plan"
                                        value={`${bridgeReplayPlan.products.length} product(s), ${bridgeReplayPlan.bridge_hold_required ? "hold active" : "hold cleared"}`}
                                      />
                                      {bridgeReplayPlan.products.map((productPlan) => (
                                        <StateLine
                                          key={`${node.node_id}-${productPlan.product}`}
                                          label={`Replay ${productPlan.product}`}
                                          value={`${productPlan.update_plan.action} -> ${productPlan.update_plan.target_version || "none"} / ${productPlan.recovery_bridge_mode || "default"} / ${productPlan.last_status_reason || "no reason"}`}
                                        />
                                      ))}
                                      <div className="actions">
                                        <button
                                          className="ghost"
                                          onClick={() => {
                                            void copyTextToClipboard(JSON.stringify(bridgeReplayPlan, null, 2));
                                            setNotice(`Bridge replay plan copied: ${node.name}`);
                                          }}
                                        >
                                          Copy replay plan
                                        </button>
                                        <button
                                          className="ghost"
                                          onClick={() => {
                                            const artifactRefs = bridgeReplayPlan.products
                                              ?.map((productPlan) => productPlan.update_plan.artifact?.url || "")
                                              .filter((value) => value.length > 0) || [];
                                            void copyTextToClipboard(artifactRefs.join("\n"));
                                            setNotice(
                                              artifactRefs.length > 0
                                                ? `Replay artifact reference copied: ${node.name}`
                                                : `Replay artifact reference is not available yet: ${node.name}`,
                                            );
                                          }}
                                        >
                                          Copy artifact reference
                                        </button>
                                        <button
                                          className="ghost"
                                          onClick={() => {
                                            const replaySummary = (bridgeReplayPlan.products || [])
                                              .map((productPlan) => {
                                                const plan = productPlan.update_plan;
                                                return [
                                                  `product=${productPlan.product}`,
                                                  `action=${plan.action}`,
                                                  `target=${plan.target_version || "none"}`,
                                                  `mode=${productPlan.recovery_bridge_mode || "default"}`,
                                                  `reason=${productPlan.last_status_reason || plan.reason || "unknown"}`,
                                                  `artifact=${plan.artifact?.url || "n/a"}`,
                                                ].join(" | ");
                                              })
                                              .join("\n");
                                            void copyTextToClipboard(replaySummary || `node=${node.name} | no replay products`);
                                            setNotice(`Bridge replay summary copied: ${node.name}`);
                                          }}
                                        >
                                          Copy replay summary
                                        </button>
                                      </div>
                                      <RawJSON title={`Raw bridge replay plan: ${node.name}`} value={bridgeReplayPlan} />
                                    </>
                                  )}
                                  <StateLine label="Risks" value={node.risks.join(", ") || "none"} />
                                  <StateLine label="Recovery artifacts" value={productSummary || "н/д"} />
                                  <StateLine label="Действие" value={staleNodeRecoveryRecommendation(node)} />
                                  <div className="actions">
                                    <button className="ghost" onClick={() => focusBlockerNode(node.node_id, "details")}>
                                      Последние статусы
                                    </button>
                                    <button className="ghost" onClick={() => focusBlockerNode(node.node_id, "manage")}>
                                      Policy / listener
                                    </button>
                                    <button className="ghost" onClick={() => focusNodeAuditTrail(node.node_id)}>
                                      Показать update trail
                                    </button>
                                  </div>
                                </div>
                              );
                            })}
                        </div>
                      ) : (
                        <p className="muted">Сейчас узлов-блокеров нет: rollout можно продолжать после отдельного решения оператора.</p>
                      )}
                      {standardCleanupBlockedAuditEvents.length > 0 && (
                        <div className="stack compact">
                          <p className="muted">Последние заблокированные попытки rollout</p>
                          {standardCleanupBlockedAuditEvents.map((event) => {
                            const payload = objectField(event.payload) || {};
                            const blockedOperation = stringField(payload, "blocked_operation", "");
                            const staleNodes = numberField(payload, "stale_nodes");
                            const blockedNodes = numberField(payload, "blocked_nodes");
                            const target = `${statusLabel(event.target_type)}${event.target_id ? `:${shortId(event.target_id)}` : ""}`;
                            const counts = [
                              Number.isFinite(staleNodes) ? `stale ${staleNodes}` : "",
                              Number.isFinite(blockedNodes) ? `blockers ${blockedNodes}` : "",
                            ]
                              .filter(Boolean)
                              .join(" / ");
                            return (
                              <div key={event.id} className="stateList">
                                <StateLine label="Когда" value={formatDate(event.created_at)} />
                                <StateLine label="Операция" value={blockedOperation || event.event_type} />
                                <StateLine label="Цель" value={target} />
                                <StateLine label="Причина" value={counts || "guard active"} />
                              </div>
                            );
                          })}
                        </div>
                      )}
                      <div className="stack compact">
                        <p className="muted">Operator smoke проверяет, что breaking release блокируется, пока stale recovery-risk узлы ещё есть.</p>
                        <div className="membershipList">
                          <span className="pill">smoke</span>
                          {standardGuardSmokeResult ? (
                            standardGuardSmokeResult.includes("unexpectedly succeeded") ? (
                              <span className="pill bad">unexpected success</span>
                            ) : (
                              <span className="pill good">
                                expected blocked 409{standardGuardSmokeCheckedAt ? ` · ${formatDateAgo(standardGuardSmokeCheckedAt)}` : ""}
                              </span>
                            )
                          ) : (
                            <span className="pill info">not checked</span>
                          )}
                        </div>
                        <div className="actions">
                          <button
                            className="ghost"
                            disabled={!selectedClusterId || staleNodeRiskReport.summary.blocked_nodes < 1 || loading}
                            onClick={() =>
                              confirmHighRisk("Проверить standard-cleanup guard через blocked release smoke") &&
                              void runFabricStandardCleanupGuardSmoke()
                            }
                          >
                            Проверить blocked 409
                          </button>
                        </div>
                        {standardGuardSmokeResult && (
                          <div className={`noticePanel ${standardGuardSmokeResult.includes("unexpectedly succeeded") ? "badPanel" : "warnPanel"}`}>
                            <strong>Guard smoke</strong>
                            <div>{standardGuardSmokeResult}</div>
                            {standardGuardSmokeCheckedAt && <div className="muted">Проверено: {formatDate(standardGuardSmokeCheckedAt)}</div>}
                          </div>
                        )}
                      </div>
                    </div>
                  )}
                </article>

                <article className="card">
                  <h3>Control/API access</h3>
                  <div className="stateGrid">
                    <StateLine label="Entry nodes" value={`${nodesWithRole("entry-node", rolesByNode).length} узл.`} />
                    <StateLine label="Relay nodes" value={`${nodesWithRole("relay-node", rolesByNode).length} узл.`} />
                    <StateLine label="Core mesh" value={`${nodesWithRole("core-mesh", rolesByNode).length} узл.`} />
                  </div>
                  <p className="muted">
                    Это сервисный вход в панель управления, а не transport fabric. Межузловая ферма остается QUIC/UDP-only; HTTP здесь только внешний
                    сервисный интерфейс панели.
                  </p>
                </article>
              </>
            )}
          </section>
        )}

        {activeView === "nodes" && (
          <section className="grid two">
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>{t.nodeManagement}</h3>
                  <p className="muted">
                    Единый краткий список узлов. По умолчанию показан активный кластер; включите общий режим, чтобы увидеть весь инвентарь платформы.
                  </p>
                </div>
                <div className="actions">
                  <label className="checkLine">
                    <input
                      type="checkbox"
                      checked={nodeViewScope === "all"}
                      onChange={(event) => setNodeViewScope(event.target.checked ? "all" : "cluster")}
                    />
                    {t.showAllPlatformNodes}
                  </label>
                  <button
                    className="ghost"
                    onClick={() => {
                      setNodeViewScope("all");
                      setAllNodeSearch("");
                    }}
                  >
                    {t.showAllPlatformNodes}
                  </button>
                </div>
              </div>
              <div className="signalStrip compact">
                <Signal label="Узлы активного кластера" value={String(nodes.length)} />
                <Signal label="Свежая связь" value={`${freshNodeCount}/${nodes.length}`} tone={staleSignalNodeCount > 0 ? "amber" : "green"} />
                <Signal label="Rescue hold" value={String(rescueHoldNodeCount)} tone={rescueHoldNodeCount > 0 ? "amber" : "green"} />
                <Signal label="Функции узлов" value={String(activeRoleCount)} />
              </div>
              <p className="muted">{t.addNodeText}</p>
            </article>

            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>{t.nodeBriefList}</h3>
                  <p className="muted">{t.nodeBriefListHelp}</p>
                </div>
                <span className="pill">{visibleNodeInventory.length}</span>
              </div>
              <FormGrid>
                <label>
                  {t.nodeSearch}
                  <input value={allNodeSearch} onChange={(event) => setAllNodeSearch(event.target.value)} placeholder={t.nodeSearchPlaceholder} />
                </label>
                <label>
                  {t.nodeGroupFilter}
                  <select value={nodeGroupFilterId} onChange={(event) => setNodeGroupFilterId(event.target.value)}>
                    <option value="">{t.allNodeGroups}</option>
                    {nodeGroups.map((group) => (
                      <option key={group.id} value={group.id}>
                        {groupPathLabel(group, nodeGroups)}
                      </option>
                    ))}
                  </select>
                </label>
              </FormGrid>
              <p className="muted">{t.nodeGroupInventoryText}</p>
              <h4>{t.nodeGroupCreatePanel}</h4>
              <FormGrid>
                <label>
                  {t.nodeGroupName}
                  <input value={nodeGroupForm.name} onChange={(event) => setNodeGroupForm({ ...nodeGroupForm, name: event.target.value })} />
                </label>
                <label>
                  {t.parentNodeGroup}
                  <select value={nodeGroupForm.parentGroupId} onChange={(event) => setNodeGroupForm({ ...nodeGroupForm, parentGroupId: event.target.value })}>
                    <option value="">{t.rootNodeGroup}</option>
                    {nodeGroups.map((group) => (
                      <option key={group.id} value={group.id}>
                        {groupPathLabel(group, nodeGroups)}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  {t.createNodeGroup}
                  <button
                    className="primary"
                    disabled={!nodeGroupForm.name.trim()}
                    onClick={() =>
                      void runAction(
                        async () => {
                          await client.createNodeGroup(selectedClusterId, {
                            name: nodeGroupForm.name,
                            parentGroupId: nodeGroupForm.parentGroupId || null,
                          });
                          setNodeGroupForm({ name: "", parentGroupId: "" });
                        },
                        t.nodeGroupCreated,
                      )
                    }
                  >
                    {t.createNodeGroup}
                  </button>
                </label>
              </FormGrid>
              <div className="nodeList">
                {visibleNodeTreeRows.map((row) => {
                  if (row.kind === "group") {
                    const isCollapsed = collapsedNodeGroupKeys.includes(row.key);
                    return (
                      <div className="nodeListGroup" key={row.key} style={{ paddingLeft: `${row.depth * 18}px` }}>
                        <div className="nodeListMain">
                          <strong>{row.label}</strong>
                          {row.groupId && <span>{groupPathLabelById(row.groupId, nodeGroups)}</span>}
                        </div>
                        <div className="actions">
                          <span className="pill">{row.count}</span>
                          <button className="ghost" onClick={() => setCollapsedNodeGroupKeys(toggleArrayValue(collapsedNodeGroupKeys, row.key))}>
                            {isCollapsed ? t.expandGroup : t.collapseGroup}
                          </button>
                          {row.groupId && (
                            <button className="ghost" onClick={() => setNodeGroupForm({ name: "", parentGroupId: row.groupId || "" })}>
                              {t.createSubgroup}
                            </button>
                          )}
                        </div>
                      </div>
                    );
                  }
                  const entry = row.entry;
                  const activeMembership = entry.memberships.find((membership) => membership.cluster.id === selectedClusterId);
                  const displayNode = activeMembership?.node || entry.node;
                  const latestHeartbeat = (heartbeatsByNode[displayNode.id] || [])[0];
                  const runtime = nodeRuntimeConnectivity(displayNode, heartbeatsByNode[displayNode.id] || [], meshLinks);
                  const freshness = nodeSignalFreshness(displayNode, latestHeartbeat);
                  const update = nodeUpdateSummary(displayNode, nodeUpdatePlansByNode[displayNode.id], releaseVersions);
                  const updater = nodeUpdaterSummary(nodeUpdateStatusesByNode[displayNode.id] || []);
                  const activeRoles = activeMembership ? activeFabricNodeRoleAssignments(rolesByNode[displayNode.id] || []) : [];
                  const isActiveMember = activeMembership?.node.membership_status === "active";
                  const isRevokedMember = activeMembership?.node.membership_status === "revoked";
                  return (
                    <div className="nodeListRow" key={row.key} style={{ marginLeft: `${row.depth * 18}px` }}>
                      <div className="nodeListMain">
                        <strong>{displayNode.name}</strong>
                        <span>{displayNode.node_key}</span>
                        <small className="muted">{stringField((heartbeatsByNode[displayNode.id] || [])[0]?.metadata?.mesh_endpoint_report as Record<string, unknown> | undefined, "region", "area н/д")}</small>
                        <small className="muted">{runtime.address}</small>
                      </div>
                      <div className="nodeSignalCell">
                        <span className={`pill ${nodeFreshnessTone(freshness)}`}>{nodeFreshnessLabel(freshness)}</span>
                        <small>{statusLabel(displayNode.health_status)}</small>
                      </div>
                      <RuntimeBadges runtime={runtime} />
                      <div className="nodeEndpointCell">
                        <strong>{displayNode.reported_version || "версия неизвестна"}</strong>
                        <small>{update.targetLabel}</small>
                      </div>
                      <Status value={update.status} />
                      <div className="nodeEndpointCell">
                        <strong className={`pill ${updater.tone}`}>{updater.label}</strong>
                        <small>{updater.detail}</small>
                      </div>
                      <div className="nodeEndpointCell">
                        <strong>{activeRoles.length ? `${activeRoles.length} функции` : "минимальный узел"}</strong>
                        <small>{nodeFabricRoleSummary(activeRoles)}</small>
                      </div>
                      {activeMembership ? <Status value={activeMembership.node.membership_status} /> : <span className="muted">{t.notMemberOfActiveCluster}</span>}
                      <div className="actions">
                        <button
                          onClick={() => {
                            setNodeInfoDialog(entry);
                            setNodeInfoMode("details");
                          }}
                        >
                          {t.nodeDetails}
                        </button>
                        {isActiveMember ? (
                          <>
                            <button
                              className="primary"
                              onClick={() => {
                                setNodeInfoDialog(entry);
                                setNodeInfoMode("manage");
                              }}
                            >
                              {t.manageNode}
                            </button>
                            <button
                              className="danger"
                              onClick={() =>
                                confirmHighRisk(`Удалить узел ${displayNode.name} из кластера`) &&
                                void runAction(
                                  () => client.deleteClusterNode(selectedClusterId, displayNode.id, "Удалено из списка узлов панели владельца платформы."),
                                  "Узел удален из кластера.",
                                )
                              }
                            >
                              Удалить
                            </button>
                          </>
                        ) : isRevokedMember ? (
                          <span className="muted">{t.revokedMembership}</span>
                        ) : (
                          <button
                            className="primary"
                            onClick={() => {
                              setAttachNodeDialog(entry);
                              setAttachNodeRoles([]);
                            }}
                          >
                            {t.connectExistingNode}
                          </button>
                        )}
                      </div>
                    </div>
                  );
                })}
                {visibleNodeTreeRows.length === 0 && <EmptyState title={t.noNodesTitle} text={t.noNodesByFilter} />}
              </div>
            </article>

            {attachNodeDialog && (
              <div className="modalBackdrop" role="presentation">
                <div className="modalCard" role="dialog" aria-modal="true" aria-labelledby="attach-node-title">
                  <div className="cardHead">
                    <div>
                      <h3 id="attach-node-title">{t.connectExistingNodeTitle}</h3>
                      <p className="muted">{t.connectExistingNodeText}</p>
                    </div>
                    <button className="ghost" onClick={() => setAttachNodeDialog(null)}>
                      {t.cancel}
                    </button>
                  </div>
                  <div className="stateList">
                    <StateLine label="Узел" value={attachNodeDialog.node.name} />
                    <StateLine label="Node key" value={attachNodeDialog.node.node_key} />
                    <StateLine label={t.activeCluster} value={selectedCluster?.name || selectedClusterId} />
                  </div>
                  <div className="checkGrid">
                    {roleOptions.map((role) => (
                      <label className="checkLine" key={role}>
                        <input type="checkbox" checked={attachNodeRoles.includes(role)} onChange={() => setAttachNodeRoles(toggleArrayValue(attachNodeRoles, role))} />
                        {roleDisplayLabel(role)}
                      </label>
                    ))}
                  </div>
                  <div className="actions">
                    <button
                      className="primary"
                      onClick={() =>
                        void runAction(
                          async () => {
                            await client.attachExistingNode(selectedClusterId, attachNodeDialog.node.id, attachNodeRoles);
                            setAttachNodeDialog(null);
                            setAttachNodeRoles([]);
                            setNodeViewScope("cluster");
                          },
                          "Узел подключен к активному кластеру.",
                        )
                      }
                    >
                      {t.connectWithRoles}
                    </button>
                    <button onClick={() => setAttachNodeDialog(null)}>{t.cancel}</button>
                  </div>
                </div>
              </div>
            )}

            {nodeInfoDialog &&
              (() => {
                const activeMembership = nodeInfoDialog.memberships.find((membership) => membership.cluster.id === selectedClusterId);
                const node = activeMembership?.node || nodeInfoDialog.node;
                const latestHeartbeat = activeMembership ? (heartbeatsByNode[node.id] || [])[0] : undefined;
                const activeRoles = activeMembership ? activeFabricNodeRoleAssignments(rolesByNode[node.id] || []) : [];
                const desiredWorkloads = activeMembership ? desiredWorkloadsByNode[node.id] || [] : [];
                const observedWorkloads = activeMembership ? workloadsByNode[node.id] || [] : [];
                return (
                  <div className="modalBackdrop" role="presentation">
                    <div className="modalCard wide" role="dialog" aria-modal="true" aria-labelledby="node-info-title">
                      <div className="cardHead">
                        <div>
                          <h3 id="node-info-title">
                            {nodeInfoMode === "manage" ? t.manageNode : t.nodeDetails}: {node.name}
                          </h3>
                          <p className="muted">{node.node_key}</p>
                        </div>
                        <button
                          className="ghost"
                          onClick={() => {
                            setNodeInfoDialog(null);
                            setNodeInfoMode("details");
                          }}
                        >
                          {t.close}
                        </button>
                      </div>

                      <section className="nodePanel">
                        <h4>{t.nodeIdentity}</h4>
                        <div className="stateList">
                          <StateLine label="Node ID" value={shortId(node.id)} />
                          <StateLine label="Ключ узла" value={node.node_key} />
                          <StateLine
                            label="Area/site"
                            value={stringField(latestHeartbeat?.metadata?.mesh_endpoint_report as Record<string, unknown> | undefined, "region", "н/д")}
                          />
                          <StateLine label="Тип владения" value={statusLabel(node.ownership_type)} />
                          <StateLine label="Owner org" value={shortId(node.owner_organization_id)} />
                          <StateLine label="Регистрация" value={statusLabel(node.registration_status)} />
                          <StateLine label="Здоровье" value={statusLabel(node.health_status)} />
                          <StateLine label="Версия" value={node.reported_version || "неизвестно"} />
                          <StateLine label="Последний сигнал" value={formatDate(node.last_seen_at)} />
                        </div>
                      </section>

                      <section className="nodePanel">
                        <h4>{t.clusterMemberships}</h4>
                        <div className="membershipList">
                          {nodeInfoDialog.memberships.map((membership) => (
                            <span key={membership.cluster.id} className={membership.cluster.id === selectedClusterId ? "pill good" : "pill"}>
                              {membership.cluster.name}: {statusLabel(membership.node.membership_status)}
                            </span>
                          ))}
                        </div>
                      </section>

                      {activeMembership ? (
                        <>
                          <section className="nodePanel">
                            <h4>{t.activeClusterScope}</h4>
                            <div className="stateList">
                              <StateLine label="Участие" value={statusLabel(node.membership_status)} />
                              <StateLine label="Сегмент" value={statusLabel(node.partition_state)} />
                              <StateLine label="Группа" value={node.node_group_name || t.ungroupedNodes} />
                    <StateLine label="Функций" value={String(activeRoles.length)} />
                              <StateLine label="Desired-сервисов" value={String(desiredWorkloads.length)} />
                              <StateLine label="Observed-сервисов" value={String(observedWorkloads.length)} />
                            </div>
                          </section>

                          {nodeInfoMode === "details" && (
                            <NodeDetailsDashboard
                              node={node}
                              memberships={nodeInfoDialog.memberships}
                              activeRoles={activeRoles}
                              desiredWorkloads={desiredWorkloads}
                              observedWorkloads={observedWorkloads}
                              heartbeats={heartbeatsByNode[node.id] || []}
                              telemetry={telemetryByNode[node.id] || []}
                              updatePlan={nodeUpdatePlansByNode[node.id]}
                              updateStatuses={nodeUpdateStatusesByNode[node.id] || []}
                              meshLinks={meshLinks.filter((link) => link.source_node_id === node.id || link.target_node_id === node.id)}
                              syntheticConfig={syntheticMeshConfigsByNode[node.id]}
                              allNodes={nodes}
                              onSetUpdatePolicy={(targetNode, product, targetVersion) =>
                                void runAction(async () => {
                                  await client.upsertNodeUpdatePolicy(selectedClusterId, targetNode.id, {
                                    product,
                                    channel: "dev",
                                    targetVersion,
                                    strategy: targetVersion ? "rolling" : "rolling",
                                    enabled: true,
                                    rollbackAllowed: true,
                                    healthWindowSeconds: 180,
                                  });
                                }, targetVersion ? `${product} поставлен в target ${targetVersion}.` : `${product} будет следовать latest dev.`)
                              }
                              labels={t}
                            />
                          )}

                          {nodeInfoMode === "manage" && (
                          <section className="nodePanel">
                            <h4>{t.nodeFunctions}</h4>
                            <p className="muted">{t.nodeFunctionsText}</p>
                            <div className="functionList">
                              {roleOptions.map((role) => {
                                const activeRole = activeRoles.find((assignment) => assignment.role === role);
                                const desired = desiredWorkloads.find((workload) => workload.service_type === role);
                                const observed = observedWorkloads.find((workload) => workload.service_type === role);
                                const capabilityTone = capabilityPillTone(role, latestHeartbeat);
                                const desiredState = desired?.desired_state || "not_configured";
                                const observedState = observed?.reported_state || "missing";
                                const enabled = Boolean(activeRole) && desiredState === "enabled";
                                return (
                                  <div className="functionRow" key={role}>
                                    <div className="nodeListMain">
                                      <strong>{roleDisplayLabel(role)}</strong>
                                      <span>{capabilityOptionLabel(role, latestHeartbeat, language)}</span>
                                    </div>
                                    <FunctionState label={t.rolePermission} value={activeRole ? t.permissionGranted : t.permissionDenied} tone={activeRole ? "info" : ""} />
                                    <FunctionState
                                      label={t.desiredRuntime}
                                      value={`${statusLabel(desiredState)} / ${statusLabel(observedState)}`}
                                      tone={desiredState === "enabled" && observedState === "running" ? "good" : observedState === "missing" ? "warn" : ""}
                                    />
                                    <span className={`pill ${capabilityTone}`}>{capabilityLabel(role, latestHeartbeat, t)}</span>
                                    <div className="actions">
                                      {enabled ? (
                                        <button
                                          onClick={() =>
                                            void runAction(async () => {
                                              await client.setDesiredWorkload(selectedClusterId, node.id, role, {
                                                desiredState: "disabled",
                                                runtimeMode: desired?.runtime_mode || "container",
                                                config: desired?.config || {},
                                                environment: desired?.environment || {},
                                              });
                                              if (activeRole) {
                                                await client.setRoleStatus(selectedClusterId, node.id, role, "disabled", activeRole.organization_id || undefined);
                                              }
                                            }, `${role}: функция выключена.`)
                                          }
                                        >
                                          {t.disableFunction}
                                        </button>
                                      ) : (
                                        <button
                                          className="primary"
                                          onClick={() =>
                                            void runAction(async () => {
                                              if (!activeRole) {
                                                await client.setRoleStatus(selectedClusterId, node.id, role, "active", undefined);
                                              }
                                              await client.setDesiredWorkload(selectedClusterId, node.id, role, {
                                                desiredState: "enabled",
                                                runtimeMode: "container",
                                                config: {},
                                                environment: {},
                                              });
                                            }, `${role}: функция включена.`)
                                          }
                                        >
                                          {t.enableFunction}
                                        </button>
                                      )}
                                    </div>
                                  </div>
                                );
                              })}
                            </div>
                            {(() => {
                              const listenerDesired = desiredWorkloads.find((workload) => workload.service_type === "fabric-listener");
                              const listenerConfig = (listenerDesired?.config || {}) as Record<string, unknown>;
                              const draft =
                                fabricListenerDrafts[node.id] || {
                                  listenAddr: String(listenerConfig.listen_addr || ""),
                                  mode: String(listenerConfig.listen_port_mode || "auto"),
                                  autoRange: `${Number(listenerConfig.auto_port_start || 19131)}-${Number(listenerConfig.auto_port_end || 19231)}`,
                                  advertiseEndpoint: String(listenerConfig.advertise_endpoint || ""),
                                  endpointCandidates: fabricListenerEndpointCandidatesToText(listenerConfig),
                                  advertiseTransport: String(listenerConfig.advertise_transport || "direct_quic"),
                                  connectivity: String(listenerConfig.connectivity_mode || "private_lan"),
                                  nat: String(listenerConfig.nat_type || "none"),
                                  region: String(listenerConfig.region || ""),
                                };
                              const setDraft = (patch: Partial<typeof draft>) => setFabricListenerDrafts({ ...fabricListenerDrafts, [node.id]: { ...draft, ...patch } });
                              return (
                                <section className="nodePanel nestedPanel">
                                  <h4>Fabric listener</h4>
                                  <FormGrid>
                                    <label>
                                      Listen addr
                                      <input value={draft.listenAddr} onChange={(event) => setDraft({ listenAddr: event.target.value })} placeholder="0.0.0.0:19131 или :19131" />
                                    </label>
                                    <label>
                                      Port mode
                                      <select value={draft.mode} onChange={(event) => setDraft({ mode: event.target.value })}>
                                        <option value="auto">auto</option>
                                        <option value="manual">manual</option>
                                        <option value="disabled">disabled</option>
                                      </select>
                                    </label>
                                    <label>
                                      Auto ports
                                      <input value={draft.autoRange} onChange={(event) => setDraft({ autoRange: event.target.value })} placeholder="19131-19231" />
                                    </label>
                                    <label>
                                      Advertise endpoint
                                      <input
                                        value={draft.advertiseEndpoint}
                                        onChange={(event) => setDraft({ advertiseEndpoint: event.target.value })}
                                        placeholder="quic://192.168.200.85:18080"
                                      />
                                    </label>
                                    <label className="wideLabel">
                                      Endpoint candidates
                                      <textarea
                                        value={draft.endpointCandidates}
                                        onChange={(event) => setDraft({ endpointCandidates: event.target.value })}
                                        rows={5}
                                        placeholder={
                                          "quic://192.168.200.85:18080 reachability=private connectivity=private_lan interface=lan\n" +
                                          "quic://94.141.118.222:19199 reachability=public connectivity=direct provider=isp1 maps_to=192.168.200.85:18080"
                                        }
                                      />
                                      <small>
                                        Одна строка = один адрес узла. Можно указать provider, interface, maps_to, priority, reachability, connectivity, nat.
                                      </small>
                                    </label>
                                    <label>
                                      Advertise transport
                                      <select value={draft.advertiseTransport} onChange={(event) => setDraft({ advertiseTransport: event.target.value })}>
                                        <option value="direct_quic">direct_quic</option>
                                        <option value="relay_quic">relay_quic</option>
                                        <option value="outbound_reverse">outbound_reverse</option>
                                      </select>
                                    </label>
                                    <label>
                                      Connectivity
                                      <select value={draft.connectivity} onChange={(event) => setDraft({ connectivity: event.target.value })}>
                                        <option value="private_lan">private_lan</option>
                                        <option value="direct">direct</option>
                                        <option value="outbound_only">outbound_only</option>
                                        <option value="relay_required">relay_required</option>
                                      </select>
                                    </label>
                                    <label>
                                      NAT
                                      <select value={draft.nat} onChange={(event) => setDraft({ nat: event.target.value })}>
                                        <option value="none">none</option>
                                        <option value="unknown">unknown</option>
                                        <option value="port_restricted">port_restricted</option>
                                        <option value="symmetric">symmetric</option>
                                      </select>
                                    </label>
                                    <label>
                                      Region/site
                                      <input value={draft.region} onChange={(event) => setDraft({ region: event.target.value })} placeholder="dc1, office, docker-test" />
                                    </label>
                                  </FormGrid>
                                  <div className="actions">
                                    <button
                                      className="primary"
                                      onClick={() =>
                                        void runAction(async () => {
                                          const [startRaw, endRaw] = draft.autoRange.split("-").map((value) => Number(value.trim()));
                                          const start = Number.isFinite(startRaw) ? startRaw : 19131;
                                          const end = Number.isFinite(endRaw) ? endRaw : start;
                                          const endpointCandidates = parseFabricListenerEndpointCandidates(draft, node.id);
                                          const advertisedEndpoints = endpointCandidates.map((candidate) => String(candidate.address || "")).filter(Boolean);
                                          const primaryAdvertiseEndpoint =
                                            draft.advertiseEndpoint.trim().replace(/\/$/, "") || advertisedEndpoints[0] || null;
                                          await client.setDesiredWorkload(selectedClusterId, node.id, "fabric-listener", {
                                            desiredState: draft.mode === "disabled" ? "disabled" : "enabled",
                                            version: `listener-${Date.now()}`,
                                            runtimeMode: "container",
                                            config: {
                                              listen_addr: draft.listenAddr,
                                              listen_port_mode: draft.mode,
                                              auto_port_start: start,
                                              auto_port_end: end,
                                              advertise_endpoint: primaryAdvertiseEndpoint,
                                              advertise_endpoints: advertisedEndpoints,
                                              endpoint_candidates: endpointCandidates,
                                              advertise_transport: draft.advertiseTransport || "direct_quic",
                                              connectivity_mode: draft.connectivity,
                                              nat_type: draft.nat,
                                              region: draft.region || null,
                                            },
                                            environment: {},
                                          });
                                        }, "Fabric listener config обновлен.")
                                      }
                                    >
                                      Применить listener
                                    </button>
                                  </div>
                                </section>
                              );
                            })()}
                            <div className="actions">
                              <select
                                value={node.node_group_id || ""}
                                onChange={(event) =>
                                  void runAction(
                                    () => client.assignNodeGroup(selectedClusterId, node.id, event.target.value || null),
                                    event.target.value ? "Узел перемещен в группу." : "Узел убран из группы.",
                                  )
                                }
                              >
                                <option value="">{t.ungroupedNodes}</option>
                                {nodeGroups.map((group) => (
                                  <option key={group.id} value={group.id}>
                                    {groupPathLabel(group, nodeGroups)}
                                  </option>
                                ))}
                              </select>
                            </div>
                            <div className="actions">
                              <button
                                onClick={() =>
                                  confirmHighRisk(`Отключить участие узла ${node.name}`) &&
                                  void runAction(
                                    () => client.disableMembership(selectedClusterId, node.id, "Отключено из панели владельца платформы."),
                                    "Участие узла отключено.",
                                  )
                                }
                              >
                                Отключить участие
                              </button>
                              <button
                                className="danger"
                                onClick={() =>
                                  confirmHighRisk(`Отозвать identity узла ${node.name}`) &&
                                  void runAction(
                                    () => client.revokeNodeIdentity(selectedClusterId, node.id, "Отозвано из панели владельца платформы."),
                                    "Identity узла отозван.",
                                  )
                                }
                              >
                                Отозвать identity
                              </button>
                            </div>
                          </section>
                          )}
                        </>
                      ) : (
                        <section className="nodePanel">
                          <h4>{t.noActiveClusterMembership}</h4>
                          <div className="actions">
                            <button
                              className="primary"
                              onClick={() => {
                                setAttachNodeDialog(nodeInfoDialog);
                                setAttachNodeRoles([]);
                                setNodeInfoDialog(null);
                              }}
                            >
                              {t.connectExistingNode}
                            </button>
                          </div>
                        </section>
                      )}
                    </div>
                  </div>
                );
              })()}

            {false && (nodeViewScope === "all" ? (
              <article className="card span2">
                <h3>{t.allNodes}</h3>
                <p className="muted">{t.nodeGlobalInventoryText}</p>
                <FormGrid>
                  <label>
                    {t.nodeSearch}
                    <input value={allNodeSearch} onChange={(event) => setAllNodeSearch(event.target.value)} placeholder="имя, ключ, кластер, статус" />
                  </label>
                  <label>
                    {t.groupNodesBy}
                    <select value={allNodeGroupBy} onChange={(event) => setAllNodeGroupBy(event.target.value as typeof allNodeGroupBy)}>
                      <option value="membership">{t.groupByMembership}</option>
                      <option value="health">{t.groupByHealth}</option>
                      <option value="ownership">{t.groupByOwnership}</option>
                      <option value="cluster_count">{t.groupByClusterCount}</option>
                    </select>
                  </label>
                </FormGrid>
                <div className="stack">
                  {groupedAllNodeInventory.map((group) => (
                    <section className="nodePanel" key={group.label}>
                      <div className="cardHead">
                        <h4>{group.label}</h4>
                        <span className="pill">{group.items.length}</span>
                      </div>
                      <DataTable
                        columns={["узел", "ключ", t.currentClusterMembership, t.clusterMemberships, "здоровье", "версия", "последний сигнал", "действие"]}
                        rows={group.items.map((entry) => {
                          const { node, memberships } = entry;
                          const activeMembership = memberships.find((membership) => membership.cluster.id === selectedClusterId);
                          const isActiveMember = activeMembership?.node.membership_status === "active";
                          const isRevokedMember = activeMembership?.node.membership_status === "revoked";
                          return [
                            node.name,
                            node.node_key,
                            activeMembership ? <Status value={activeMembership.node.membership_status} /> : <span className="muted">{t.notMemberOfActiveCluster}</span>,
                            <div className="membershipList">
                              {memberships.map((membership) => (
                                <span key={`${membership.cluster.id}-${membership.node.id}`} className={membership.cluster.id === selectedClusterId ? "pill good" : "pill"}>
                                  {membership.cluster.name}: {statusLabel(membership.node.membership_status)}
                                </span>
                              ))}
                            </div>,
                            statusLabel(node.health_status),
                            node.reported_version || "неизвестно",
                            formatDate(node.last_seen_at),
                            <div className="actions" key={`${selectedClusterId}-${node.id}`}>
                              {isActiveMember ? (
                                <button
                                  onClick={() => {
                                    setNodeViewScope("cluster");
                                  }}
                                >
                                  {t.manageInCluster}
                                </button>
                              ) : isRevokedMember ? (
                                <span className="muted">{t.revokedMembership}</span>
                              ) : (
                                <button
                                  className="primary"
                                  onClick={() => {
                                    setAttachNodeDialog(entry);
                                    setAttachNodeRoles([]);
                                  }}
                                >
                                  {t.connectExistingNode}
                                </button>
                              )}
                            </div>,
                          ];
                        })}
                      />
                    </section>
                  ))}
                  {groupedAllNodeInventory.length === 0 && <EmptyState title="Нет узлов" text="По текущему фильтру узлы не найдены." />}
                </div>
                {attachNodeDialog && (
                  <div className="modalBackdrop" role="presentation">
                    <div className="modalCard" role="dialog" aria-modal="true" aria-labelledby="attach-node-title">
                      <div className="cardHead">
                        <div>
                          <h3 id="attach-node-title">{t.connectExistingNodeTitle}</h3>
                          <p className="muted">{t.connectExistingNodeText}</p>
                        </div>
                        <button className="ghost" onClick={() => setAttachNodeDialog(null)}>
                          {t.cancel}
                        </button>
                      </div>
                      <div className="stateList">
                        <StateLine label="Узел" value={attachNodeDialog!.node.name} />
                        <StateLine label="Node key" value={attachNodeDialog!.node.node_key} />
                        <StateLine label={t.activeCluster} value={selectedCluster?.name || selectedClusterId} />
                      </div>
                      <div className="checkGrid">
                        {roleOptions.map((role) => (
                          <label className="checkLine" key={role}>
                            <input
                              type="checkbox"
                              checked={attachNodeRoles.includes(role)}
                              onChange={() => setAttachNodeRoles(toggleArrayValue(attachNodeRoles, role))}
                            />
                            {roleDisplayLabel(role)}
                          </label>
                        ))}
                      </div>
                      <div className="actions">
                        <button
                          className="primary"
                          onClick={() =>
                            void runAction(
                              async () => {
                                await client.attachExistingNode(selectedClusterId, attachNodeDialog!.node.id, attachNodeRoles);
                                setAttachNodeDialog(null);
                                setAttachNodeRoles([]);
                                setNodeViewScope("cluster");
                              },
                              "Узел подключен к активному кластеру.",
                            )
                          }
                        >
                          {t.connectWithRoles}
                        </button>
                        <button onClick={() => setAttachNodeDialog(null)}>{t.cancel}</button>
                      </div>
                    </div>
                  </div>
                )}
              </article>
            ) : (
              <>
            <article className="card span2">
              <h3>{t.testMode}</h3>
              <p className="muted">{t.testModeText}</p>
              <div className="actions">
                <button
                  className={platformTestingFlag?.telemetry_enabled ? "primary" : ""}
                  onClick={() =>
                    void runAction(
                      () =>
                        client.updateFabricTestingFlag({
                          scopeType: "platform",
                          enabled: true,
                          telemetryEnabled: !platformTestingFlag?.telemetry_enabled,
                          syntheticLinksEnabled: Boolean(platformTestingFlag?.synthetic_links_enabled),
                          historyRetentionHours: platformTestingFlag?.history_retention_hours || 24,
                        }),
                      platformTestingFlag?.telemetry_enabled ? "Тестовая телеметрия платформы выключена." : "Тестовая телеметрия платформы включена.",
                    )
                  }
                >
                  {t.enableTelemetry}: {platformTestingFlag?.telemetry_enabled ? "ВКЛ" : "ВЫКЛ"}
                </button>
                <button
                  className={platformTestingFlag?.synthetic_links_enabled ? "primary" : ""}
                  onClick={() =>
                    void runAction(
                      () =>
                        client.updateFabricTestingFlag({
                          scopeType: "platform",
                          enabled: true,
                          telemetryEnabled: Boolean(platformTestingFlag?.telemetry_enabled),
                          syntheticLinksEnabled: !platformTestingFlag?.synthetic_links_enabled,
                          historyRetentionHours: platformTestingFlag?.history_retention_hours || 24,
                        }),
                      platformTestingFlag?.synthetic_links_enabled ? "Тестовые связи выключены." : "Тестовые связи включены.",
                    )
                  }
                >
                  {t.enableSyntheticLinks}: {platformTestingFlag?.synthetic_links_enabled ? "ВКЛ" : "ВЫКЛ"}
                </button>
              </div>
              <section className="nodePanel">
                <h4>{t.organizationTestFlag}</h4>
                <p className="muted">
                  Флаг уровня организации нужен для безопасной проверки телеметрии и истории в tenant scope. Он не раскрывает внутреннюю topology
                  organization-панелям.
                </p>
                <FormGrid>
                  <label>
                    {t.organizationId}
                    <input value={testingOrgId} onChange={(event) => setTestingOrgId(event.target.value)} placeholder="UUID организации" />
                  </label>
                  <label className="checkLine">
                    <input
                      type="checkbox"
                      checked={testingOrgDraft.telemetry}
                      onChange={(event) => setTestingOrgDraft({ ...testingOrgDraft, telemetry: event.target.checked })}
                    />
                    {t.enableTelemetry}
                  </label>
                  <label className="checkLine">
                    <input
                      type="checkbox"
                      checked={testingOrgDraft.links}
                      onChange={(event) => setTestingOrgDraft({ ...testingOrgDraft, links: event.target.checked })}
                    />
                    {t.enableSyntheticLinks}
                  </label>
                </FormGrid>
                <div className="actions">
                  <button
                    disabled={!testingOrgId}
                    onClick={() =>
                      void runAction(
                        () =>
                          client.updateFabricTestingFlag({
                            scopeType: "organization",
                            scopeId: testingOrgId,
                            clusterId: selectedClusterId,
                            enabled: true,
                            telemetryEnabled: testingOrgDraft.telemetry,
                            syntheticLinksEnabled: testingOrgDraft.links,
                            historyRetentionHours: organizationTestingFlag?.history_retention_hours || 24,
                          }),
                        "Флаг тестирования организации сохранен.",
                      )
                    }
                  >
                    {t.saveOrganizationFlag}
                  </button>
                  {organizationTestingFlag && <Status value={organizationTestingFlag?.enabled ? "enabled" : "disabled"} />}
                </div>
              </section>
            </article>
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>{t.nodeGroups}</h3>
                  <p className="muted">
                    Группы принадлежат активному кластеру и могут быть вложенными. Один узел может быть в другой группе в другом кластере.
                  </p>
                </div>
                <span className="pill">{nodeGroups.length}</span>
              </div>
              <FormGrid>
                <label>
                  {t.nodeGroupName}
                  <input value={nodeGroupForm.name} onChange={(event) => setNodeGroupForm({ ...nodeGroupForm, name: event.target.value })} />
                </label>
                <label>
                  {t.parentNodeGroup}
                  <select
                    value={nodeGroupForm.parentGroupId}
                    onChange={(event) => setNodeGroupForm({ ...nodeGroupForm, parentGroupId: event.target.value })}
                  >
                    <option value="">{t.rootNodeGroup}</option>
                    {nodeGroups.map((group) => (
                      <option key={group.id} value={group.id}>
                        {groupPathLabel(group, nodeGroups)}
                      </option>
                    ))}
                  </select>
                </label>
              </FormGrid>
              <div className="actions">
                <button
                  className="primary"
                  disabled={!nodeGroupForm.name.trim()}
                  onClick={() =>
                    void runAction(
                      async () => {
                        await client.createNodeGroup(selectedClusterId, {
                          name: nodeGroupForm.name,
                          parentGroupId: nodeGroupForm.parentGroupId || null,
                        });
                        setNodeGroupForm({ name: "", parentGroupId: "" });
                      },
                      "Группа узлов создана.",
                    )
                  }
                >
                  {t.createNodeGroup}
                </button>
              </div>
              <NodeGroupTree groups={nodeGroups} nodes={nodes} labels={t} />
            </article>
            {nodes.map((node) => {
              const latestHeartbeat = (heartbeatsByNode[node.id] || [])[0];
              const activeRoles = activeFabricNodeRoleAssignments(rolesByNode[node.id] || []);
              const desiredWorkloads = desiredWorkloadsByNode[node.id] || [];
              const observedWorkloads = workloadsByNode[node.id] || [];
              return (
              <article className="card nodeCard" key={node.id}>
                <div className="cardHead">
                  <div>
                    <h3>{node.name}</h3>
                    <p className="muted">{node.node_key}</p>
                  </div>
                  <Status value={node.health_status} />
                </div>
                <section className="nodePanel">
                  <h4>{t.nodeIdentity}</h4>
                  <div className="stateList">
                    <StateLine label="Node ID" value={shortId(node.id)} />
                    <StateLine label="Ключ узла" value={node.node_key} />
                    <StateLine label="Тип владения" value={statusLabel(node.ownership_type)} />
                    <StateLine label="Owner org" value={shortId(node.owner_organization_id)} />
                    <StateLine label="Регистрация" value={statusLabel(node.registration_status)} />
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.activeClusterScope}</h4>
                  <p className="muted">{t.activeClusterScopeText}</p>
                  <div className="stateList">
                    <StateLine label="Участие" value={statusLabel(node.membership_status)} />
                    <StateLine label="Сегмент" value={statusLabel(node.partition_state)} />
                    <StateLine
                      label="Area/site"
                      value={stringField(latestHeartbeat?.metadata?.mesh_endpoint_report as Record<string, unknown> | undefined, "region", "н/д")}
                    />
                    <StateLine label="Здоровье" value={statusLabel(node.health_status)} />
                    <StateLine label="Группа" value={node.node_group_name || t.ungroupedNodes} />
                    <StateLine label="Версия" value={node.reported_version || "неизвестно"} />
                    <StateLine label="Последний сигнал" value={formatDate(node.last_seen_at)} />
                    <StateLine label="Функций в кластере" value={String(activeRoles.length)} />
                    <StateLine label="Desired-сервисов" value={String(desiredWorkloads.length)} />
                    <StateLine label="Observed-сервисов" value={String(observedWorkloads.length)} />
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.nodeRoles}</h4>
                  <div className="serviceTags">
                    {activeRoles.length === 0 && <p className="muted">{t.noRoles}</p>}
                    {activeRoles.map((role) => (
                        <div className="serviceTag" key={role.id}>
                          <strong>{roleDisplayLabel(role.role)}</strong>
                          <span>{role.organization_id ? `organization: ${shortId(role.organization_id)}` : "cluster-wide"}</span>
                          <small>{formatDate(role.assigned_at)}</small>
                          <span className={`pill ${capabilityPillTone(role.role, latestHeartbeat)}`}>
                            {capabilityLabel(role.role, latestHeartbeat, t)}
                          </span>
                        </div>
                      ))}
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.desiredServices}</h4>
                  <div className="serviceTags">
                    {desiredWorkloads.length === 0 && <p className="muted">{t.noServices}</p>}
                    {desiredWorkloads.map((workload) => (
                      <div className="serviceTag" key={`${workload.service_type}-${workload.runtime_mode}`}>
                        <strong>{workload.service_type}</strong>
                        <span>{statusLabel(workload.desired_state)} / {workload.runtime_mode}</span>
                        <small>{workload.version || "версия не закреплена"}</small>
                        <span className={`pill ${capabilityPillTone(workload.service_type, latestHeartbeat)}`}>
                          {capabilityLabel(workload.service_type, latestHeartbeat, t)}
                        </span>
                      </div>
                    ))}
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.observedServices}</h4>
                  <div className="serviceTags">
                    {observedWorkloads.length === 0 && <p className="muted">{t.noServices}</p>}
                    {observedWorkloads.map((workload) => (
                      <div className="serviceTag" key={workload.id}>
                        <strong>{workload.service_type}</strong>
                        <span>{statusLabel(workload.reported_state)} / {workload.runtime_mode}</span>
                        <small>{formatDate(workload.observed_at)}</small>
                      </div>
                    ))}
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.nodeManagement}</h4>
                  <div className="actions">
                    <select
                      value={nodeRoleDrafts[node.id] || ""}
                      onChange={(event) => setNodeRoleDrafts({ ...nodeRoleDrafts, [node.id]: event.target.value })}
                    >
                      <option value="">Функция...</option>
                      {roleOptions.map((role) => (
                        <option key={role} value={role}>
                          {roleDisplayLabel(role)} — {capabilityOptionLabel(role, latestHeartbeat, language)}
                        </option>
                      ))}
                    </select>
                    <button
                      disabled={!nodeRoleDrafts[node.id]}
                      onClick={() =>
                        void runAction(
                          () => client.assignRole(selectedClusterId, node.id, nodeRoleDrafts[node.id], undefined),
                          "Функция назначена.",
                        )
                      }
                    >
                      Назначить функцию
                    </button>
                    <select
                      value={nodeWorkloadDrafts[node.id] || ""}
                      onChange={(event) => setNodeWorkloadDrafts({ ...nodeWorkloadDrafts, [node.id]: event.target.value })}
                    >
                      <option value="">Сервис...</option>
                      {serviceWorkloadOptions.map((role) => (
                        <option key={role} value={role}>
                          {roleDisplayLabel(role)} — {capabilityOptionLabel(role, latestHeartbeat, language)}
                        </option>
                      ))}
                    </select>
                    <button
                      disabled={!nodeWorkloadDrafts[node.id]}
                      onClick={() =>
                        void runAction(
                          () =>
                            client.setDesiredWorkload(selectedClusterId, node.id, nodeWorkloadDrafts[node.id], {
                              desiredState: "enabled",
                              runtimeMode: "container",
                              config: {},
                              environment: {},
                            }),
                          "Желаемое состояние сервиса включено.",
                        )
                      }
                    >
                      Включить сервис
                    </button>
                    <button
                      disabled={!nodeWorkloadDrafts[node.id]}
                      onClick={() =>
                        void runAction(
                          () =>
                            client.setDesiredWorkload(selectedClusterId, node.id, nodeWorkloadDrafts[node.id], {
                              desiredState: "disabled",
                              runtimeMode: "container",
                              config: {},
                              environment: {},
                            }),
                          "Желаемое состояние сервиса выключено.",
                        )
                      }
                    >
                      Выключить сервис
                    </button>
                    <select
                      value={node.node_group_id || ""}
                      onChange={(event) =>
                        void runAction(
                          () => client.assignNodeGroup(selectedClusterId, node.id, event.target.value || null),
                          event.target.value ? "Узел перемещен в группу." : "Узел убран из группы.",
                        )
                      }
                    >
                      <option value="">{t.ungroupedNodes}</option>
                      {nodeGroups.map((group) => (
                        <option key={group.id} value={group.id}>
                          {groupPathLabel(group, nodeGroups)}
                        </option>
                      ))}
                    </select>
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.testMode}</h4>
                  <div className="actions">
                    <label className="checkLine">
                      <input
                        type="checkbox"
                        checked={nodeTestingDrafts[node.id]?.telemetry ?? true}
                        onChange={(event) =>
                          setNodeTestingDrafts({
                            ...nodeTestingDrafts,
                            [node.id]: { telemetry: event.target.checked, links: nodeTestingDrafts[node.id]?.links ?? true },
                          })
                        }
                      />
                      {t.enableTelemetry}
                    </label>
                    <label className="checkLine">
                      <input
                        type="checkbox"
                        checked={nodeTestingDrafts[node.id]?.links ?? true}
                        onChange={(event) =>
                          setNodeTestingDrafts({
                            ...nodeTestingDrafts,
                            [node.id]: { telemetry: nodeTestingDrafts[node.id]?.telemetry ?? true, links: event.target.checked },
                          })
                        }
                      />
                      {t.enableSyntheticLinks}
                    </label>
                    <button
                      onClick={() =>
                        void runAction(
                          () =>
                            client.updateFabricTestingFlag({
                              scopeType: "node",
                              scopeId: node.id,
                              clusterId: selectedClusterId,
                              enabled: true,
                              telemetryEnabled: nodeTestingDrafts[node.id]?.telemetry ?? true,
                              syntheticLinksEnabled: nodeTestingDrafts[node.id]?.links ?? true,
                              historyRetentionHours: 24,
                            }),
                          "Флаг тестирования узла сохранен.",
                        )
                      }
                    >
                      {t.saveTestFlag}
                    </button>
                  </div>
                </section>
                <section className="nodePanel">
                  <h4>{t.nodeTelemetry}</h4>
                  <TelemetryStrip items={telemetryByNode[node.id] || []} emptyText={t.noTelemetry} />
                </section>
                <section className="nodePanel">
                  <h4>{t.recentHeartbeats}</h4>
                  <DataTable
                    columns={["состояние", "версия", "listener", "mesh recovery", "mesh intents", "rv leases", "path decisions", "route gen", "route health", "наблюдение"]}
                    rows={(heartbeatsByNode[node.id] || []).slice(0, 5).map((heartbeat) => [
                      heartbeat.health_status,
                      heartbeat.reported_version || "неизвестно",
                      fabricListenerSummary(heartbeat),
                      meshRecoverySummary(heartbeat),
                      meshConnectionIntentSummary(heartbeat),
                      meshRendezvousLeaseSummary(heartbeat),
                      meshRoutePathDecisionSummary(heartbeat),
                      meshRouteGenerationSummary(heartbeat),
                      meshRouteHealthConfigSummary(heartbeat),
                      formatDate(heartbeat.observed_at),
                    ])}
                  />
                </section>
                <div className="actions">
                  <button
                    onClick={() =>
                      confirmHighRisk(`Отключить участие узла ${node.name}`) &&
                      void runAction(
                        () => client.disableMembership(selectedClusterId, node.id, "Отключено из панели владельца платформы."),
                        "Участие узла отключено.",
                      )
                    }
                  >
                    Отключить участие
                  </button>
                  <button
                    className="danger"
                    onClick={() =>
                      confirmHighRisk(`Отозвать identity узла ${node.name}`) &&
                      void runAction(
                        () => client.revokeNodeIdentity(selectedClusterId, node.id, "Отозвано из панели владельца платформы."),
                        "Identity узла отозван.",
                      )
                    }
                  >
                    Отозвать identity
                  </button>
                </div>
              </article>
              );
            })}
            {nodes.length === 0 && <EmptyState title="Нет узлов" text="Одобренные node-agent появятся здесь." />}
              </>
            ))}
          </section>
        )}

        {activeView === "enrollment" && (
          <section className="grid two">
            <article className="card">
              <h3>{t.joinTokenTitle}</h3>
              <p className="muted">{t.joinTokenText}</p>
              <FormGrid>
                <label>
                  {t.ttlHours}
                  <input
                    type="number"
                    min={1}
                    max={720}
                    value={joinTokenForm.ttlHours}
                    onChange={(event) => setJoinTokenForm({ ...joinTokenForm, ttlHours: Number(event.target.value) })}
                  />
                  <small>{t.ttlHelp}</small>
                </label>
                <label>
                  {t.maxUses}
                  <input
                    type="number"
                    min={1}
                    max={100}
                    value={joinTokenForm.maxUses}
                    onChange={(event) => setJoinTokenForm({ ...joinTokenForm, maxUses: Number(event.target.value) })}
                  />
                  <small>{t.maxUsesHelp}</small>
                </label>
                <label>
                  {t.nodeOwnership}
                  <select
                    value={joinTokenForm.ownershipType}
                    onChange={(event) => setJoinTokenForm({ ...joinTokenForm, ownershipType: event.target.value })}
                  >
                    <option value="platform_managed">platform_managed, управляется платформой</option>
                    <option value="customer_managed">customer_managed, управляется клиентом</option>
                  </select>
                </label>
                <label>
                  {t.tokenPurpose}
                  <input
                    value={joinTokenForm.purpose}
                    onChange={(event) => setJoinTokenForm({ ...joinTokenForm, purpose: event.target.value })}
                    placeholder="например: стартовый entry-node в ru-msk-1"
                  />
                </label>
                <label>
                  Имя нового узла
                  <input
                    value={joinTokenForm.nodeName}
                    onChange={(event) => setJoinTokenForm({ ...joinTokenForm, nodeName: event.target.value })}
                    placeholder={suggestedInstallNodeName(joinTokenForm, selectedCluster)}
                  />
                  <small>Если оставить пустым, панель подставит имя автоматически.</small>
                </label>
                <label>
                  Группа узла
                  <select value={joinTokenForm.nodeGroupId} onChange={(event) => setJoinTokenForm({ ...joinTokenForm, nodeGroupId: event.target.value })}>
                    <option value="">Без группы</option>
                    {nodeGroups.map((group) => (
                      <option key={group.id} value={group.id}>
                        {groupPathLabel(group, nodeGroups)}
                      </option>
                    ))}
                  </select>
                </label>
              </FormGrid>
              <section className="nodePanel">
                <h4>Join bundle</h4>
                <p className="muted">Панель готовит signed join bundle: trust root, join token, fabric seeds и install/runtime параметры. После старта узел живет через QUIC fabric, а не через отдельный HTTP control path.</p>
                <div className="segmented">
                  {[
                    ["docker", "Docker Linux"],
                    ["linux_binary", "Ubuntu service"],
                    ["windows_service", "Windows"],
                  ].map(([mode, label]) => (
                    <button
                      type="button"
                      key={mode}
                      className={joinTokenForm.installMode === mode ? "active" : ""}
                      onClick={() => setJoinTokenForm({ ...joinTokenForm, installMode: mode })}
                    >
                      {label}
                    </button>
                  ))}
                </div>
                <div className="segmented">
                  {[
                    ["private_lan", "LAN"],
                    ["direct", "Public"],
                    ["nat_forward", "NAT"],
                    ["outbound_only", "Outbound"],
                  ].map(([mode, label]) => (
                    <button
                      type="button"
                      key={mode}
                      className={dockerConnectivityPreset(joinTokenForm) === mode ? "active" : ""}
                      onClick={() => setJoinTokenForm(applyDockerConnectivityPreset(joinTokenForm, mode))}
                    >
                      {label}
                    </button>
                  ))}
                </div>
                <FormGrid>
                  <label>
                    {joinTokenForm.installMode === "windows_service" ? "Windows node-agent artifact" : joinTokenForm.installMode === "linux_binary" ? "Linux node-agent artifact" : "Docker image"}
                    <input value={joinTokenForm.dockerImage} onChange={(event) => setJoinTokenForm({ ...joinTokenForm, dockerImage: event.target.value })} />
                  </label>
                  {joinTokenForm.installMode === "windows_service" && (
                    <>
                      <label>
                        Windows startup
                        <select value={joinTokenForm.windowsStartupMode} onChange={(event) => setJoinTokenForm({ ...joinTokenForm, windowsStartupMode: event.target.value })}>
                          <option value="auto">auto: system task, user rescue task</option>
                          <option value="system-task">system task, admin required</option>
                          <option value="user-task">user task, no admin</option>
                          <option value="none">none</option>
                        </select>
                      </label>
                      <label>
                        Install dir
                        <input
                          value={joinTokenForm.windowsInstallDir}
                          onChange={(event) => setJoinTokenForm({ ...joinTokenForm, windowsInstallDir: event.target.value })}
                          placeholder="C:\\Program Files\\RAP\\node-name"
                        />
                      </label>
                      <label>
                        Windows node-agent SHA256
                        <input
                          value={joinTokenForm.windowsNodeAgentSHA256}
                          onChange={(event) => setJoinTokenForm({ ...joinTokenForm, windowsNodeAgentSHA256: event.target.value })}
                          placeholder="опционально, но желательно для production"
                        />
                      </label>
                    </>
                  )}
                  {joinTokenForm.installMode === "linux_binary" && (
                    <>
                      <label>
                        Linux install dir
                        <input
                          value={joinTokenForm.linuxInstallDir}
                          onChange={(event) => setJoinTokenForm({ ...joinTokenForm, linuxInstallDir: event.target.value })}
                          placeholder="/opt/rap/node-name"
                        />
                      </label>
                      <label>
                        Linux node-agent SHA256
                        <input
                          value={joinTokenForm.linuxNodeAgentSHA256}
                          onChange={(event) => setJoinTokenForm({ ...joinTokenForm, linuxNodeAgentSHA256: event.target.value })}
                          placeholder="опционально, но желательно для production"
                        />
                      </label>
                    </>
                  )}
                  {joinTokenForm.installMode === "docker" && <label>
                    Container name
                    <input
                      value={joinTokenForm.dockerContainerName}
                      onChange={(event) => setJoinTokenForm({ ...joinTokenForm, dockerContainerName: event.target.value })}
                      placeholder={suggestedInstallContainerName(joinTokenForm, selectedCluster)}
                    />
                  </label>}
                  <details className="compactDetails">
                    <summary>Local artifact paths</summary>
                    <label>
                      Paths
                      <input
                        value={joinTokenForm.artifactEndpoints}
                        onChange={(event) => setJoinTokenForm({ ...joinTokenForm, artifactEndpoints: event.target.value })}
                        placeholder="optional local paths only"
                      />
                      <small>Optional override for local files already present on the target.</small>
                    </label>
                  </details>
                  {joinTokenForm.installMode === "docker" && <label>
                    Docker image tar SHA256
                    <input
                      value={joinTokenForm.dockerImageArtifactSHA256}
                      onChange={(event) => setJoinTokenForm({ ...joinTokenForm, dockerImageArtifactSHA256: event.target.value })}
                      placeholder="опционально, но желательно для production"
                    />
                  </label>}
                  {joinTokenForm.installMode === "docker" && <label>
                    Docker network
                    <select value={joinTokenForm.dockerNetwork} onChange={(event) => setJoinTokenForm({ ...joinTokenForm, dockerNetwork: event.target.value })}>
                      <option value="host">host</option>
                      <option value="bridge">bridge</option>
                    </select>
                  </label>}
                  <label>
                    Fabric listen addr
                    <input value={joinTokenForm.fabricListenAddr} onChange={(event) => setJoinTokenForm({ ...joinTokenForm, fabricListenAddr: event.target.value })} />
                  </label>
                  <label>
                    Fabric listen mode
                    <select
                      value={joinTokenForm.fabricListenPortMode}
                      onChange={(event) => setJoinTokenForm({ ...joinTokenForm, fabricListenPortMode: event.target.value })}
                    >
                      <option value="auto">auto</option>
                      <option value="manual">manual</option>
                      <option value="disabled">disabled</option>
                    </select>
                  </label>
                  <label>
                    Fabric auto ports
                    <input
                      value={`${joinTokenForm.fabricListenAutoPortStart}-${joinTokenForm.fabricListenAutoPortEnd}`}
                      onChange={(event) => {
                        const [start, end] = event.target.value.split("-").map((value) => Number(value.trim()));
                        setJoinTokenForm({
                          ...joinTokenForm,
                          fabricListenAutoPortStart: Number.isFinite(start) ? start : joinTokenForm.fabricListenAutoPortStart,
                          fabricListenAutoPortEnd: Number.isFinite(end) ? end : joinTokenForm.fabricListenAutoPortEnd,
                        });
                      }}
                    />
                  </label>
                  <label>
                    Advertise endpoint
                    <input
                      value={joinTokenForm.meshAdvertiseEndpoint}
                      onChange={(event) => setJoinTokenForm({ ...joinTokenForm, meshAdvertiseEndpoint: event.target.value })}
                      placeholder="quic://192.168.200.85:18080"
                    />
                  </label>
                  <label className="wideLabel">
                    Endpoint candidates
                    <textarea
                      value={joinTokenForm.meshAdvertiseEndpoints}
                      onChange={(event) => setJoinTokenForm({ ...joinTokenForm, meshAdvertiseEndpoints: event.target.value })}
                      rows={5}
                      placeholder={
                        "quic://192.168.200.85:18080 reachability=private connectivity=private_lan nat=none interface=lan priority=1\n" +
                        "quic://94.141.118.222:19199 reachability=public connectivity=direct nat=port_restricted provider=isp1 maps_to=192.168.200.85:18080 priority=2"
                      }
                    />
                    <small>
                      Сюда вносим все реальные адреса узла: LAN, разные адаптеры, публичные UDP NAT-пробросы разных провайдеров.
                    </small>
                  </label>
                  <label>
                    Advertise transport
                    <select
                      value={joinTokenForm.meshAdvertiseTransport}
                      onChange={(event) => setJoinTokenForm({ ...joinTokenForm, meshAdvertiseTransport: event.target.value })}
                    >
                      <option value="direct_quic">direct_quic</option>
                      <option value="relay_quic">relay_quic</option>
                      <option value="outbound_reverse">outbound_reverse</option>
                    </select>
                  </label>
                  <label>
                    Connectivity
                    <select
                      value={joinTokenForm.meshConnectivityMode}
                      onChange={(event) => setJoinTokenForm({ ...joinTokenForm, meshConnectivityMode: event.target.value })}
                    >
                      <option value="direct">direct</option>
                      <option value="private_lan">private_lan</option>
                      <option value="outbound_only">outbound_only</option>
                      <option value="relay_required">relay_required</option>
                    </select>
                  </label>
                  <label>
                    NAT
                    <select value={joinTokenForm.meshNATType} onChange={(event) => setJoinTokenForm({ ...joinTokenForm, meshNATType: event.target.value })}>
                      <option value="none">none</option>
                      <option value="unknown">unknown</option>
                      <option value="full_cone">full_cone</option>
                      <option value="port_restricted">port_restricted</option>
                      <option value="symmetric">symmetric</option>
                    </select>
                  </label>
                  <label>
                    Region/site
                    <input value={joinTokenForm.meshRegion} onChange={(event) => setJoinTokenForm({ ...joinTokenForm, meshRegion: event.target.value })} />
                  </label>
                  {joinTokenForm.installMode === "docker" && <label className="checkLine">
                    <input type="checkbox" checked={joinTokenForm.pullImage} onChange={(event) => setJoinTokenForm({ ...joinTokenForm, pullImage: event.target.checked })} />
                    Pull image
                  </label>}
                  <label className="checkLine">
                    <input type="checkbox" checked={joinTokenForm.replace} onChange={(event) => setJoinTokenForm({ ...joinTokenForm, replace: event.target.checked })} />
                    Replace existing install
                  </label>
                </FormGrid>
              </section>
              <section className="nodePanel">
                <h4>{t.suggestedRoles}</h4>
                <p className="muted">
                  В install token записываются только базовые функции узла фермы. Сервисные runtime назначения задаются отдельно, после входа узла в fabric.
                </p>
                <div className="checkGrid">
                  {roleOptions.map((role) => (
                    <label className="checkLine" key={role}>
                      <input
                        type="checkbox"
                        checked={joinTokenForm.roles.includes(role)}
                        onChange={() => setJoinTokenForm({ ...joinTokenForm, roles: toggleArrayValue(joinTokenForm.roles, role) })}
                      />
                      {roleDisplayLabel(role)}
                    </label>
                  ))}
                </div>
              </section>
              <details>
                <summary>{t.generatedScope}</summary>
                <p className="muted">{t.generatedScopeHelp}</p>
                <pre className="codePreview">{JSON.stringify(joinTokenScope, null, 2)}</pre>
              </details>
              <p className="muted">{t.manualApprovalRequired}.</p>
              <button
                className="primary"
                disabled={!selectedClusterId}
                onClick={() =>
                  void runAction(async () => {
                    const token = await client.createJoinToken(selectedClusterId, {
                      ttlHours: joinTokenForm.ttlHours,
                      maxUses: joinTokenForm.maxUses,
                      scope: joinTokenScope,
                    });
                    const nodeName = suggestedInstallNodeName(joinTokenForm, selectedCluster);
                    const [dockerBundle, linuxBundle, windowsBundle] = await Promise.all([
                      client.getDockerJoinBundle({
                        clusterId: selectedClusterId,
                        installToken: token.token,
                        nodeName,
                      }),
                      client.getLinuxJoinBundle({
                        clusterId: selectedClusterId,
                        installToken: token.token,
                        nodeName,
                      }),
                      client.getWindowsJoinBundle({
                        clusterId: selectedClusterId,
                        installToken: token.token,
                        nodeName,
                      }),
                    ]);
                    setLastJoinToken(token);
                    setLastJoinBundles({
                      docker: dockerBundle,
                      linux_binary: linuxBundle,
                      windows_service: windowsBundle,
                    });
                  }, "Join token создан.")
                }
              >
                Создать install token
              </button>
              {lastJoinToken && (
                <div className="secretOnce">
                  <strong>Исходный token, возвращается один раз</strong>
                  <code>{lastJoinToken.token}</code>
                  <span className="muted">Authority key: {shortId(lastJoinToken.authority_signature?.key_fingerprint)}</span>
                  <strong>Scope выданного token</strong>
                  <pre className="codePreview">{JSON.stringify(lastJoinToken.scope, null, 2)}</pre>
                  <strong>Signed join bundle</strong>
                  <div className="actions">
                    <button
                      onClick={() =>
                        activeJoinBundle &&
                        downloadTextFile(
                          joinBundleFileName(joinTokenForm.installMode, selectedCluster, lastJoinTokenInstallForm),
                          JSON.stringify(activeJoinBundle, null, 2),
                        )
                      }
                      disabled={!activeJoinBundle}
                    >
                      Скачать bundle
                    </button>
                    <button
                      onClick={() =>
                        activeJoinBundle &&
                        void copyTextToClipboard(JSON.stringify(activeJoinBundle, null, 2))
                      }
                      disabled={!activeJoinBundle}
                    >
                      Копировать bundle JSON
                    </button>
                  </div>
                  {activeJoinBundle && <pre className="codePreview">{JSON.stringify(activeJoinBundle, null, 2)}</pre>}
                  <strong>Bundle-first install command</strong>
                  <pre className="codePreview">{joinInstallCommand(lastJoinToken, selectedCluster, lastJoinTokenInstallForm)}</pre>
                </div>
              )}
            </article>

            <article className="card">
              <h3>Как добавить узел</h3>
              <div className="stateList">
                <div className="stateLine">
                  <span>1</span>
                  <strong>Заполните join bundle слева.</strong>
                </div>
                <div className="stateLine">
                  <span>2</span>
                  <strong>Нажмите “Создать install token”.</strong>
                </div>
                <div className="stateLine">
                  <span>3</span>
                  <strong>Скачайте signed join bundle или выполните bundle-first install command на целевой машине.</strong>
                </div>
                <div className="stateLine">
                  <span>4</span>
                  <strong>Подтвердите join request в этой же вкладке.</strong>
                </div>
              </div>
            </article>

            <article className="card">
              <h3>Install tokens</h3>
              <DataTable
                columns={["scope", "status", "uses", "expires", "created", "action"]}
                rows={joinTokens.map((token) => [
                  joinTokenName(token),
                  statusLabel(token.status),
                  `${token.used_count}/${token.max_uses}`,
                  formatDate(token.expires_at),
                  formatDate(token.created_at),
                  token.status === "active" ? (
                    <button
                      className="danger"
                      onClick={() =>
                        confirmHighRisk(`Отозвать install token ${shortId(token.id)}`) &&
                        void runAction(() => client.revokeJoinToken(selectedClusterId, token.id), "Install token отозван.")
                      }
                    >
                      Отозвать
                    </button>
                  ) : (
                    <span className="muted">{statusLabel(token.status)}</span>
                  ),
                ])}
              />
            </article>

            <article className="card">
              <h3>Заявки на подключение</h3>
              <div className="stack">
                {joinRequests.map((request) => (
                  <div className="requestCard" key={request.id}>
                    <div>
                      <strong>{request.node_name}</strong>
                      <p>{request.node_fingerprint}</p>
                      <Status value={request.status} />
                      {request.approval_signature?.key_fingerprint && (
                        <small className="muted">approval key {shortId(request.approval_signature.key_fingerprint)}</small>
                      )}
                    </div>
                    <div className="actions">
                      <button
                        disabled={request.status !== "pending"}
                        onClick={() => void runAction(() => client.approveJoinRequest(selectedClusterId, request.id), "Заявка одобрена.")}
                      >
                        Одобрить
                      </button>
                      <button
                        disabled={request.status !== "pending"}
                        onClick={() =>
                          void runAction(
                            () => client.rejectJoinRequest(selectedClusterId, request.id, "Отклонено из панели владельца платформы."),
                            "Заявка отклонена.",
                          )
                        }
                      >
                        Отклонить
                      </button>
                    </div>
                  </div>
                ))}
                {joinRequests.length === 0 && <EmptyState title="Нет заявок" text="Новые подключения node-agent появятся здесь." />}
              </div>
            </article>
          </section>
        )}

        {activeView === "functions" && (
          <section className="stack">
            <article className="card">
              <h3>Функции узлов фермы</h3>
              <p className="muted">Capabilities — технические факты из heartbeat. Здесь назначаются только инфраструктурные функции активного кластера.</p>
            </article>
            {nodes.map((node) => (
              <article className="card roleRow" key={node.id}>
                <div>
                  <h3>{node.name}</h3>
                  <p>{summarizeRoles(rolesByNode[node.id] || [])}</p>
                </div>
                <select
                  defaultValue=""
                  onChange={(event) => {
                    const role = event.target.value;
                    event.currentTarget.value = "";
                    if (role) {
                      void runAction(() => client.assignRole(selectedClusterId, node.id, role, undefined), `${role} назначена узлу ${node.name}.`);
                    }
                  }}
                >
                  <option value="">Назначить функцию...</option>
                  {roleOptions.map((role) => (
                    <option key={role} value={role}>
                      {roleDisplayLabel(role)}
                    </option>
                  ))}
                </select>
              </article>
            ))}
          </section>
        )}

        {activeView === "workloads" && (
          <section className="grid two">
            <article className="card">
              <h3>Желаемое состояние сервиса</h3>
              <p className="muted">Здесь задается только желаемое состояние. Runtime-исполнение остается под контролем node-agent и политик.</p>
              <FormGrid>
                <label>
                  Узел
                  <select value={workloadForm.nodeId} onChange={(event) => setWorkloadForm({ ...workloadForm, nodeId: event.target.value })}>
                    <option value="">Выберите узел...</option>
                    {nodes.map((node) => (
                      <option key={node.id} value={node.id}>
                        {node.name}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  Сервис
                  <select value={workloadForm.serviceType} onChange={(event) => setWorkloadForm({ ...workloadForm, serviceType: event.target.value })}>
                    {serviceWorkloadOptions.map((role) => (
                      <option key={role} value={role}>
                        {roleDisplayLabel(role)}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  Желаемое состояние
                  <select value={workloadForm.desiredState} onChange={(event) => setWorkloadForm({ ...workloadForm, desiredState: event.target.value })}>
                    <option value="enabled">включено</option>
                    <option value="disabled">выключено</option>
                  </select>
                </label>
                <label>
                  Режим runtime
                  <select value={workloadForm.runtimeMode} onChange={(event) => setWorkloadForm({ ...workloadForm, runtimeMode: event.target.value })}>
                    <option value="container">контейнер</option>
                    <option value="native">нативно</option>
                  </select>
                </label>
                <label>
                  Версия
                  <input value={workloadForm.version} onChange={(event) => setWorkloadForm({ ...workloadForm, version: event.target.value })} />
                </label>
              </FormGrid>
              <label>
                Config JSON
                <textarea value={workloadForm.configJson} onChange={(event) => setWorkloadForm({ ...workloadForm, configJson: event.target.value })} />
              </label>
              <label>
                Environment JSON
                <textarea
                  value={workloadForm.environmentJson}
                  onChange={(event) => setWorkloadForm({ ...workloadForm, environmentJson: event.target.value })}
                />
              </label>
              <button
                className="primary"
                disabled={!workloadForm.nodeId || !selectedClusterId}
                onClick={() =>
                  void runAction(
                    () =>
                      client.setDesiredWorkload(selectedClusterId, workloadForm.nodeId, workloadForm.serviceType, {
                        desiredState: workloadForm.desiredState,
                        runtimeMode: workloadForm.runtimeMode,
                        version: workloadForm.version,
                        config: parseJSONObject(workloadForm.configJson, "config сервиса"),
                        environment: parseJSONObject(workloadForm.environmentJson, "environment сервиса"),
                      }),
                    "Желаемое состояние сервиса обновлено.",
                  )
                }
              >
                Задать желаемое состояние
              </button>
            </article>

            <article className="card">
              <h3>Отчеты сервисов</h3>
              <div className="stack">
                {nodes.map((node) => (
                  <div className="workloadBlock" key={node.id}>
                    <strong>{node.name}</strong>
                    {(workloadsByNode[node.id] || []).length === 0 ? (
                      <p className="muted">Статус пока не получен.</p>
                    ) : (
                      <DataTable
                        columns={["сервис", "состояние", "runtime", "наблюдение"]}
                        rows={(workloadsByNode[node.id] || []).map((workload) => [
                          workload.service_type,
                          workload.reported_state,
                          workload.runtime_mode,
                          formatDate(workload.observed_at),
                        ])}
                      />
                    )}
                  </div>
                ))}
              </div>
            </article>
          </section>
        )}

        {activeView === "fabric" && (
          <section className="fabricTransportView">
            <article className="card fabricMapCard">
              <div className="cardHead">
                <div>
                  <h3>Транспортный слой Fabric</h3>
                  <p className="muted">
                  Карта показывает реальные свежие QUIC-соседства и проверенные relay/route-health маршруты. Прямые связи рисуются сплошной линией,
                  relay и route-health отделены пунктиром, чтобы не смешивать физического соседа и достижимый маршрут.
                  </p>
                </div>
                <div className="summaryChips">
                  <span className="pill good">direct {meshLinks.length}</span>
                  <span className="pill">{webIngressReceiverCluster.label}</span>
                  <Status value={platformTestingFlag?.synthetic_links_enabled ? "enabled" : "disabled"} />
                </div>
              </div>
              <FabricTopology
                nodes={nodes}
                links={meshLinks}
                heartbeatsByNode={heartbeatsByNode}
                rolesByNode={rolesByNode}
                workloadsByNode={workloadsByNode}
                labels={t}
                emptyText={t.noLinks}
              />
              <details className="sectionBlock fabricDiagnostics">
                <summary>Диагностика transport/runtime receivers</summary>
                <div className="signalStrip compact">
                  <Signal label="Synthetic configs" value={`${syntheticConfigEnabledCount}/${nodes.length}`} />
                  <Signal label="Routes" value={String(syntheticRouteCount)} />
                  <Signal label="Endpoints / candidates" value={`${syntheticPeerEndpointCount}/${syntheticCandidateCount}`} />
                  <Signal label="Scoped production" value={productionForwardingConfigCount === 0 ? "false" : `true:${productionForwardingConfigCount}`} />
                </div>
                <DataTable
                  columns={["узел", "status", "reason", "trusted keys", "service classes", "QUIC addr", "ошибка"]}
                  rows={nodes.map((node) => {
                    const report = objectField(heartbeatsByNode[node.id]?.[0]?.metadata?.web_ingress_runtime_receiver_report);
                    const status = webIngressReceiverStatus(heartbeatsByNode[node.id]?.[0]);
                    const actualClasses = report ? arrayStrings(report.service_classes) : [];
                    const expectedClasses = expectedWebIngressRuntimeClasses(rolesByNode[node.id] || []);
                    const mismatch = expectedClasses.length > 0 && !expectedClasses.every((serviceClass) => actualClasses.includes(serviceClass));
                    return [
                      node.name,
                      <span className={`pill ${status === "ready" ? "good" : status === "degraded" ? "warn" : status === "blocked" ? "bad" : ""}`}>{status}</span>,
                      report ? stringField(report, "reason", "н/д") : "no report",
                      report ? String(numberField(report, "trusted_key_count")) : "0",
                      <span className={mismatch ? "pill warn" : ""}>{report ? actualClasses.join(", ") || "н/д" : "н/д"}</span>,
                      report ? stringField(report, "quic_fabric_listen_addr", "н/д") : "н/д",
                      mismatch ? `expected: ${expectedClasses.join(", ")}` : report ? stringField(report, "quic_fabric_error", "") || stringField(report, "error", "") || "—" : "—",
                    ];
                  })}
                />
              </details>
            </article>
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>Synthetic mesh config</h3>
                  <p className="muted">
                    Node-scoped config from the Control/API layer. Endpoint candidates and scoring inputs are visible to the platform owner only; production
                    forwarding for service traffic must remain disabled here.
                  </p>
                </div>
                <span className={productionForwardingConfigCount === 0 ? "pill good" : "pill bad"}>
                  production_forwarding={productionForwardingConfigCount === 0 ? "false" : "true"}
                </span>
              </div>
              <DataTable
                columns={[
                  "узел",
                  "config",
                  "routes",
                  "peer endpoints",
                  "candidates",
                  "peer dir",
                  "recovery seeds",
                  "rendezvous leases",
                  "relay policy",
                  "path decisions",
                  "authority",
                  "scoped production",
                ]}
                rows={nodes.map((node) => {
                  const config = syntheticMeshConfigsByNode[node.id];
                  return [
                    node.name,
                    config ? (config.enabled ? "enabled" : "disabled") : "не загружен",
                    String(config?.routes.length ?? 0),
                    String(Object.keys(config?.peer_endpoints || {}).length),
                    String(config ? countPeerEndpointCandidates(config) : 0),
                    String(config?.peer_directory?.length ?? 0),
                    String(config?.recovery_seeds?.length ?? 0),
                    String(config?.rendezvous_leases?.length ?? 0),
                    rendezvousRelayPolicySummary(config),
                    routePathDecisionSummary(config),
                    config?.authority_required ? shortId(config.authority_signature?.key_fingerprint) : "не требуется",
                    config?.production_forwarding ? "true" : "false",
                  ];
                })}
              />
              <p className="muted">
                Health-aware scoring не выбирает service route и не открывает service-соединения. C17Z19 показывает управляющий route/path
                decisions, route generation status, synthetic route-health effective path и relay feedback scoring, но не переносит
                RDP/VPN/file/video/service payload.
              </p>
            </article>
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>Route intents lifecycle</h3>
                  <p className="muted">
                    Operator view for temporary fabric routes. Expired and disabled intents are not emitted into node-scoped synthetic config.
                  </p>
                </div>
                <div className="summaryChips">
                  <span className="pill good">active {routeIntentActive.length}</span>
                  <span className={routeIntentExpired.length > 0 ? "pill warn" : "pill"}>expired {routeIntentExpired.length}</span>
                  <span className="pill">disabled {routeIntentDisabled.length}</span>
                </div>
              </div>
              <DataTable
                columns={["route", "life", "service", "priority", "source", "destination", "expires", "updated", "actions"]}
                rows={routeIntents.slice(0, 120).map((item) => {
                  const lifecycle = routeIntentLifecycle(item);
                  return [
                    shortId(item.id),
                    <span className={`pill ${routeIntentTone(item)}`}>{lifecycle}</span>,
                    item.service_class,
                    String(item.priority),
                    routeIntentNodeSelector(item.source_selector || {}),
                    routeIntentNodeSelector(item.destination_selector || {}),
                    item.policy_expires_at ? formatDate(item.policy_expires_at) : "нет",
                    formatDate(item.updated_at),
                    <div className="inlineActions">
                      {lifecycle === "active" ? (
                        <button
                          type="button"
                          className="ghost"
                          onClick={() =>
                            void runAction(
                              () => client.expireRouteIntent(selectedClusterId, item.id, "operator expired stale route intent"),
                              "Route intent expired.",
                            )
                          }
                        >
                          expire
                        </button>
                      ) : (
                        <span className="muted">expire</span>
                      )}
                      {lifecycle !== "disabled" ? (
                        <button
                          type="button"
                          className="ghost"
                          onClick={() =>
                            void runAction(
                              () => client.disableRouteIntent(selectedClusterId, item.id, "operator disabled route intent"),
                              "Route intent disabled.",
                            )
                          }
                        >
                          disable
                        </button>
                      ) : (
                        <span className="muted">disable</span>
                      )}
                    </div>,
                  ];
                })}
              />
              {routeIntents.length === 0 && <EmptyState title="Route intents отсутствуют" text="Нет настроенных fabric route intents для текущего кластера." />}
            </article>
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>Service-channel route feedback</h3>
                  <p className="muted">
                    Cluster-level runtime feedback from the shared fabric channel. Fenced and no-alternate cases affect route selection for any service class.
                  </p>
                </div>
                <div className="summaryChips">
                  <span className={fabricFeedbackFenced.length > 0 ? "pill bad" : "pill good"}>fenced {fabricFeedbackFenced.length}</span>
                  <span className={fabricFeedbackDegraded.length > 0 ? "pill warn" : "pill"}>degraded {fabricFeedbackDegraded.length}</span>
                  <span className={fabricFeedbackRetryCooldown.length > 0 ? "pill warn" : "pill"}>retry {fabricFeedbackRetryCooldown.length}</span>
                  <span className={fabricFeedbackRecovered.length > 0 ? "pill warn" : "pill"}>recovered {fabricFeedbackRecovered.length}</span>
                  <span className={fabricFeedbackPromoted.length > 0 ? "pill good" : "pill"}>promoted {fabricFeedbackPromoted.length}</span>
                  <span className={fabricFeedbackDemoted.length > 0 ? "pill bad" : "pill"}>demoted {fabricFeedbackDemoted.length}</span>
                  <span className="pill good">healthy {fabricFeedbackHealthy.length}</span>
                  <span className={fabricNoAlternateDecisions.length > 0 ? "pill bad" : "pill"}>no alternate {fabricNoAlternateDecisions.length}</span>
                  <span className={fabricRecoveryHysteresisDecisions.length > 0 ? "pill warn" : "pill"}>hysteresis {fabricRecoveryHysteresisDecisions.length}</span>
                  <span className={fabricRecoveryPromotedDecisions.length > 0 ? "pill good" : "pill"}>promoted paths {fabricRecoveryPromotedDecisions.length}</span>
                  <span className={fabricRecoveryDemotedDecisions.length > 0 ? "pill bad" : "pill"}>demoted paths {fabricRecoveryDemotedDecisions.length}</span>
                  <span className={(fabricRecoveryPolicy?.fingerprint || "").length > 0 ? "pill good" : "pill warn"}>policy fp {fabricRecoveryPolicy?.fingerprint ? shortId(fabricRecoveryPolicy.fingerprint) : "нет"}</span>
                  <span className={fabricRebuildDecisions.length > fabricRebuildAppliedDecisions.length ? "pill warn" : "pill good"}>
                    rebuild {fabricRebuildAppliedDecisions.length}/{fabricRebuildDecisions.length}
                  </span>
                  <span className={fabricRebuildPendingAttempts.length > 0 ? "pill warn" : "pill good"}>
                    ledger {fabricRebuildAppliedAttempts.length}/{fabricRebuildAttempts.length}
                  </span>
                  <span className={fabricRebuildGuardAlerts.length > 0 ? "pill bad" : "pill good"}>guard {fabricRebuildGuardAlerts.length}</span>
                  <span className={fabricRebuildLedgerDeep ? "pill info" : "pill"}>{fabricRebuildLedgerDeep ? "deep ledger" : "fast ledger"}</span>
                </div>
              </div>
              {fabricNoAlternateDecisions.length > 0 && (
                <div className="noticePanel">
                  Есть service-channel route без unfenced alternate. Для production-сервиса это означает деградацию: fabric не нашел безопасную замену и будет ждать нового маршрута или операторского решения.
                </div>
              )}
              {fabricSchemaStatus && (
                <div className={`noticePanel ${fabricSchemaStatus.status === "blocked" ? "badPanel" : "goodPanel"}`}>
                  <div className="cardHead compact">
                    <div>
                      <h4>Fabric schema preflight</h4>
                      <p className="muted">
                        Fabric schema contract check before diagnostics or service channels use new fields.
                      </p>
                    </div>
                    <div className="summaryChips">
                      <span className={`pill ${fabricSchemaStatus.status === "blocked" ? "bad" : "good"}`}>
                        {statusLabel(fabricSchemaStatus.status)}
                      </span>
                      <span className={fabricSchemaStatus.missing_check_count > 0 ? "pill bad" : "pill good"}>
                        {fabricSchemaStatus.passed_check_count}/{fabricSchemaStatus.required_check_count}
                      </span>
                      <button className="ghost" onClick={() => void warmupFabricRebuildSnapshots()} disabled={loading}>
                        warm snapshots
                      </button>
                    </div>
                  </div>
                  <div className="stateList">
                    <StateLine label="reason" value={statusLabel(fabricSchemaStatus.reason)} />
                    <StateLine label="required" value={fabricSchemaStatus.required_migration} />
                    <StateLine label="missing" value={(fabricSchemaStatus.missing_checks || []).map((item) => item.check_id).slice(0, 4).join(", ") || "нет"} />
                    <StateLine label="action" value={fabricSchemaStatus.recommended_operator_action || "schema is compatible"} />
                    {fabricSnapshotWarmup && (
                      <StateLine
                        label="warmup"
                        value={`warmed ${fabricSnapshotWarmup.warmed_count}, fresh ${fabricSnapshotWarmup.already_fresh_count}, missing ${fabricSnapshotWarmup.missing_snapshot_count}, stale ${fabricSnapshotWarmup.stale_snapshot_count}, deferred ${fabricSnapshotWarmup.deferred_stale_count}, errors ${fabricSnapshotWarmup.error_count}`}
                      />
                    )}
                  </div>
                </div>
              )}
              {fabricSnapshotHealth && (
                <div className={`noticePanel ${fabricSnapshotHealth.status === "degraded" ? "warnPanel" : "goodPanel"}`}>
                  <div className="cardHead compact">
                    <div>
                      <h4>Snapshot maintenance</h4>
                      <p className="muted">
                        Auto-warmup visibility for rebuild snapshot cache after node heartbeats.
                      </p>
                    </div>
                    <div className="summaryChips">
                      <span className={`pill ${fabricSnapshotHealth.status === "degraded" ? "warn" : "good"}`}>
                        {statusLabel(fabricSnapshotHealth.status)}
                      </span>
                      <span className={fabricSnapshotHealth.overdue_missing_snapshot_count > 0 ? "pill bad" : "pill good"}>
                        overdue {fabricSnapshotHealth.overdue_missing_snapshot_count}
                      </span>
                      <span className={fabricSnapshotHealth.auto_warmup_error_count > 0 ? "pill bad" : "pill good"}>
                        auto errors {fabricSnapshotHealth.auto_warmup_error_count}
                      </span>
                    </div>
                  </div>
                  <div className="stateList">
                    <StateLine label="reason" value={statusLabel(fabricSnapshotHealth.reason)} />
                    <StateLine label="snapshots" value={`valid ${fabricSnapshotHealth.valid_snapshot_count}, missing ${fabricSnapshotHealth.missing_snapshot_count}, attempts ${fabricSnapshotHealth.recent_attempt_count}`} />
                    <StateLine label="auto-warmup" value={`events ${fabricSnapshotHealth.auto_warmup_event_count}, warmed ${fabricSnapshotHealth.auto_warmup_warmed_count}, fresh ${fabricSnapshotHealth.auto_warmup_already_fresh_count}, latest ${formatDate(fabricSnapshotHealth.latest_auto_warmup_at)}`} />
                    <StateLine label="guard" value={`age ${fabricSnapshotHealth.min_age_seconds}s, heartbeats ${fabricSnapshotHealth.heartbeat_threshold}`} />
                    <StateLine label="action" value={fabricSnapshotHealth.recommended_operator_action || "snapshot maintenance is current"} />
                  </div>
                  {(fabricSnapshotHealth.nodes || []).length > 0 && (
                    <DataTable
                      columns={["node", "snapshots", "heartbeat", "auto-warmup", "latest"]}
                      rows={(fabricSnapshotHealth.nodes || []).slice(0, 6).map((item) => [
                        nodeName(nodes, item.node_id),
                        <span className={item.overdue_missing_snapshot_count > 0 ? "pill bad" : item.missing_snapshot_count > 0 ? "pill warn" : "pill good"}>
                          {item.valid_snapshot_count}/{item.recent_attempt_count} overdue {item.overdue_missing_snapshot_count}
                        </span>,
                        item.heartbeat_after_attempt_count,
                        `${item.auto_warmup_warmed_count}/${item.auto_warmup_event_count} errors ${item.auto_warmup_error_count}`,
                        formatDate(item.latest_auto_warmup_at || item.last_heartbeat_at),
                      ])}
                    />
                  )}
                </div>
              )}
              {fabricLeaseMaintenance && (
                <div className={`noticePanel ${fabricLeaseMaintenance.status === "degraded" ? "warnPanel" : "goodPanel"}`}>
                  <div className="cardHead compact">
                    <div>
                      <h4>Service-channel leases</h4>
                      <p className="muted">
                        Durable fabric lease records for route introspection after control-service restarts.
                      </p>
                    </div>
                    <div className="summaryChips">
                      <span className={`pill ${fabricLeaseMaintenance.status === "degraded" ? "warn" : "good"}`}>
                        {statusLabel(fabricLeaseMaintenance.status)}
                      </span>
                      <span className="pill good">active {fabricLeaseMaintenance.active_count}</span>
                      <span className={fabricLeaseMaintenance.expired_count > 0 ? "pill warn" : "pill"}>expired {fabricLeaseMaintenance.expired_count}</span>
                      <button className="ghost" onClick={() => void cleanupFabricServiceChannelLeases()} disabled={loading}>
                        cleanup
                      </button>
                    </div>
                  </div>
                  <div className="stateList">
                    <StateLine label="reason" value={statusLabel(fabricLeaseMaintenance.reason)} />
                    <StateLine label="scanned" value={`${fabricLeaseMaintenance.scanned_count}/${fabricLeaseMaintenance.window_limit}`} />
                    <StateLine label="deleted" value={String(fabricLeaseMaintenance.deleted_expired_count || 0)} />
                    <StateLine label="action" value={fabricLeaseMaintenance.recommended_operator_action || "lease maintenance is current"} />
                  </div>
                  {(fabricLeaseMaintenance.leases || []).length > 0 && (
                    <DataTable
                      columns={["expires", "resource", "entry", "exit", "route", "data plane", "state"]}
                      rows={(fabricLeaseMaintenance.leases || []).slice(0, 8).map((lease) => [
                        formatDate(lease.expires_at),
                        lease.resource_id || shortId(lease.channel_id),
                        nodeName(nodes, lease.selected_entry_node_id || ""),
                        nodeName(nodes, lease.selected_exit_node_id || ""),
                        lease.primary_route_id ? `${shortId(lease.primary_route_id)} / ${statusLabel(lease.primary_route_status || "")}` : "degraded route",
                        `${statusLabel(lease.data_plane?.working_data_transport || "unknown")} / ${statusLabel(lease.data_plane?.backend_relay_policy || "unknown")}`,
                        <span className={`pill ${lease.expired ? "warn" : lease.force_degraded_route ? "warn" : "good"}`}>
                          {lease.expired ? "expired" : lease.force_degraded_route ? "degraded route" : statusLabel(lease.status)}
                        </span>,
                      ])}
                    />
                  )}
                </div>
              )}
              {fabricAccessTelemetry && (
                <div className={`noticePanel ${fabricAccessTelemetry.status === "degraded" ? "warnPanel" : "goodPanel"}`}>
                  <div className="cardHead compact">
                    <div>
                      <h4>Service-channel access</h4>
                      <p className="muted">
                        Live accepted_by visibility from node telemetry and heartbeat metadata.
                      </p>
                    </div>
                    <div className="summaryChips">
                      <span className={`pill ${fabricAccessTelemetry.status === "degraded" ? "warn" : "good"}`}>
                        {statusLabel(fabricAccessTelemetry.status)}
                      </span>
                      <span className="pill good">accepted {fabricAccessTelemetry.total_accepted}</span>
                      <span className={fabricAccessTelemetry.degraded_route_use_count > 0 ? "pill warn" : "pill"}>
                        degraded {fabricAccessTelemetry.degraded_route_use_count}
                      </span>
                      <span className={(fabricAccessTelemetry.degraded_route_blocked_count ?? 0) > 0 ? "pill bad" : "pill"}>
                        blocked {fabricAccessTelemetry.degraded_route_blocked_count ?? 0}
                      </span>
                      <span className={`pill ${fabricAccessTelemetry.last_working_data_transport === "fabric_service_channel" ? "good" : fabricAccessTelemetry.data_plane_contract_count ? "warn" : ""}`}>
                        data-plane {fabricAccessTelemetry.data_plane_contract_count || 0}
                      </span>
                      <span className={`pill ${fabricAccessTelemetry.last_degraded_route_policy === "disabled" ? "good" : fabricAccessTelemetry.last_degraded_route_policy === "degraded_fallback_only" ? "info" : ""}`}>
                        route {statusLabel(fabricAccessTelemetry.last_degraded_route_policy || "unknown")}
                      </span>
                      <span className={fabricAccessTelemetry.degraded_fallback_channel_count > 0 || fabricAccessTelemetry.degraded_route_count > 0 ? "pill warn" : "pill good"}>
                        channels {fabricAccessTelemetry.active_channel_count}
                      </span>
                      <span className={fabricAccessTelemetry.no_safe_recovery_decision_count ? "pill warn" : fabricAccessTelemetry.route_decision_channel_count ? "pill info" : "pill"}>
                        decisions {fabricAccessTelemetry.route_decision_channel_count || 0}
                        {fabricAccessTelemetry.replacement_decision_count ? ` / repl ${fabricAccessTelemetry.replacement_decision_count}` : ""}
                        {fabricAccessTelemetry.applied_rebuild_decision_count ? ` / applied ${fabricAccessTelemetry.applied_rebuild_decision_count}` : ""}
                        {fabricAccessTelemetry.recovery_decision_count ? ` / recovery ${fabricAccessTelemetry.recovery_decision_count}` : ""}
                        {fabricAccessTelemetry.no_safe_recovery_decision_count ? ` / no-safe ${fabricAccessTelemetry.no_safe_recovery_decision_count}` : ""}
                      </span>
                      <span className={`pill ${flowHealthPillClass(fabricAccessTelemetry.flow_health_status, fabricAccessTelemetry.flow_dropped)}`}>
                        {formatTrafficClassCounts(fabricAccessTelemetry.traffic_class_counts)}
                      </span>
                      <span className={`pill ${flowHealthPillClass(fabricAccessTelemetry.flow_health_status, fabricAccessTelemetry.flow_dropped)}`}>
                        flow {statusLabel(fabricAccessTelemetry.flow_health_status || "healthy")}
                      </span>
                      <span className={`pill ${fabricAccessTelemetry.adaptive_backpressure_active ? "info" : "good"}`}>
                        windows {formatRecommendedWindows(fabricAccessTelemetry.recommended_parallel_windows)}
                      </span>
                    </div>
                  </div>
                  <div className="stateList">
                    <StateLine label="reason" value={statusLabel(fabricAccessTelemetry.reason)} />
                    <StateLine label="reporting nodes" value={`${fabricAccessTelemetry.reporting_node_count}/${fabricAccessTelemetry.node_count}`} />
                    <StateLine label="accepted by" value={`signed ${fabricAccessTelemetry.signed_accepted}, introspection ${fabricAccessTelemetry.introspection_accepted}, unsigned ${fabricAccessTelemetry.unsigned_accepted}`} />
                    <StateLine label="data plane" value={`${fabricAccessTelemetry.data_plane_contract_count || 0} contracts, mode ${statusLabel(fabricAccessTelemetry.last_data_plane_mode || "unknown")}, working ${statusLabel(fabricAccessTelemetry.last_working_data_transport || "unknown")}, steady ${statusLabel(fabricAccessTelemetry.last_steady_state_transport || "unknown")}, degraded ${statusLabel(fabricAccessTelemetry.last_degraded_route_policy || "unknown")}, flows ${statusLabel(fabricAccessTelemetry.last_logical_flow_mode || "unknown")}, blocked ${fabricAccessTelemetry.degraded_route_blocked_count ?? 0}, route failures ${fabricAccessTelemetry.fabric_route_send_failure_count || 0}`} />
                    <StateLine label="data-plane violation" value={fabricAccessTelemetry.last_data_plane_violation_status ? `${statusLabel(fabricAccessTelemetry.last_data_plane_violation_status)} / ${fabricAccessTelemetry.last_data_plane_violation_reason || "n/a"}` : "none"} />
                    <StateLine label="active channels" value={`${fabricAccessTelemetry.active_channel_count || 0}, degraded ${fabricAccessTelemetry.degraded_fallback_channel_count || 0}, correlated routes ${fabricAccessTelemetry.correlated_route_count || 0}, degraded routes ${fabricAccessTelemetry.degraded_route_count || 0}`} />
                    <StateLine label="route decisions" value={`channels ${fabricAccessTelemetry.route_decision_channel_count || 0}, replacement ${fabricAccessTelemetry.replacement_decision_count || 0}, applied ${fabricAccessTelemetry.applied_rebuild_decision_count || 0}, recovery ${fabricAccessTelemetry.recovery_decision_count || 0}, no-safe ${fabricAccessTelemetry.no_safe_recovery_decision_count || 0}`} />
                    <StateLine label="flow QoS" value={`${statusLabel(fabricAccessTelemetry.flow_health_status || "healthy")} / ${statusLabel(fabricAccessTelemetry.flow_health_reason || "flow_health_ready")}, ${formatTrafficClassCounts(fabricAccessTelemetry.traffic_class_counts)}, flows ${fabricAccessTelemetry.flow_channel_count || 0}, in-flight ${fabricAccessTelemetry.flow_max_in_flight || 0}, dropped ${fabricAccessTelemetry.flow_dropped || 0}`} />
                    <StateLine label="adaptive windows" value={`${fabricAccessTelemetry.adaptive_backpressure_active ? statusLabel(fabricAccessTelemetry.adaptive_backpressure_reason || "adaptive") : "off"}, ${formatRecommendedWindows(fabricAccessTelemetry.recommended_parallel_windows)}, policy ${fabricAccessTelemetry.adaptive_policy_fingerprint ? shortId(fabricAccessTelemetry.adaptive_policy_fingerprint) : "n/a"}`} />
                    <StateLine label="latest accepted" value={formatDate(fabricAccessTelemetry.latest_accepted_at)} />
                    <StateLine label="action" value={fabricAccessTelemetry.recommended_operator_action || "access telemetry is current"} />
                  </div>
                  {(fabricAccessTelemetry.active_channels || []).length > 0 && (
                    <DataTable
                      columns={["resource", "entry -> exit", "route", "decision", "entry access", "data plane", "flow health", "windows", "flow QoS", "route quality", "remediation", "guard", "execution", "expires"]}
                      rows={(fabricAccessTelemetry.active_channels || []).slice(0, 10).map((item) => [
                        item.resource_id || shortId(item.channel_id),
                        `${nodeName(nodes, item.selected_entry_node_id || "")} -> ${nodeName(nodes, item.selected_exit_node_id || "")}`,
                        item.primary_route_id ? `${shortId(item.primary_route_id)} / ${statusLabel(item.primary_route_status || "")}` : "degraded route",
                        <span className={`pill ${routeDecisionTone(item.route_decision_source, item.route_decision_rebuild_status, item.route_decision_score_reasons)}`}>
                          {item.route_decision_source
                            ? `${statusLabel(item.route_decision_source)}${item.route_decision_route_id ? ` ${shortId(item.route_decision_route_id)}` : ""}${item.route_decision_replacement_route_id ? ` -> ${shortId(item.route_decision_replacement_route_id)}` : ""}${item.route_decision_rebuild_status ? ` / ${statusLabel(item.route_decision_rebuild_status)}` : ""}`
                            : "n/a"}
                        </span>,
                        `accepted ${item.entry_node_total_accepted}, introspection ${item.entry_node_introspection_accepted}, degraded ${item.entry_node_degraded_route_count}`,
                        <span className={`pill ${item.entry_node_last_working_data_transport === "fabric_service_channel" ? "good" : item.entry_node_data_plane_contract_count ? "warn" : ""}`}>
                          {`${item.entry_node_data_plane_contract_count || 0} / ${statusLabel(item.entry_node_last_working_data_transport || "unknown")} / ${statusLabel(item.entry_node_last_degraded_route_policy || "unknown")}${item.entry_node_degraded_route_blocked_count ? ` / blocked ${item.entry_node_degraded_route_blocked_count}` : ""}`}
                        </span>,
                        <span className={`pill ${flowHealthPillClass(item.entry_node_flow_health_status, item.entry_node_flow_dropped)}`}>
                          {statusLabel(item.entry_node_flow_health_status || "healthy")}
                          {item.entry_node_flow_health_reason ? ` / ${statusLabel(item.entry_node_flow_health_reason)}` : ""}
                        </span>,
                        <span className={`pill ${item.entry_node_adaptive_backpressure_active ? "info" : "good"}`}>
                          {formatRecommendedWindows(item.entry_node_recommended_parallel_windows)}
                        </span>,
                        <span className={`pill ${flowHealthPillClass(item.entry_node_flow_health_status, item.entry_node_flow_dropped)}`}>
                          {formatTrafficClassCounts(item.entry_node_traffic_class_counts)}
                          {` / flows ${item.entry_node_flow_channel_count || 0} / in ${item.entry_node_flow_max_in_flight || 0}`}
                        </span>,
                        <span className={`pill ${item.force_degraded_route || item.route_feedback_status === "degraded" || item.route_feedback_status === "fenced" ? "warn" : item.route_feedback_status ? "good" : ""}`}>
                          {item.force_degraded_route
                            ? "degraded route"
                            : item.route_feedback_status
                              ? `${statusLabel(item.route_feedback_status)} / ${item.last_send_duration_ms || 0}ms / q ${item.route_quality_window_sample_count || 0}`
                              : "no route feedback"}
                        </span>,
                        <span className={`pill ${item.remediation_action === "none" ? "good" : item.remediation_action === "prefer_alternate_route" ? "warn" : item.remediation_action ? "bad" : ""}`}>
                          {item.remediation_action
                            ? `${item.remediation_command ? "cmd " : ""}${statusLabel(item.remediation_action)}${item.remediation_command?.replacement_route_id ? ` -> ${shortId(item.remediation_command.replacement_route_id)}` : item.remediation_route_id ? ` -> ${shortId(item.remediation_route_id)}` : ""}`
                            : "n/a"}
                        </span>,
                        <span className={`pill ${item.remediation_guard_status === "rejected" ? "bad" : item.pool_policy_fingerprint ? "good" : ""}`}>
                          {item.remediation_guard_status ? statusLabel(item.remediation_guard_status) : item.pool_policy_fingerprint ? "pool policy" : "n/a"}
                          {item.remediation_guard_reason ? ` / ${statusLabel(item.remediation_guard_reason)}` : ""}
                        </span>,
                        <span className={`pill ${remediationExecutionTone(item.remediation_execution_status)}`}>
                          {item.remediation_execution_status ? statusLabel(item.remediation_execution_status) : "n/a"}
                          {item.remediation_execution_generation ? ` / ${shortId(item.remediation_execution_generation)}` : ""}
                          {item.remediation_execution_reason ? ` / ${statusLabel(item.remediation_execution_reason)}` : ""}
                        </span>,
                        formatDate(item.expires_at),
                      ])}
                    />
                  )}
                  {(fabricAccessTelemetry.nodes || []).length > 0 && (
                    <DataTable
                        columns={["node", "accepted", "signed", "introspection", "unsigned", "degraded", "data plane", "flow health", "windows", "flow QoS", "latest"]}
                      rows={(fabricAccessTelemetry.nodes || []).slice(0, 10).map((item) => [
                        nodeName(nodes, item.node_id) || item.node_name || shortId(item.node_id),
                        item.total_accepted,
                        item.signed_accepted,
                        item.introspection_accepted,
                        item.unsigned_accepted,
                        <span className={item.degraded_route_use_count > 0 ? "pill warn" : "pill"}>
                          {item.degraded_route_use_count}
                        </span>,
                        <span className={`pill ${item.last_working_data_transport === "fabric_service_channel" ? "good" : item.data_plane_contract_count ? "warn" : ""}`}>
                          {`${item.data_plane_contract_count || 0} / ${statusLabel(item.last_working_data_transport || "unknown")} / ${statusLabel(item.last_degraded_route_policy || "unknown")}${item.degraded_route_blocked_count ? ` / blocked ${item.degraded_route_blocked_count}` : ""}`}
                        </span>,
                        <span className={`pill ${flowHealthPillClass(item.flow_health_status, item.flow_dropped)}`}>
                          {statusLabel(item.flow_health_status || "healthy")}
                          {item.flow_health_reason ? ` / ${statusLabel(item.flow_health_reason)}` : ""}
                        </span>,
                        <span className={`pill ${item.adaptive_backpressure_active ? "info" : "good"}`}>
                          {formatRecommendedWindows(item.recommended_parallel_windows)}
                        </span>,
                        <span className={`pill ${flowHealthPillClass(item.flow_health_status, item.flow_dropped)}`}>
                          {formatTrafficClassCounts(item.traffic_class_counts)}
                          {` / flows ${item.flow_channel_count || 0} / in ${item.flow_max_in_flight || 0}`}
                        </span>,
                        formatDate(item.last_accepted_at || item.observed_at),
                      ])}
                    />
                  )}
                </div>
              )}
              {fabricReadiness && (
                <div className={`noticePanel ${fabricReadiness.status === "blocked" ? "badPanel" : fabricReadiness.status === "degraded" ? "warnPanel" : "goodPanel"}`}>
                  <div className="cardHead compact">
                    <div>
                      <h4>Fabric service-channel readiness</h4>
                      <p className="muted">
                        Verdict for production service-channel use. Working service payloads should not depend on this fabric while the gate is blocked.
                      </p>
                    </div>
                    <div className="summaryChips">
                      <span className={`pill ${fabricReadiness.status === "blocked" ? "bad" : fabricReadiness.status === "degraded" ? "warn" : "good"}`}>
                        {statusLabel(fabricReadiness.status)}
                      </span>
                      <span className={fabricReadiness.active_alert_count > 0 ? "pill bad" : "pill"}>active {fabricReadiness.active_alert_count}</span>
                      <span className={fabricReadiness.resurfaced_count > 0 ? "pill bad" : "pill"}>resurfaced {fabricReadiness.resurfaced_count}</span>
                    </div>
                  </div>
                  <div className="stateList">
                    <StateLine label="reason" value={statusLabel(fabricReadiness.reason)} />
                    <StateLine label="blocking" value={(fabricReadiness.blocking_reasons || []).map(statusLabel).join(", ") || "нет"} />
                    <StateLine label="degraded" value={(fabricReadiness.degraded_reasons || []).map(statusLabel).join(", ") || "нет"} />
                    <StateLine label="missing/post" value={`transition ${fabricReadiness.missing_transition_count}, route-gen ${fabricReadiness.missing_route_generation_count}, traffic ${fabricReadiness.missing_post_rebuild_traffic_count}`} />
                  </div>
                </div>
              )}
              {fabricRebuildIncidents.length > 0 && (
                <div className="subPanel">
                  <div className="cardHead compact">
                    <div>
                      <h4>Rebuild incidents</h4>
                      <p className="muted">
                        Grouped recent rebuild attempts by reporter, route, service, generation, and guard. Open an incident to load the exact deep ledger slice.
                      </p>
                    </div>
                    <span className="pill">{fabricRebuildIncidents.length}</span>
                  </div>
                  <DataTable
                    columns={["last", "source", "reporter", "route", "service", "guard", "count", "replacement", "action"]}
                    rows={fabricRebuildIncidents.slice(0, 10).map((incident) => [
                      formatDate(incident.last_seen_at),
                      incident.incident_source ? statusLabel(incident.incident_source) : "ledger",
                      nodeName(nodes, incident.reporter_node_id),
                      shortId(incident.route_id),
                      incident.service_class,
                      <span className={`pill ${incident.alert_resurfaced ? "bad" : incident.guard_severity === "bad" ? "bad" : incident.guard_severity === "warn" ? "warn" : "good"}`}>
                        {statusLabel(incident.guard_status)}{incident.alert_silenced ? " / silenced" : incident.alert_resurfaced ? " / resurfaced" : ""}
                      </span>,
                      String(incident.attempt_count),
                      incident.latest_replacement_route_id ? shortId(incident.latest_replacement_route_id) : "нет",
                      <div className="inlineActions">
                        <span>
                          {statusLabel(incident.recommended_operator_action || "inspect")}
                          {incident.alert_resurfaced && incident.alert_resurfaced_cause
                            ? ` (${statusLabel(incident.alert_resurfaced_cause)})`
                            : ""}
                          {incident.alert_resurfaced && incident.alert_resurfaced_previous_generation
                            ? ` from ${shortId(incident.alert_resurfaced_previous_generation)} until ${formatDate(incident.alert_resurfaced_previous_until)}`
                            : ""}
                        </span>
                        <button
                          type="button"
                          className="ghost"
                          onClick={() => void runAction(() => openFabricRebuildIncidentDeepLedger(incident), "Deep rebuild investigation opened.")}
                        >
                          open deep
                        </button>
                        {!incident.alert_silenced ? (
                          <button
                            type="button"
                            className="ghost"
                            onClick={() => void runAction(() => silenceFabricRebuildIncident(incident), "Rebuild incident silenced for 6 hours.")}
                          >
                            silence 6h
                          </button>
                        ) : (
                          <span className="muted">silenced</span>
                        )}
                      </div>,
                    ])}
                  />
                </div>
              )}
              {(fabricBreadcrumbWindowPolicy || fabricDrilldownAuditEvents.length > 0) && (
                <div className="subPanel">
                  <div className="cardHead compact">
                    <div>
                      <h4>Recent investigations</h4>
                      <p className="muted">
                        Recent operator drilldowns opened from rebuild incidents or feedback breakdown rows.
                      </p>
                    </div>
                    <div className="summaryChips">
                      <span className="pill info">{fabricDrilldownAuditSummary?.total_count || fabricDrilldownAuditEvents.length}</span>
                      <span className="pill good">linked {fabricDrilldownAuditSummary?.correlated_count || 0}</span>
                      <span className={(fabricDrilldownAuditSummary?.not_visible_count || 0) > 0 ? "pill warn" : "pill"}>
                        not visible {fabricDrilldownAuditSummary?.not_visible_count || 0}
                      </span>
                      {Object.entries(fabricDrilldownAuditSummary?.counts_by_breadcrumb_status || {}).map(([status, count]) => (
                        <span key={status} className={status === "current" ? "pill good" : status === "stale" ? "pill warn" : "pill bad"}>
                          {statusLabel(status)} {count}
                        </span>
                      ))}
                      {Object.entries(fabricDrilldownAuditSummary?.counts_by_current_diagnostic_status || {}).slice(0, 3).map(([status, count]) => (
                        <span key={status} className={status === "breakdown_active" || status === "incident_visible" ? "pill good" : status === "not_visible" ? "pill warn" : "pill"}>
                          {statusLabel(status)} {count}
                        </span>
                      ))}
                    </div>
                  </div>
                  {fabricBreadcrumbWindowPolicy && (
                    <div className="inlineForm">
                      <label>
                        current window, sec
                        <input
                          type="number"
                          min="60"
                          value={fabricBreadcrumbWindowPolicyForm.currentWindowSeconds}
                          onChange={(event) => setFabricBreadcrumbWindowPolicyForm((form) => ({ ...form, currentWindowSeconds: event.target.value }))}
                        />
                      </label>
                      <label>
                        history window, sec
                        <input
                          type="number"
                          min="60"
                          value={fabricBreadcrumbWindowPolicyForm.historyWindowSeconds}
                          onChange={(event) => setFabricBreadcrumbWindowPolicyForm((form) => ({ ...form, historyWindowSeconds: event.target.value }))}
                        />
                      </label>
                      <button
                        type="button"
                        className="ghost"
                        onClick={() =>
                          void runAction(async () => {
                            const updated = await client.updateFabricServiceChannelBreadcrumbWindowPolicy(selectedClusterId, {
                              currentWindowSeconds: Number(fabricBreadcrumbWindowPolicyForm.currentWindowSeconds),
                              historyWindowSeconds: Number(fabricBreadcrumbWindowPolicyForm.historyWindowSeconds),
                            });
                            setFabricBreadcrumbWindowPolicy(updated);
                            const drilldownAudit = await client.getFabricServiceChannelRebuildInvestigationBreadcrumbs(selectedClusterId, { limit: 20 });
                            setFabricDrilldownAudit(drilldownAudit.events);
                            setFabricDrilldownAuditSummary(drilldownAudit.summary || null);
                          }, "Breadcrumb window policy updated.")
                        }
                      >
                        apply windows
                      </button>
                      <span className="muted">
                        source {fabricBreadcrumbWindowPolicy.source}, fp {shortId(fabricBreadcrumbWindowPolicy.fingerprint || "")}
                      </span>
                    </div>
                  )}
                  {fabricDrilldownAuditSummary && (
                    <div className="stateList">
                      <StateLine label="latest" value={formatDate(fabricDrilldownAuditSummary.latest_at)} />
                      <StateLine
                        label="windows"
                        value={`${fabricBreadcrumbWindowPolicy?.current_window_seconds || "n/a"}s current / ${fabricBreadcrumbWindowPolicy?.history_window_seconds || "n/a"}s history`}
                      />
                      <StateLine
                        label="sources"
                        value={
                          Object.entries(fabricDrilldownAuditSummary.counts_by_feedback_source || {})
                            .slice(0, 3)
                            .map(([source, count]) => `${statusLabel(source)} ${count}`)
                            .join(", ") || "нет"
                        }
                      />
                      <StateLine
                        label="violations"
                        value={
                          Object.entries(fabricDrilldownAuditSummary.counts_by_feedback_violation_status || {})
                            .slice(0, 3)
                            .map(([status, count]) => `${statusLabel(status)} ${count}`)
                            .join(", ") || "нет"
                        }
                      />
                    </div>
                  )}
                  <DataTable
                    columns={["time", "freshness", "source", "feedback", "target", "current", "actor", "reason"]}
                    rows={fabricDrilldownAuditEvents.map((event) => {
                      const payload = objectField(event.payload) || {};
                      const feedbackChannelID = stringField(payload, "feedback_channel_id", "");
                      const feedbackViolationStatus = stringField(payload, "feedback_violation_status", "");
                      const feedbackSource = stringField(payload, "feedback_source", "");
                      const reporterNodeID = stringField(payload, "reporter_node_id", "");
                      const routeID = stringField(payload, "route_id", "");
                      const drilldownSource = stringField(payload, "drilldown_source", "");
                      const hintStatus = event.correlation_hints?.current_diagnostic_status || "";
                      const breadcrumbStatus = event.correlation_hints?.breadcrumb_status || "current";
                      const breadcrumbAgeSeconds = event.correlation_hints?.breadcrumb_age_seconds;
                      const matchingBreakdown = event.correlation_hints?.feedback_breakdown || fabricFeedbackBreakdownForAuditEvent(event);
                      const matchingIncident = event.correlation_hints?.rebuild_incident || fabricRebuildIncidentForAuditEvent(event);
                      return [
                        formatDate(event.created_at),
                        <div className="stackedText">
                          <span className={breadcrumbStatus === "current" ? "pill good" : breadcrumbStatus === "stale" ? "pill warn" : "pill bad"}>
                            {statusLabel(breadcrumbStatus)}
                          </span>
                          <span className="muted">{formatAgeSeconds(breadcrumbAgeSeconds)}</span>
                        </div>,
                        <div className="stackedText">
                          <span>{event.event_type.includes("feedback_breakdown") ? "feedback breakdown" : "incident"}</span>
                          <span className="muted">{statusLabel(drilldownSource || event.target_type)}</span>
                        </div>,
                        feedbackSource || feedbackChannelID || feedbackViolationStatus ? (
                          <div className="stackedText">
                            <span>{statusLabel(feedbackSource || "feedback")}</span>
                            <span className="muted">{feedbackChannelID ? `ch ${shortId(feedbackChannelID)}` : "any channel"}</span>
                            <span className="muted">{statusLabel(feedbackViolationStatus || "any violation")}</span>
                          </div>
                        ) : (
                          <span className="muted">нет</span>
                        ),
                        <div className="stackedText">
                          <span>{reporterNodeID ? nodeName(nodes, reporterNodeID) : "any reporter"}</span>
                          <span className="muted">{routeID ? shortId(routeID) : event.target_id ? shortId(event.target_id) : "any route"}</span>
                        </div>,
                        matchingBreakdown ? (
                          <div className="inlineActions">
                            <span className={matchingBreakdown.active_bad_count ? "pill bad" : matchingBreakdown.active_warn_count ? "pill warn" : "pill good"}>
                              {statusLabel(hintStatus || "breakdown_active")}
                            </span>
                            <span className="muted">
                              bad {matchingBreakdown.active_bad_count || 0} / warn {matchingBreakdown.active_warn_count || 0}
                            </span>
                            <button
                              type="button"
                              className="ghost"
                              onClick={() => void runAction(() => openFabricRebuildFeedbackBreakdownLedger(matchingBreakdown), "Rebuild ledger opened for current feedback breakdown.")}
                            >
                              open
                            </button>
                          </div>
                        ) : matchingIncident ? (
                          <div className="inlineActions">
                            <span className={`pill ${matchingIncident.guard_severity === "bad" ? "bad" : matchingIncident.guard_severity === "warn" ? "warn" : "good"}`}>
                              {statusLabel(hintStatus || "incident_visible")}
                            </span>
                            <span className="muted">{statusLabel(matchingIncident.guard_status)}</span>
                            <button
                              type="button"
                              className="ghost"
                              onClick={() => void runAction(() => openFabricRebuildIncidentDeepLedger(matchingIncident), "Deep rebuild investigation opened for current incident.")}
                            >
                              open
                            </button>
                          </div>
                        ) : (
                          <span className="muted">{statusLabel(hintStatus || "not_visible")}</span>
                        ),
                        event.actor_user_id ? shortId(event.actor_user_id) : "system",
                        stringField(payload, "reason", "operator opened investigation"),
                      ];
                    })}
                  />
                </div>
              )}
              {fabricRebuildSilences.length > 0 && (
                <div className="subPanel">
                  <div className="cardHead compact">
                    <div>
                      <h4>Active rebuild silences</h4>
                      <p className="muted">
                        Operator acknowledgements currently suppressing rebuild/access-decision alerts. Remove a silence to let the incident become active again.
                      </p>
                    </div>
                    <span className="pill info">{fabricRebuildSilences.length}</span>
                  </div>
                  <DataTable
                    columns={["until", "source", "channel", "reporter", "route", "guard", "reason", "action"]}
                    rows={fabricRebuildSilences.slice(0, 10).map((silence) => [
                      formatDate(silence.expires_at),
                      silence.incident_source ? statusLabel(silence.incident_source) : "ledger",
                      silence.channel_id ? shortId(silence.channel_id) : "нет",
                      nodeName(nodes, silence.reporter_node_id),
                      shortId(silence.display_route_id || silence.route_id),
                      statusLabel(silence.guard_status),
                      silence.reason || "acknowledged",
                      <button
                        type="button"
                        className="ghost"
                        onClick={() => void runAction(() => unsilenceFabricRebuildAlert(silence), "Rebuild alert silence removed.")}
                      >
                        unsilence
                      </button>,
                    ])}
                  />
                </div>
              )}
              {fabricRebuildHealth && (
                <div className="subPanel">
                  <div className="cardHead compact">
                    <div>
                      <h4>Rebuild health</h4>
                      <p className="muted">
                        Сводка по последним {fabricRebuildHealth.total_attempts} rebuild попыткам. Данные помогают быстро увидеть, где backend уже принял решение, но node-agent или post-rebuild traffic не подтвердили результат.
                      </p>
                    </div>
                    <div className="summaryChips">
                      <span className="pill good">ok {fabricRebuildHealth.good_count}</span>
                      <span className={fabricRebuildHealth.active_warn_count > 0 ? "pill warn" : "pill"}>warn {fabricRebuildHealth.active_warn_count}/{fabricRebuildHealth.warn_count}</span>
                      <span className={fabricRebuildHealth.active_bad_count > 0 ? "pill bad" : "pill"}>bad {fabricRebuildHealth.active_bad_count}/{fabricRebuildHealth.bad_count}</span>
                      <span className={fabricRebuildHealth.resurfaced_count > 0 ? "pill bad" : "pill"}>resurfaced {fabricRebuildHealth.resurfaced_count}</span>
                      <span className={fabricRebuildHealth.silenced_count > 0 ? "pill info" : "pill"}>silenced {fabricRebuildHealth.silenced_count}</span>
                      <span className="pill">applied {fabricRebuildHealth.applied_count}</span>
                      <span className={fabricRebuildHealth.access_no_safe_count ? "pill bad" : fabricRebuildHealth.access_route_decision_count ? "pill info" : "pill"}>
                        access {fabricRebuildHealth.access_route_decision_count || 0}
                        {fabricRebuildHealth.access_no_safe_count ? ` / no-safe ${fabricRebuildHealth.access_no_safe_count}` : ""}
                      </span>
                    </div>
                  </div>
                  <div className="stateList">
                    <StateLine label="observed" value={formatDate(fabricRebuildHealth.observed_at)} />
                    <StateLine label="affected nodes" value={(fabricRebuildHealth.affected_reporter_node_ids || []).map((id) => nodeName(nodes, id)).join(", ") || "нет"} />
                    <StateLine label="affected routes" value={(fabricRebuildHealth.affected_route_ids || []).map(shortId).join(", ") || "нет"} />
                    <StateLine label="action" value={statusLabel(fabricRebuildHealth.recommended_operator_action || "no_operator_action_required")} />
                  </div>
                  {(fabricRebuildHealth.feedback_breakdowns || []).length > 0 && (
                    <DataTable
                      columns={["feedback", "active", "total", "affected", "incidents", "latest", "action"]}
                      rows={(fabricRebuildHealth.feedback_breakdowns || []).slice(0, 8).map((item) => {
                        const relatedIncidents = fabricRebuildIncidentsForFeedbackBreakdown(item);
                        return [
                          <div className="stackedText">
                            <span>{statusLabel(item.feedback_source || "feedback")}</span>
                            <span className="muted">{item.feedback_channel_id ? `ch ${shortId(item.feedback_channel_id)}` : "any channel"}</span>
                            <span className="muted">{statusLabel(item.feedback_violation_status || "unknown")}</span>
                          </div>,
                          <span className={item.active_bad_count ? "pill bad" : item.active_warn_count ? "pill warn" : "pill"}>
                            bad {item.active_bad_count || 0} / warn {item.active_warn_count || 0}
                          </span>,
                          `total ${item.total_count} / bad ${item.bad_count || 0} / warn ${item.warn_count || 0} / silenced ${item.silenced_count || 0}`,
                          <div className="stackedText">
                            <span>{(item.affected_reporter_node_ids || []).map((id) => nodeName(nodes, id)).join(", ") || "нет узлов"}</span>
                            <span className="muted">{(item.affected_route_ids || []).map(shortId).join(", ") || "нет routes"}</span>
                          </div>,
                          relatedIncidents.length > 0 ? (
                            <div className="stackedText">
                              <span className="pill warn">{relatedIncidents.length}</span>
                              <span className="muted">{relatedIncidents.slice(0, 2).map((incident) => statusLabel(incident.guard_status)).join(", ")}</span>
                            </div>
                          ) : (
                            <span className="muted">нет</span>
                          ),
                          formatDate(item.latest_observed_at),
                          <button
                            type="button"
                            className="ghost"
                            onClick={() => void runAction(() => openFabricRebuildFeedbackBreakdownLedger(item), "Rebuild ledger opened for feedback breakdown.")}
                          >
                            open ledger
                          </button>,
                        ];
                      })}
                    />
                  )}
                  {(fabricRebuildHealth.most_recent_bad_attempts || []).length > 0 && (
                    <DataTable
                      columns={["time", "reporter", "route", "guard", "reason"]}
                      rows={(fabricRebuildHealth.most_recent_bad_attempts || []).slice(0, 5).map((attempt) => [
                        formatDate(attempt.updated_at),
                        nodeName(nodes, attempt.reporter_node_id),
                        shortId(attempt.route_id),
                        <span className="pill bad">{statusLabel(attempt.guard_status || "bad")}</span>,
                        <div className="inlineActions">
                          <span>{statusLabel(attempt.guard_reason || "unknown")}</span>
                          <button
                            type="button"
                            className="ghost"
                            onClick={() =>
                              void runAction(
                                () =>
                                  client.silenceFabricServiceChannelRouteRebuildAlert(selectedClusterId, {
                                    reporterNodeId: attempt.reporter_node_id,
                                    routeId: attempt.route_id,
                                    guardStatus: attempt.guard_status || "unknown",
                                    generation: attempt.generation || "",
                                    reason: "operator acknowledged known rebuild alert",
                                    ttlSeconds: 21600,
                                  }),
                                "Rebuild alert silenced for this route generation.",
                              )
                            }
                          >
                            silence 6h
                          </button>
                        </div>,
                      ])}
                    />
                  )}
                  {(fabricRebuildHealth.resurfaced_attempts || []).length > 0 && (
                    <DataTable
                      columns={["time", "reporter", "route", "guard", "previous", "action"]}
                      rows={(fabricRebuildHealth.resurfaced_attempts || []).slice(0, 5).map((attempt) => [
                        formatDate(attempt.updated_at),
                        nodeName(nodes, attempt.reporter_node_id),
                        shortId(attempt.route_id),
                        <span className="pill bad">{statusLabel(attempt.guard_status || "bad")}</span>,
                        `${shortId(attempt.alert_resurfaced_previous_generation)} until ${formatDate(attempt.alert_resurfaced_previous_until)}`,
                        <div className="inlineActions">
                          <span>{statusLabel(attempt.guard_reason || "unknown")}</span>
                          <button
                            type="button"
                            className="ghost"
                            onClick={() =>
                              void runAction(
                                () =>
                                  client.silenceFabricServiceChannelRouteRebuildAlert(selectedClusterId, {
                                    reporterNodeId: attempt.reporter_node_id,
                                    routeId: attempt.route_id,
                                    guardStatus: attempt.guard_status || "unknown",
                                    generation: attempt.generation || "",
                                    reason: "operator acknowledged resurfaced rebuild alert",
                                    ttlSeconds: 21600,
                                  }),
                                "Resurfaced rebuild alert silenced for this generation.",
                              )
                            }
                          >
                            silence 6h
                          </button>
                        </div>,
                      ])}
                    />
                  )}
                </div>
              )}
              {fabricRecoveryPolicy && (
                <div className="inlineForm">
                  <label>
                    penalty
                    <input
                      type="number"
                      min="0"
                      value={fabricRecoveryPolicyForm.hysteresisPenalty}
                      onChange={(event) => setFabricRecoveryPolicyForm((form) => ({ ...form, hysteresisPenalty: event.target.value }))}
                    />
                  </label>
                  <label>
                    promote samples
                    <input
                      type="number"
                      min="1"
                      value={fabricRecoveryPolicyForm.promotionMinSamples}
                      onChange={(event) => setFabricRecoveryPolicyForm((form) => ({ ...form, promotionMinSamples: event.target.value }))}
                    />
                  </label>
                  <label>
                    fail
                    <input
                      type="number"
                      min="1"
                      value={fabricRecoveryPolicyForm.demotionFailureThreshold}
                      onChange={(event) => setFabricRecoveryPolicyForm((form) => ({ ...form, demotionFailureThreshold: event.target.value }))}
                    />
                  </label>
                  <label>
                    drop
                    <input
                      type="number"
                      min="1"
                      value={fabricRecoveryPolicyForm.demotionDropThreshold}
                      onChange={(event) => setFabricRecoveryPolicyForm((form) => ({ ...form, demotionDropThreshold: event.target.value }))}
                    />
                  </label>
                  <label>
                    slow
                    <input
                      type="number"
                      min="1"
                      value={fabricRecoveryPolicyForm.demotionSlowThreshold}
                      onChange={(event) => setFabricRecoveryPolicyForm((form) => ({ ...form, demotionSlowThreshold: event.target.value }))}
                    />
                  </label>
                  <label className="checkLine">
                    <input
                      type="checkbox"
                      checked={fabricRecoveryPolicyForm.demotionRebuildEnabled}
                      onChange={(event) => setFabricRecoveryPolicyForm((form) => ({ ...form, demotionRebuildEnabled: event.target.checked }))}
                    />
                    rebuild
                  </label>
                  <label className="checkLine">
                    <input
                      type="checkbox"
                      checked={fabricRecoveryPolicyForm.demotionFencedEnabled}
                      onChange={(event) => setFabricRecoveryPolicyForm((form) => ({ ...form, demotionFencedEnabled: event.target.checked }))}
                    />
                    fenced
                  </label>
                  <button
                    type="button"
                    className="ghost"
                    onClick={() =>
                      void runAction(async () => {
                        const updated = await client.updateFabricServiceChannelRecoveryPolicy(selectedClusterId, {
                          hysteresisPenalty: Number(fabricRecoveryPolicyForm.hysteresisPenalty),
                          promotionMinSamples: Number(fabricRecoveryPolicyForm.promotionMinSamples),
                          demotionFailureThreshold: Number(fabricRecoveryPolicyForm.demotionFailureThreshold),
                          demotionDropThreshold: Number(fabricRecoveryPolicyForm.demotionDropThreshold),
                          demotionSlowThreshold: Number(fabricRecoveryPolicyForm.demotionSlowThreshold),
                          demotionRebuildEnabled: fabricRecoveryPolicyForm.demotionRebuildEnabled,
                          demotionFencedEnabled: fabricRecoveryPolicyForm.demotionFencedEnabled,
                        });
                        setFabricRecoveryPolicy(updated);
                      }, "Recovery policy updated.")
                    }
                  >
                    apply policy
                  </button>
                  <span className="muted">source {fabricRecoveryPolicy.source}</span>
                </div>
              )}
              <DataTable
                columns={["route", "reporter", "service", "status", "recovery", "score", "reasons", "failures", "retry/cooldown", "expires", "action"]}
                rows={fabricRouteFeedbackVisible.slice(0, 80).map((item) => [
                  shortId(item.route_id),
                  nodeName(nodes, item.reporter_node_id),
                  item.service_class,
                  <span className={`pill ${serviceChannelFeedbackTone(item.feedback_status)}`}>{statusLabel(item.feedback_status)}</span>,
                  item.recovery_state ? (
                    <span className={`pill ${serviceChannelRecoveryTone(item.recovery_state)}`}>
                      {item.recovery_demoted ? `demoted ${item.recovery_reason ? statusLabel(item.recovery_reason) : ""}` : item.recovery_promoted ? "promoted" : statusLabel(item.recovery_state)}
                      {item.recovery_hysteresis_penalty ? ` -${item.recovery_hysteresis_penalty}` : ""}
                    </span>
                  ) : item.stale_policy || item.stale_generation ? (
                    <span className="pill warn">{statusLabel(item.stale_reason || "stale")}</span>
                  ) : item.provenance_missing ? (
                    <span className="pill warn">provenance missing</span>
                  ) : (
                    "нет"
                  ),
                  String(item.score_adjustment),
                  (item.reasons || []).join(", ") || "нет",
                  String(item.consecutive_failures || 0),
                  item.retry_cooldown_until ? formatDate(item.retry_cooldown_until) : "нет",
                  formatDate(item.expires_at),
                  item.feedback_status === "healthy" || item.feedback_status === "operator_retry_cooldown" ? (
                    <span className="muted">нет</span>
                  ) : (
                    <button
                      type="button"
                      className="ghost"
                      onClick={() =>
                        void runAction(
                          () =>
                            client.expireFabricServiceChannelRouteFeedback(selectedClusterId, {
                              routeId: item.route_id,
                              reporterNodeId: item.reporter_node_id,
                              serviceClass: item.service_class,
                              reason: "operator expired stale service-channel feedback",
                            }),
                          "Service-channel feedback expired.",
                        )
                      }
                    >
                      expire
                    </button>
                  ),
                ])}
              />
              {fabricRouteFeedbackVisible.length === 0 && <EmptyState title="Feedback отсутствует" text="Нет свежих route feedback наблюдений от fabric service-channel runtime." />}
              <DataTable
                columns={["local node", "route", "replacement", "rebuild", "attempt", "feedback", "source", "destination", "decision", "score", "expires"]}
                rows={[...fabricReplacementDecisions, ...fabricNoAlternateDecisions, ...fabricRebuildDecisions]
                  .filter((decision, index, all) => all.findIndex((item) => item.decision_id === decision.decision_id) === index)
                  .slice(0, 80)
                  .map((decision) => [
                  nodeName(nodes, decision.local_node_id),
                  shortId(decision.route_id),
                  decision.replacement_route_id ? shortId(decision.replacement_route_id) : "нет",
                  decision.rebuild_status || "нет",
                  decision.rebuild_attempt == null ? "н/д" : String(decision.rebuild_attempt),
                  decision.feedback_observation_id ? (
                    <div className="stackedText">
                      <span>{statusLabel(decision.feedback_source || "feedback")}</span>
                      <span className="muted">{shortId(decision.feedback_observation_id)} {decision.feedback_channel_id ? `ch ${shortId(decision.feedback_channel_id)}` : ""}</span>
                      <span className="muted">{statusLabel(decision.feedback_violation_status || "")}</span>
                    </div>
                  ) : "нет",
                  nodeName(nodes, decision.source_node_id),
                  nodeName(nodes, decision.destination_node_id),
                  decision.decision_source,
                  decision.path_score == null ? "н/д" : String(decision.path_score),
                  formatDate(decision.expires_at),
                ])}
              />
              <div className="inlineForm">
                <label>
                  reporter
                  <select
                    value={fabricRebuildLedgerFilters.reporterNodeId}
                    onChange={(event) => setFabricRebuildLedgerFilters((filters) => ({ ...filters, reporterNodeId: event.target.value, offset: 0 }))}
                  >
                    <option value="">all</option>
                    {nodes.map((node) => (
                      <option key={node.id} value={node.id}>{node.name}</option>
                    ))}
                  </select>
                </label>
                <label>
                  route
                  <input
                    value={fabricRebuildLedgerFilters.routeId}
                    onChange={(event) => setFabricRebuildLedgerFilters((filters) => ({ ...filters, routeId: event.target.value.trim(), offset: 0 }))}
                    placeholder="route id"
                  />
                </label>
                <label>
                  generation
                  <input
                    value={fabricRebuildLedgerFilters.generation}
                    onChange={(event) => setFabricRebuildLedgerFilters((filters) => ({ ...filters, generation: event.target.value.trim(), offset: 0 }))}
                    placeholder="route generation"
                  />
                </label>
                <label>
                  service
                  <input
                    value={fabricRebuildLedgerFilters.serviceClass}
                    onChange={(event) => setFabricRebuildLedgerFilters((filters) => ({ ...filters, serviceClass: event.target.value.trim(), offset: 0 }))}
                    placeholder="vpn_packets"
                  />
                </label>
                <label>
                  feedback source
                  <input
                    value={fabricRebuildLedgerFilters.feedbackSource}
                    onChange={(event) => setFabricRebuildLedgerFilters((filters) => ({ ...filters, feedbackSource: event.target.value.trim(), offset: 0 }))}
                    placeholder="fabric_service_channel_access_report"
                  />
                </label>
                <label>
                  channel
                  <input
                    value={fabricRebuildLedgerFilters.feedbackChannelId}
                    onChange={(event) => setFabricRebuildLedgerFilters((filters) => ({ ...filters, feedbackChannelId: event.target.value.trim(), offset: 0 }))}
                    placeholder="feedback channel id"
                  />
                </label>
                <label>
                  violation
                  <input
                    value={fabricRebuildLedgerFilters.feedbackViolationStatus}
                    onChange={(event) => setFabricRebuildLedgerFilters((filters) => ({ ...filters, feedbackViolationStatus: event.target.value.trim(), offset: 0 }))}
                    placeholder="fabric_route_send_failed_degraded_route_blocked"
                  />
                </label>
                <button type="button" className="ghost" onClick={() => void loadFabricRebuildLedger(fabricRebuildLedgerDeep, { ...fabricRebuildLedgerFilters, offset: 0 })}>
                  apply
                </button>
                <button
                  type="button"
                  className="ghost"
                  onClick={() => {
                    const cleared = { ...defaultFabricRebuildLedgerFilters };
                    setFabricRebuildLedgerFilters(cleared);
                    void loadFabricRebuildLedger(false, cleared);
                  }}
                >
                  clear
                </button>
              </div>
              <DataTable
                columns={["time", "reporter", "route", "replacement", "feedback", "guard", "outcome", "backend", "agent", "route-gen", "traffic", "policy", "hops"]}
                rows={fabricRebuildAttempts.slice(0, 80).map((attempt) => [
                  formatDate(attempt.updated_at),
                  nodeName(nodes, attempt.reporter_node_id),
                  shortId(attempt.route_id),
                  attempt.replacement_route_id ? shortId(attempt.replacement_route_id) : "нет",
                  attempt.feedback_observation_id ? (
                    <div className="stackedText">
                      <span>{statusLabel(attempt.feedback_source || "feedback")}</span>
                      <span className="muted">{shortId(attempt.feedback_observation_id)} {attempt.feedback_channel_id ? `ch ${shortId(attempt.feedback_channel_id)}` : ""}</span>
                      <span className="muted">{statusLabel(attempt.feedback_violation_status || "")}</span>
                    </div>
                  ) : attempt.feedback_status ? statusLabel(attempt.feedback_status) : "нет",
                  fabricRebuildLedgerDeep ? (
                    <span className={`pill ${attempt.guard_severity === "bad" ? "bad" : attempt.guard_severity === "warn" ? "warn" : "good"}`}>
                      {statusLabel(attempt.guard_status || "unknown")}{attempt.alert_silenced ? " / silenced" : attempt.alert_resurfaced ? " / resurfaced" : ""}
                    </span>
                  ) : (
                    <span className="pill info">summary</span>
                  ),
                  statusLabel(attempt.outcome),
                  <span className={`pill ${attempt.rebuild_status === "applied" ? "good" : "warn"}`}>{statusLabel(attempt.rebuild_status)}</span>,
                  !fabricRebuildLedgerDeep ? (
                    <span className="pill info">deep only</span>
                  ) : attempt.node_transition_matched ? (
                    <span className={`pill ${attempt.node_transition_status === "applied_rebuild" ? "good" : "warn"}`}>{statusLabel(attempt.node_transition_status || "matched")}</span>
                  ) : (
                    <span className="pill warn">not seen</span>
                  ),
                  !fabricRebuildLedgerDeep ? (
                    <span className="pill info">deep only</span>
                  ) : attempt.node_route_generation_matched ? (
                    <span className="pill good">{statusLabel(attempt.node_route_generation_status || "seen")}</span>
                  ) : (
                    <span className="pill warn">not seen</span>
                  ),
                  !fabricRebuildLedgerDeep
                    ? "deep only"
                    : attempt.post_rebuild_selected_route_id
                    ? `${shortId(attempt.post_rebuild_selected_route_id)} packets ${attempt.post_rebuild_send_flow_packets || attempt.post_rebuild_send_packets || 0} drop ${attempt.post_rebuild_send_flow_dropped || 0}`
                    : "нет",
                  attempt.policy_fingerprint ? shortId(attempt.policy_fingerprint) : "нет",
                  `${(attempt.old_hops || []).map((id) => nodeName(nodes, id)).join(" -> ") || "нет"} => ${(attempt.replacement_hops || []).map((id) => nodeName(nodes, id)).join(" -> ") || "нет"}`,
                ])}
              />
              <div className="inlineActions">
                <button
                  type="button"
                  className="ghost"
                  onClick={() => void loadFabricRebuildLedger(!fabricRebuildLedgerDeep, { ...fabricRebuildLedgerFilters, offset: 0 })}
                >
                  {fabricRebuildLedgerDeep ? "fast ledger" : "deep ledger"}
                </button>
                <button
                  type="button"
                  className="ghost"
                  disabled={!fabricRebuildLedgerDeep || fabricRebuildLedgerFilters.offset <= 0}
                  onClick={() =>
                    void loadFabricRebuildLedger(true, {
                      ...fabricRebuildLedgerFilters,
                      offset: Math.max(0, fabricRebuildLedgerFilters.offset - 20),
                    })
                  }
                >
                  prev
                </button>
                <button
                  type="button"
                  className="ghost"
                  disabled={!fabricRebuildLedgerDeep || fabricRebuildAttempts.length < 20}
                  onClick={() => void loadFabricRebuildLedger(true, { ...fabricRebuildLedgerFilters, offset: fabricRebuildLedgerFilters.offset + 20 })}
                >
                  next
                </button>
                <span className="pill">offset {fabricRebuildLedgerDeep ? fabricRebuildLedgerFilters.offset : 0}</span>
                <span className="muted">Deep ledger correlates heartbeat timeline and can be slower; default refresh stays fast.</span>
              </div>
              {fabricRebuildAttempts.length === 0 && <EmptyState title="Rebuild ledger пуст" text="Пока нет долговечной истории service-channel route rebuild решений." />}
            </article>
            <article className="card span2">
              <h3>{t.servicePlacement}</h3>
              <DataTable
                columns={["узел", "runtime", "адрес", "здоровье", "функции", "желаемые / reported сервисы", "последний heartbeat"]}
                rows={nodes.map((node) => {
                  const runtime = nodeRuntimeConnectivity(node, heartbeatsByNode[node.id] || [], meshLinks);
                  return [
                    node.name,
                    <RuntimeBadges runtime={runtime} />,
                    runtime.address,
                    node.health_status,
                    summarizeRoles(rolesByNode[node.id] || []),
                    summarizeWorkloads(workloadsByNode[node.id] || []),
                    formatDate((heartbeatsByNode[node.id] || [])[0]?.observed_at || node.last_seen_at),
                  ];
                })}
              />
            </article>
            <article className="card">
              <h3>{t.trafficFlow}</h3>
              <DataTable
                columns={["источник", "цель", "тип", "route/path", "статус", "задержка", "качество", "наблюдение"]}
                rows={latestLinkObservations(meshLinks).filter((link) => link.source_node_id !== link.target_node_id).map((link) => {
                  const sourceNode = nodes.find((node) => node.id === link.source_node_id);
                  const targetNode = nodes.find((node) => node.id === link.target_node_id);
                  return [
                    <NodeLinkEndpoint node={sourceNode} fallback={nodeName(nodes, link.source_node_id)} heartbeatsByNode={heartbeatsByNode} meshLinks={meshLinks} />,
                    <NodeLinkEndpoint node={targetNode} fallback={nodeName(nodes, link.target_node_id)} heartbeatsByNode={heartbeatsByNode} meshLinks={meshLinks} />,
                    meshLinkObservationLabel(link),
                    meshLinkRoutePathSummary(link, nodes),
                    link.link_status,
                    link.latency_ms == null ? "н/д" : `${link.latency_ms} мс`,
                    link.quality_score == null ? "н/д" : `${link.quality_score}/100`,
                    formatDate(link.observed_at),
                  ];
                })}
              />
            </article>
            <article className="card">
              <h3>Политики QoS</h3>
              <DataTable
                columns={["класс", "приоритет", "надежность", "политика сброса"]}
                rows={qosPolicies.map((policy) => [
                  policy.service_class,
                  String(policy.priority),
                  policy.reliability_mode,
                  policy.drop_policy,
                ])}
              />
            </article>
          </section>
        )}

        {activeView === "vpn" && (
          <section className="grid two">
            <article className="card">
              <h3>Создать желаемое состояние VPN-подключения</h3>
              <p className="muted">Только Control/API слой. Здесь не выполняются TUN/TAP, маршруты, DNS, firewall, QoS или packet forwarding.</p>
              <FormGrid>
                <label>
                  ID организации
                  <input value={vpnForm.organizationId} onChange={(event) => setVPNForm({ ...vpnForm, organizationId: event.target.value })} />
                </label>
                <label>
                  Название
                  <input value={vpnForm.name} onChange={(event) => setVPNForm({ ...vpnForm, name: event.target.value })} />
                </label>
                <label>
                  Протокол
                  <select value={vpnForm.protocolFamily} onChange={(event) => setVPNForm({ ...vpnForm, protocolFamily: event.target.value })}>
                    <option value="generic">generic</option>
                    <option value="wireguard">wireguard</option>
                    <option value="ipsec">ipsec</option>
                    <option value="openvpn">openvpn</option>
                  </select>
                </label>
                <label>
                  Желаемое состояние
                  <select value={vpnForm.desiredState} onChange={(event) => setVPNForm({ ...vpnForm, desiredState: event.target.value })}>
                    <option value="disabled">выключено</option>
                    <option value="enabled">включено</option>
                  </select>
                </label>
                <label>
                  Ссылка на credential
                  <input value={vpnForm.credentialRef} onChange={(event) => setVPNForm({ ...vpnForm, credentialRef: event.target.value })} />
                </label>
              </FormGrid>
              <label>
                Целевой endpoint JSON
                <textarea value={vpnForm.targetEndpointJson} onChange={(event) => setVPNForm({ ...vpnForm, targetEndpointJson: event.target.value })} />
              </label>
              <label>
                Политика разрешенных узлов JSON
                <textarea
                  value={vpnForm.allowedNodePolicyJson}
                  onChange={(event) => setVPNForm({ ...vpnForm, allowedNodePolicyJson: event.target.value })}
                />
              </label>
              <details>
                <summary>Расширенные routing / QoS / placement JSON</summary>
                <label>
                  Использование маршрутизации JSON
                  <textarea value={vpnForm.routingUsageJson} onChange={(event) => setVPNForm({ ...vpnForm, routingUsageJson: event.target.value })} />
                </label>
                <label>
                  Политика маршрута JSON
                  <textarea value={vpnForm.routePolicyJson} onChange={(event) => setVPNForm({ ...vpnForm, routePolicyJson: event.target.value })} />
                </label>
                <label>
                  Политика QoS JSON
                  <textarea value={vpnForm.qosPolicyJson} onChange={(event) => setVPNForm({ ...vpnForm, qosPolicyJson: event.target.value })} />
                </label>
                <label>
                  Политика размещения JSON
                  <textarea value={vpnForm.placementPolicyJson} onChange={(event) => setVPNForm({ ...vpnForm, placementPolicyJson: event.target.value })} />
                </label>
              </details>
              <button
                className="primary"
                disabled={!selectedClusterId || !vpnForm.organizationId || !vpnForm.name}
                onClick={() =>
                  void runAction(
                    () =>
                      client.createVPNConnection(selectedClusterId, {
                        organizationId: vpnForm.organizationId,
                        name: vpnForm.name,
                        protocolFamily: vpnForm.protocolFamily,
                        credentialRef: vpnForm.credentialRef || null,
                        desiredState: vpnForm.desiredState,
                        targetEndpoint: parseJSONObject(vpnForm.targetEndpointJson, "target endpoint"),
                        allowedNodePolicy: parseJSONObject(vpnForm.allowedNodePolicyJson, "allowed node policy"),
                        routingUsage: parseJSONArray(vpnForm.routingUsageJson, "routing usage"),
                        routePolicy: parseJSONObject(vpnForm.routePolicyJson, "route policy"),
                        qosPolicy: parseJSONObject(vpnForm.qosPolicyJson, "qos policy"),
                        placementPolicy: parseJSONObject(vpnForm.placementPolicyJson, "placement policy"),
                      }),
                    "Желаемое состояние VPN создано.",
                  )
                }
              >
                Создать желаемое состояние VPN
              </button>
            </article>

            <article className="card">
              <div className="cardHead">
                <div>
                  <h3>VPN-подключения</h3>
                  <p className="muted">Cluster-managed состояние, VPN packet path stats и диагностика Android-клиента.</p>
                </div>
                <div className="actions compactActions">
                  <button
                    onClick={() =>
                      void runAction(async () => {
                        const expired = await client.expireStaleVPNLeases(selectedClusterId);
                        setNotice(`Истекшие VPN lease: ${expired.length}.`);
                      }, "Stale VPN lease проверены.")
                    }
                  >
                    Проверить stale lease
                  </button>
                  <button onClick={() => void refreshVPNClientDiagnostic()}>Обновить клиент</button>
                </div>
              </div>
              <div className="inlineForm">
                <label>
                  Android device id
                  <input
                    value={vpnDiagnosticDeviceId}
                    placeholder="0315f630-..."
                    onChange={(event) => setVPNDiagnosticDeviceId(event.target.value)}
                    onBlur={() => localStorage.setItem(storageKeys.vpnDiagnosticDeviceId, vpnDiagnosticDeviceId.trim())}
                  />
                </label>
                {vpnClientDiagnostics.length > 0 && (
                  <label>
                    Найденные клиенты
                    <select
                      value={vpnDiagnosticDeviceId}
                      onChange={(event) => {
                        const deviceId = event.target.value;
                        setVPNDiagnosticDeviceId(deviceId);
                        localStorage.setItem(storageKeys.vpnDiagnosticDeviceId, deviceId);
                        setVPNClientDiagnostic(vpnClientDiagnostics.find((item) => item.device_id === deviceId) || null);
                      }}
                    >
                      {vpnClientDiagnostics.map((item) => {
                        const payload = objectField(item.payload) || {};
                        return (
                          <option key={item.device_id} value={item.device_id}>
                            {shortId(item.device_id)} / {stringField(payload, "app_version", "н/д")} / {formatDate(item.observed_at)}
                          </option>
                        );
                      })}
                    </select>
                  </label>
                )}
              </div>
              <div className="diagnosticCommandPanel">
                <div className="actions compactActions">
                  <button onClick={() => void sendVPNDiagnosticCommand({ type: "refresh_profile" }, "Профиль")}>Обновить профиль</button>
                  <button onClick={() => void sendVPNDiagnosticCommand({ type: "start_vpn" }, "VPN")}>Старт VPN</button>
                  <button onClick={() => void sendVPNDiagnosticCommand({ type: "stop_vpn" }, "VPN")}>Стоп VPN</button>
                  <button onClick={() => void sendVPNDiagnosticCommand({ type: "vpn_stats" }, "Stats")}>Stats</button>
                </div>
                {lastVPNDiagnosticCommand && (
                  <p className="muted">
                    Последняя команда: {stringField(lastVPNDiagnosticCommand.payload, "type", "н/д")} / {formatDate(lastVPNDiagnosticCommand.created_at)}
                  </p>
                )}
              </div>
              {renderVPNClientDiagnostic(vpnClientDiagnostic)}
              <div className="stack">
                {vpnConnections.map((connection) => {
                  const runtime = objectField(connection.metadata?.client_config);
                  const fabricRoute = objectField(runtime?.vpn_fabric_route);
                  const entryPool = arrayStrings(fabricRoute?.entry_pool_node_ids || connection.placement_policy?.entry_node_ids);
                  const exitPool = arrayStrings(fabricRoute?.exit_pool_node_ids || connection.placement_policy?.exit_node_ids);
                  const selectedEntryNodeId = String(fabricRoute?.selected_entry_node_id || entryPool[0] || "");
                  const selectedExitNodeId = String(
                    fabricRoute?.selected_exit_node_id ||
                      vpnLeases[connection.id]?.owner_node_id ||
                      connection.placement_policy?.exit_node_id ||
                      exitPool[0] ||
                      "",
                  );
                  const stats = vpnPacketStats[connection.id] || {};
                  return (
                    <div className="vpnCard" key={connection.id}>
                      <div>
                        <strong>{connection.name}</strong>
                        <p className="muted">
                          {connection.protocol_family} / {connection.mode} / организация {shortId(connection.organization_id)}
                        </p>
                        <Status value={connection.desired_state} />
                        <Status value={connection.status} />
                        <span className={`pill ${runtime?.packet_forwarding ? "good" : "warn"}`}>
                          {runtime?.packet_forwarding ? "packet path active" : "packet path inactive"}
                        </span>
                        <span className="pill">
                          {String(fabricRoute?.preferred_data_plane || "backend_relay")} / fallback {String(fabricRoute?.fallback_data_plane || "н/д")}
                        </span>
                      </div>
                      <div className="stateList">
                        <StateLine label="Секрет" value={connection.credential_ref ? "задан" : "не задан"} />
                        <StateLine label="Активный lease" value={vpnLeases[connection.id] ? shortId(vpnLeases[connection.id]?.owner_node_id) : "нет"} />
                        <StateLine
                          label="Fabric route"
                          value={`${selectedEntryNodeId ? nodeName(nodes, selectedEntryNodeId) : "entry auto"} -> ${selectedExitNodeId ? nodeName(nodes, selectedExitNodeId) : "exit auto"}`}
                        />
                        <StateLine label="Entry pool" value={entryPool.map((id) => nodeName(nodes, id)).join(", ") || "н/д"} />
                        <StateLine label="Exit pool" value={exitPool.map((id) => nodeName(nodes, id)).join(", ") || "н/д"} />
                        <StateLine label="Runtime" value={String(runtime?.runtime_status || "н/д")} />
                        <StateLine label="Gateway" value={String(runtime?.gateway_assignment_status || "н/д")} />
                        <StateLine label="Client -> gateway" value={vpnPacketStatLine(stats.client_to_gateway)} />
                        <StateLine label="Gateway -> client" value={vpnPacketStatLine(stats.gateway_to_client)} />
                        <StateLine label="Обновлено" value={formatDate(connection.updated_at)} />
                      </div>
                      <div className="actions">
                        <button
                          disabled={connection.desired_state === "enabled"}
                          onClick={() =>
                            void runAction(
                              () => client.updateVPNConnectionDesiredState(selectedClusterId, connection.id, "enabled"),
                              "Желаемое состояние VPN включено.",
                            )
                          }
                        >
                          Включить
                        </button>
                        <button
                          disabled={connection.desired_state === "disabled"}
                          onClick={() =>
                            void runAction(
                              () => client.updateVPNConnectionDesiredState(selectedClusterId, connection.id, "disabled"),
                              "Желаемое состояние VPN выключено.",
                            )
                          }
                        >
                          Выключить
                        </button>
                      </div>
                    </div>
                  );
                })}
                {vpnConnections.length === 0 && <EmptyState title="Нет желаемого состояния VPN" text="Control-plane записи C18 появятся здесь." />}
              </div>
            </article>
          </section>
        )}

        {activeView === "org-safe" && (
          <section className="grid two">
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>Организации и пользователи</h3>
                  <p className="muted">Операционный слой для владельца платформы: tenant scope, роли участников и безопасная сводка без раскрытия core mesh.</p>
                </div>
                <span className="pill">{organizations.length}</span>
              </div>
              <FormGrid>
                <label>
                  Slug
                  <input value={organizationForm.slug} onChange={(event) => setOrganizationForm({ ...organizationForm, slug: event.target.value })} placeholder="home" />
                </label>
                <label>
                  Название
                  <input value={organizationForm.name} onChange={(event) => setOrganizationForm({ ...organizationForm, name: event.target.value })} placeholder="HOME" />
                </label>
              </FormGrid>
              <div className="actions">
                <button
                  className="primary"
                  disabled={!organizationForm.slug.trim() || !organizationForm.name.trim()}
                  onClick={() =>
                    void runAction(async () => {
                      const org = await client.createOrganization(organizationForm);
                      setOrganizationForm({ slug: "", name: "" });
                      setOrganizationId(org.id);
                      setMembershipForm((previous) => ({ ...previous, organizationId: org.id }));
                      setResourceForm((previous) => ({ ...previous, organizationId: org.id }));
                    }, "Организация создана.")
                  }
                >
                  Создать организацию
                </button>
              </div>
              <DataTable
                columns={["организация", "slug", "статус", "ресурсы", "участники", "действие"]}
                rows={organizations.map((org) => {
                  const orgResources = resources.filter((resource) => resource.organization_id === org.id);
                  const memberships = membershipsByOrg[org.id] || [];
                  return [
                    org.name,
                    org.slug,
                    <Status value={org.status} />,
                    String(orgResources.length),
                    String(memberships.length),
                    <div className="actions" key={org.id}>
                      <button
                        onClick={() =>
                          void runAction(async () => {
                            setOrganizationId(org.id);
                            setOrganizationSummary(await client.getOrganizationAdminSummary(org.id));
                          }, "Сводка организации загружена.")
                        }
                      >
                        Открыть
                      </button>
                    </div>,
                  ];
                })}
              />
            </article>

            <article className="card">
              <h3>Пользователь</h3>
              <FormGrid>
                <label>
                  Email / логин
                  <input value={userForm.email} onChange={(event) => setUserForm({ ...userForm, email: event.target.value })} placeholder="user@example.com" />
                </label>
                <label>
                  Пароль
                  <input
                    type="password"
                    value={userForm.password}
                    onChange={(event) => setUserForm({ ...userForm, password: event.target.value })}
                    placeholder="минимум 8 символов"
                  />
                </label>
                <label>
                  Роль платформы
                  <select value={userForm.platformRole} onChange={(event) => setUserForm({ ...userForm, platformRole: event.target.value })}>
                    <option value="user">user</option>
                    <option value="platform_admin">platform_admin</option>
                    <option value="platform_recovery_admin">platform_recovery_admin</option>
                  </select>
                </label>
              </FormGrid>
              <div className="actions">
                <button
                  disabled={!userForm.email.trim() || userForm.password.length < 8}
                  onClick={() =>
                    void runAction(async () => {
                      const user = await client.createUser(userForm);
                      setUsers(await client.listUsers());
                      setUserForm({ email: "", password: "", platformRole: "user" });
                      setMembershipForm((previous) => ({ ...previous, userId: user.id }));
                    }, "Пользователь создан.")
                  }
                >
                  Создать пользователя
                </button>
              </div>
              <DataTable
                columns={["пользователь", "роль платформы", "id"]}
                rows={users.map((user) => [user.email, <Status value={user.platform_role || "user"} />, <code>{user.id}</code>])}
              />
            </article>

            <article className="card">
              <h3>Участник организации</h3>
              <FormGrid>
                <label>
                  Организация
                  <select value={membershipForm.organizationId} onChange={(event) => setMembershipForm({ ...membershipForm, organizationId: event.target.value })}>
                    <option value="">Выберите организацию</option>
                    {organizations.map((org) => (
                      <option key={org.id} value={org.id}>
                        {org.name}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  Пользователь
                  <select value={membershipForm.userId} onChange={(event) => setMembershipForm({ ...membershipForm, userId: event.target.value })}>
                    <option value="">Выберите пользователя</option>
                    {users.map((user) => (
                      <option key={user.id} value={user.id}>
                        {user.email}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  Роль
                  <select value={membershipForm.roleId} onChange={(event) => setMembershipForm({ ...membershipForm, roleId: event.target.value })}>
                    <option value="org_owner">org_owner</option>
                    <option value="org_admin">org_admin</option>
                    <option value="org_operator">org_operator</option>
                    <option value="org_member">org_member</option>
                    <option value="org_viewer">org_viewer</option>
                  </select>
                </label>
              </FormGrid>
              <div className="actions">
                <button
                  disabled={!membershipForm.organizationId || !membershipForm.userId.trim()}
                  onClick={() =>
                    void runAction(
                      () => client.addOrganizationMembership(membershipForm.organizationId, { userId: membershipForm.userId, roleId: membershipForm.roleId }),
                      "Участник организации сохранен.",
                    )
                  }
                >
                  Сохранить участника
                </button>
              </div>
            </article>

            <article className="card">
              <h3>Безопасная сводка</h3>
              <div className="inlineForm">
                <select value={organizationId} onChange={(event) => setOrganizationId(event.target.value)}>
                  <option value="">Выберите организацию</option>
                  {organizations.map((org) => (
                    <option key={org.id} value={org.id}>
                      {org.name}
                    </option>
                  ))}
                </select>
                <button
                  disabled={!organizationId}
                  onClick={() =>
                    void runAction(async () => {
                      setOrganizationSummary(await client.getOrganizationAdminSummary(organizationId));
                    }, "Сводка организации загружена.")
                  }
                >
                  Обновить
                </button>
              </div>
              {organizationSummary ? (
                <div className="stack">
                  <Metric label="Ресурсы" value={organizationSummary.resource_count} tone="steel" />
                  <Metric label="Активные сессии" value={organizationSummary.active_session_count} tone="green" />
                  <StateLine label="Topology exposure" value={organizationSummary.topology_exposure} />
                  <DataTable
                    columns={["контур", "состояние"]}
                    rows={Object.entries(organizationSummary.connector_status || {}).map(([key, value]) => [
                      key,
                      typeof value === "string" ? statusLabel(value) : JSON.stringify(value),
                    ])}
                  />
                  <DataTable columns={["протокол", "количество"]} rows={organizationSummary.service_endpoints.map((item) => [item.protocol, String(item.count)])} />
                </div>
              ) : (
                <EmptyState title="Сводка не выбрана" text="Выберите организацию, чтобы проверить tenant-safe состояние." />
              )}
            </article>
          </section>
        )}

        {activeView === "servers" && (
          <section className="grid two">
            <article className="card span2">
              <div className="cardHead">
                <div>
                  <h3>Справочник серверов</h3>
                  <p className="muted">Единый каталог целей для RDP/VPN: адрес сервера, организация, протокол и предпочтительный вход/выход маршрута.</p>
                </div>
                <span className="pill">{resources.length}</span>
              </div>
              <FormGrid>
                <label>
                  Организация
                  <select value={resourceForm.organizationId} onChange={(event) => setResourceForm({ ...resourceForm, organizationId: event.target.value })}>
                    <option value="">Выберите организацию</option>
                    {organizations.map((org) => (
                      <option key={org.id} value={org.id}>
                        {org.name}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  Имя сервера
                  <input value={resourceForm.name} onChange={(event) => setResourceForm({ ...resourceForm, name: event.target.value })} placeholder="Office RDP" />
                </label>
                <label>
                  Адрес
                  <input value={resourceForm.address} onChange={(event) => setResourceForm({ ...resourceForm, address: event.target.value })} placeholder="192.168.1.10:3389" />
                </label>
                <label>
                  Протокол
                  <select value={resourceForm.protocol} onChange={(event) => setResourceForm({ ...resourceForm, protocol: event.target.value })}>
                    <option value="rdp">RDP</option>
                    <option value="vpn">VPN</option>
                    <option value="ssh">SSH</option>
                    <option value="http">HTTP</option>
                  </select>
                </label>
                <label>
                  Вход
                  <select value={resourceForm.entryNode} onChange={(event) => setResourceForm({ ...resourceForm, entryNode: event.target.value })}>
                    <option value="">Автоматически</option>
                    {nodes.map((node) => (
                      <option key={node.id} value={node.id}>
                        {node.name}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  Выход
                  <select value={resourceForm.exitNode} onChange={(event) => setResourceForm({ ...resourceForm, exitNode: event.target.value })}>
                    <option value="">Автоматически</option>
                    {nodes.map((node) => (
                      <option key={node.id} value={node.id}>
                        {node.name}
                      </option>
                    ))}
                  </select>
                </label>
                <label>
                  Теги
                  <input value={resourceForm.tags} onChange={(event) => setResourceForm({ ...resourceForm, tags: event.target.value })} placeholder="home, accounting" />
                </label>
                <label>
                  RDP пользователь
                  <input value={resourceForm.username} onChange={(event) => setResourceForm({ ...resourceForm, username: event.target.value })} placeholder="user или DOMAIN\\user" />
                </label>
                <label>
                  RDP пароль
                  <input type="password" value={resourceForm.password} onChange={(event) => setResourceForm({ ...resourceForm, password: event.target.value })} placeholder="хранится как secret" />
                </label>
                <label>
                  Домен
                  <input value={resourceForm.domain} onChange={(event) => setResourceForm({ ...resourceForm, domain: event.target.value })} placeholder="опционально" />
                </label>
              </FormGrid>
              <div className="actions">
                <button
                  className="primary"
                  disabled={!resourceForm.organizationId || !resourceForm.name.trim() || !resourceForm.address.trim()}
                  onClick={() =>
                    void runAction(async () => {
                      const secretRef =
                        ["rdp", "vnc", "ssh"].includes(resourceForm.protocol)
                          ? `rap-secret://org/${resourceForm.organizationId}/resources/${crypto.randomUUID()}/primary`
                          : null;
                      const created = await client.createResource({
                        organizationId: resourceForm.organizationId,
                        name: resourceForm.name,
                        address: resourceForm.address,
                        protocol: resourceForm.protocol,
                        secretRef,
                        certificateVerificationMode: resourceForm.protocol === "rdp" ? "ignore" : "strict",
                        clipboardMode: resourceForm.protocol === "rdp" ? "bidirectional" : "disabled",
                        fileTransferMode: resourceForm.protocol === "rdp" ? "bidirectional" : "disabled",
                        metadata: {
                          route_mode: resourceForm.routeMode,
                          preferred_entry_node_id: resourceForm.entryNode || null,
                          preferred_exit_node_id: resourceForm.exitNode || null,
                          tags: resourceForm.tags.split(",").map((item) => item.trim()).filter(Boolean),
                        },
                      });
                      if (["rdp", "vnc", "ssh"].includes(resourceForm.protocol) && (resourceForm.username.trim() || resourceForm.password)) {
                        await client.upsertResourceSecret(created.id, {
                          username: resourceForm.username.trim(),
                          password: resourceForm.password,
                          domain: resourceForm.domain.trim(),
                        });
                      }
                      setResourceForm({ ...resourceForm, name: "", address: "", tags: "", username: "", password: "", domain: "" });
                    }, "Сервер добавлен в справочник.")
                  }
                >
                  Добавить сервер
                </button>
              </div>
              <DataTable
                columns={["сервер", "адрес", "протокол", "секрет", "организация", "маршрут", "создано", "действия"]}
                rows={resources.map((resource) => {
                  const metadata = resource.metadata || {};
                  const org = organizations.find((item) => item.id === resource.organization_id);
                  return [
                    resource.name,
                    resource.address,
                    resource.protocol,
                    resource.has_secret ? "сохранен" : resource.secret_ref ? "нужен payload" : "нет",
                    org?.name || shortId(resource.organization_id),
                    `${shortId(String(metadata.preferred_entry_node_id || "")) || "auto"} -> ${shortId(String(metadata.preferred_exit_node_id || "")) || "auto"}`,
                    formatDate(resource.created_at),
                    <button
                      className="ghost"
                      onClick={() => {
                        setResourceSecretDialog(resource);
                        setResourceSecretForm({ username: "", password: "", domain: "" });
                      }}
                    >
                      Обновить secret
                    </button>,
                  ];
                })}
              />
              {resourceSecretDialog && (
                <div className="modalBackdrop" role="presentation">
                  <div className="modalCard" role="dialog" aria-modal="true" aria-labelledby="resource-secret-title">
                    <div className="cardHead">
                      <div>
                        <h3 id="resource-secret-title">Учетные данные RDP</h3>
                        <p className="muted">
                          {resourceSecretDialog.name} · {resourceSecretDialog.address}
                        </p>
                      </div>
                      <button className="ghost" onClick={() => setResourceSecretDialog(null)}>
                        Закрыть
                      </button>
                    </div>
                    <FormGrid>
                      <label>
                        Пользователь
                        <input value={resourceSecretForm.username} onChange={(event) => setResourceSecretForm({ ...resourceSecretForm, username: event.target.value })} placeholder="user или DOMAIN\\user" />
                      </label>
                      <label>
                        Пароль
                        <input type="password" value={resourceSecretForm.password} onChange={(event) => setResourceSecretForm({ ...resourceSecretForm, password: event.target.value })} />
                      </label>
                      <label>
                        Домен
                        <input value={resourceSecretForm.domain} onChange={(event) => setResourceSecretForm({ ...resourceSecretForm, domain: event.target.value })} placeholder="опционально" />
                      </label>
                    </FormGrid>
                    <p className="muted">Пароль сохраняется как encrypted resource secret. В metadata ресурса он не попадет.</p>
                    <div className="actions">
                      <button
                        className="primary"
                        disabled={!resourceSecretForm.username.trim() || !resourceSecretForm.password}
                        onClick={() =>
                          void runAction(async () => {
                            await client.upsertResourceSecret(resourceSecretDialog.id, {
                              username: resourceSecretForm.username.trim(),
                              password: resourceSecretForm.password,
                              domain: resourceSecretForm.domain.trim(),
                            });
                            setResourceSecretDialog(null);
                            setResourceSecretForm({ username: "", password: "", domain: "" });
                          }, "Secret ресурса обновлен.")
                        }
                      >
                        Сохранить secret
                      </button>
                      <button onClick={() => setResourceSecretDialog(null)}>Отмена</button>
                    </div>
                  </div>
                </div>
              )}
            </article>
          </section>
        )}

        {activeView === "audit" && (
          <section className="card">
            <div className="cardHead">
              <div>
                <h3>Аудит кластера</h3>
                {auditFocusNodeId && (
                  <p className="muted">
                    Фильтр по узлу: <strong>{auditFocusNodeLabel || shortId(auditFocusNodeId)}</strong>
                  </p>
                )}
              </div>
              {auditFocusNodeId && (
                <button
                  className="ghost"
                  onClick={() => {
                    setAuditFocusNodeId("");
                    setAuditFocusNodeLabel("");
                  }}
                >
                  Сбросить фильтр
                </button>
              )}
            </div>
            <DataTable
              columns={["событие", "цель", "actor", "создано"]}
              rows={visibleAuditEvents.map((event) => [
                event.event_type,
                `${event.target_type}${event.target_id ? `:${shortId(event.target_id)}` : ""}`,
                event.actor_user_id ? shortId(event.actor_user_id) : "system",
                formatDate(event.created_at),
              ])}
            />
          </section>
        )}
      </section>
    </main>
  );
}

function Metric({ label, value, tone }: { label: string; value: number; tone: string }) {
  return (
    <article className={`metric ${tone}`}>
      <span>{label}</span>
      <strong>{value}</strong>
    </article>
  );
}

function Signal({ label, value, tone }: { label: string; value: ReactNode; tone?: string }) {
  return (
    <div className={`signal ${tone || ""}`}>
      <span>{label}</span>
      <strong>{value}</strong>
    </div>
  );
}

function Status({ value }: { value: string }) {
  return <span className={`status ${value.replace(/_/g, "-")}`}>{statusLabel(value)}</span>;
}

function FunctionState({ label, value, tone }: { label: string; value: string; tone?: string }) {
  return (
    <span className={`functionState ${tone || ""}`}>
      <small>{label}</small>
      <strong>{value}</strong>
    </span>
  );
}

function StateLine({ label, value }: { label: string; value: ReactNode }) {
  return (
    <div className="stateLine">
      <span>{label}</span>
      <strong>{value}</strong>
    </div>
  );
}

function EmptyState({ title, text }: { title: string; text: string }) {
  return (
    <article className="empty">
      <h3>{title}</h3>
      <p>{text}</p>
    </article>
  );
}

function renderVPNClientDiagnostic(status: VPNClientDiagnosticStatus | null) {
  if (!status) {
    return <p className="muted">Диагностика Android-клиента не загружена. Укажи device id из приложения и нажми “Обновить клиент”.</p>;
  }
  const payload = objectField(status.payload) || {};
  const runtime = objectField(payload.runtime);
  const config = objectField(payload.vpn_config);
  const appVersion = stringField(payload, "app_version", "н/д");
  const serviceState = stringField(payload, "service_state", "н/д");
  const controlMode = stringField(payload, "control_network_mode", "н/д");
  const activeRelay = stringField(config, "packet_relay_active_base_url") || stringField(config, "packet_relay_base_url", "н/д");
  const profileRelay = stringField(config, "packet_relay_profile_base_url", "н/д");
  const candidates = stringField(config, "packet_relay_candidate_urls", "н/д");
  const read = numberField(runtime, "uplink_read_total");
  const sent = numberField(runtime, "uplink_sent_total");
  const down = numberField(runtime, "downlink_received_total");
  const drops = numberField(runtime, "uplink_dropped_packets") + numberField(runtime, "downlink_dropped_packets");
  const bypass = numberField(runtime, "uplink_bypassed_control_packets");
  const downBytes = numberField(runtime, "downlink_received_bytes");
  const upBytes = numberField(runtime, "uplink_sent_bytes");
  const runtimeState = stringField(runtime, "state", "н/д");
  const runtimeMessage = stringField(runtime, "message", "");
  const upMbps = numberField(runtime, "uplink_sent_mbps");
  const downMbps = numberField(runtime, "downlink_received_mbps");
  const lastCommandType = stringField(payload, "last_command_type", "н/д");
  const lastCommandResult = stringField(payload, "last_command_result", "н/д");
  return (
    <div className="vpnCard diagnosticCard">
      <div>
        <strong>Android client {shortId(status.device_id)}</strong>
        <p className="muted">
          {appVersion} / {serviceState} / {formatDate(status.observed_at)}
        </p>
        <Status value={Date.now() - new Date(status.observed_at).getTime() < 30_000 ? "active" : "degraded"} />
        <span className="pill">{controlMode}</span>
      </div>
      <div className="stateList">
        <StateLine label="Relay active" value={activeRelay} />
        <StateLine label="Relay profile" value={profileRelay} />
        <StateLine label="Relay candidates" value={candidates} />
        <StateLine label="Packets read/sent/down" value={`${read} / ${sent} / ${down}`} />
        <StateLine label="Drops / control bypass" value={`${drops} / ${bypass}`} />
        <StateLine label="Bytes up/down" value={`${formatBytes(upBytes)} / ${formatBytes(downBytes)}`} />
        <StateLine label="Rate up/down" value={`${upMbps.toFixed(2)} / ${downMbps.toFixed(2)} Mbps`} />
        <StateLine label="Runtime" value={runtimeMessage ? `${runtimeState}: ${runtimeMessage}` : runtimeState} />
        <StateLine label="Last command" value={`${lastCommandType}: ${lastCommandResult}`} />
      </div>
    </div>
  );
}

function TelemetryStrip({ items, emptyText }: { items: NodeTelemetryObservation[]; emptyText: string }) {
  if (items.length === 0) {
    return <EmptyState title={emptyText} text="Тестовая телеметрия появится здесь после отчета node-agent." />;
  }
  const ordered = [...items].reverse().slice(-24);
  const latest = items[0];
  const maxMemory = Math.max(...ordered.map((item) => item.memory_used_bytes || 0), 1);
  return (
    <div className="telemetryBox">
      <div className="signalStrip compact">
        <Signal label="Память" value={`${formatBytes(latest.memory_used_bytes)} / ${formatBytes(latest.memory_total_bytes)}`} />
        <Signal label="Процессор" value={latest.cpu_percent == null ? "н/д" : `${latest.cpu_percent.toFixed(1)}%`} />
        <Signal label="Процессы" value={latest.process_count == null ? "н/д" : String(latest.process_count)} />
        <Signal label="Обновлено" value={formatDate(latest.observed_at)} />
      </div>
      <div className="sparkline" aria-label="memory telemetry">
        {ordered.map((item) => (
          <span key={item.id} style={{ height: `${Math.max(8, Math.round(((item.memory_used_bytes || 0) / maxMemory) * 100))}%` }} />
        ))}
      </div>
    </div>
  );
}

function NodeDetailsDashboard({
  node,
  memberships,
  activeRoles,
  desiredWorkloads,
  observedWorkloads,
  heartbeats,
  telemetry,
  meshLinks,
  syntheticConfig,
  allNodes,
  onSetUpdatePolicy,
  updatePlan,
  updateStatuses,
  labels,
}: {
  node: ClusterNode;
  memberships: Array<{ cluster: Cluster; node: ClusterNode }>;
  activeRoles: RoleAssignment[];
  desiredWorkloads: NodeWorkloadDesiredState[];
  observedWorkloads: WorkloadStatus[];
  heartbeats: NodeHeartbeat[];
  telemetry: NodeTelemetryObservation[];
  meshLinks: MeshLink[];
  syntheticConfig?: NodeSyntheticMeshConfig;
  allNodes: ClusterNode[];
  onSetUpdatePolicy?: (node: ClusterNode, product: string, targetVersion: string | null) => void;
  updatePlan?: NodeUpdatePlan;
  updateStatuses: NodeUpdateStatus[];
  labels: Record<string, string>;
}) {
  const latestHeartbeat = heartbeats[0];
  const latestTelemetry = telemetry[0];
  const listenerReport = objectField(latestHeartbeat?.metadata?.mesh_listener_report);
  const endpointReport = objectField(latestHeartbeat?.metadata?.mesh_endpoint_report);
  const outboundReport = objectField(latestHeartbeat?.metadata?.mesh_outbound_session_report);
  const desiredListenerConfig = syntheticConfig?.mesh_listener;
  const recoveryReport = objectField(latestHeartbeat?.metadata?.mesh_peer_recovery_report);
  const intentReport = objectField(latestHeartbeat?.metadata?.mesh_peer_connection_intent_report);
  const managerReport = objectField(latestHeartbeat?.metadata?.mesh_peer_connection_manager_report);
  const registryRuntimeReport = objectField(latestHeartbeat?.metadata?.fabric_registry_runtime_report);
  const rendezvousReport = objectField(latestHeartbeat?.metadata?.mesh_rendezvous_lease_report);
  const routeDecisionReport = objectField(latestHeartbeat?.metadata?.mesh_route_path_decision_report);
  const routeGenerationReport = objectField(latestHeartbeat?.metadata?.mesh_route_generation_report);
  const routeHealthReport = objectField(latestHeartbeat?.metadata?.mesh_route_health_config_report);
  const serviceChannelFeedback = syntheticConfig?.service_channel_route_feedback;
  const serviceChannelFeedbackItems = serviceChannelFeedback?.observations || [];
  const serviceChannelRemediationCommands = syntheticConfig?.service_channel_remediation_commands || [];
  const latestLinks = latestLinkObservations(meshLinks).filter((link) => link.source_node_id !== link.target_node_id);
  const reachableLinks = latestLinks.filter((link) => link.link_status === "reachable");
  const failedLinks = latestLinks.filter((link) => link.link_status !== "reachable");
  const capabilityEntries = Object.entries(latestHeartbeat?.capabilities || {}).sort(([left], [right]) => left.localeCompare(right));
  const managerProbeResults = arrayObjects(managerReport?.probe_results);
  const [activeTab, setActiveTab] = useState("network");
  const latestNodeAgentUpdate = latestUpdateStatus(updateStatuses, "rap-node-agent");
  const latestHostAgentUpdate = latestUpdateStatus(updateStatuses, "rap-host-agent");
  const latestAnyUpdate = updateStatuses[0];
  const updaterHealth = nodeUpdaterSummary(updateStatuses);
  const primaryClusterID = memberships.find((membership) => membership.node.id === node.id)?.cluster.id || memberships[0]?.cluster.id || "";
  const reportedCandidates = arrayObjects(endpointReport?.endpoint_candidates);
  const primaryReportedCandidate = reportedCandidates[0];
  const advertisedEndpoint =
    firstStringField(endpointReport, ["peer_endpoint", "advertised_endpoint", "endpoint"]) ||
    stringField(primaryReportedCandidate, "address", "") ||
    "";
  const reportedTransport =
    firstStringField(endpointReport, ["transport", "advertise_transport"]) ||
    stringField(primaryReportedCandidate, "transport", "") ||
    "н/д";
  const reportedConnectivity =
    firstStringField(endpointReport, ["connectivity_mode", "connectivity"]) ||
    stringField(primaryReportedCandidate, "connectivity_mode", "") ||
    stringField(listenerReport, "inbound_reachability", "") ||
    "н/д";
  const reportedNat = stringField(endpointReport, "nat_type", stringField(primaryReportedCandidate, "nat_type", "н/д"));
  const reportedRegion = stringField(endpointReport, "region", stringField(listenerReport, "region", stringField(primaryReportedCandidate, "region", "н/д")));
  const reportedObservedAt = stringField(endpointReport, "observed_at", stringField(listenerReport, "observed_at", latestHeartbeat?.observed_at || "н/д"));
  const listenerStatus =
    stringField(listenerReport, "status", "") ||
    (advertisedEndpoint ? "нет listener report, есть advertised endpoint" : "report отсутствует");
  const listenerEffectiveAddr =
    stringField(listenerReport, "effective_listen_addr", "") ||
    "н/д";
  const listenerConfiguredAddr =
    stringField(listenerReport, "configured_listen_addr", "") ||
    "н/д";
  const listenerCandidates =
    reportedCandidates.length > 0
      ? reportedCandidates
      : advertisedEndpoint
        ? [
            {
              endpoint_id: `${node.id}-reported`,
              address: advertisedEndpoint,
              transport: reportedTransport,
              reachability: reportedConnectivity,
              connectivity_mode: reportedConnectivity,
              nat_type: reportedNat,
              priority: "н/д",
              last_verified_at: reportedObservedAt,
            },
          ]
        : [];
  const desiredEndpointCandidates = arrayObjects(desiredListenerConfig?.endpoint_candidates);
  const configuredPeerEndpoints = Object.entries(syntheticConfig?.peer_endpoints || {});
  const configuredPeerCandidates = Object.entries(syntheticConfig?.peer_endpoint_candidates || {}).flatMap(([peerID, candidates]) =>
    candidates.map((candidate) => ({ peerID, candidate })),
  );
  const activePeerIDs = new Set(reachableLinks.map((link) => (link.source_node_id === node.id ? link.target_node_id : link.source_node_id)));
  const reservePeerCandidates = configuredPeerCandidates.filter(({ peerID }) => !activePeerIDs.has(peerID));
  const networkDiagnostics = [
    listenerReport ? "listener report: есть" : "listener report: не прислан агентом",
    endpointReport ? "endpoint report: есть" : "endpoint report: не прислан агентом",
    outboundReport ? "outbound session: есть" : "outbound session: не прислан агентом",
    syntheticConfig ? `scoped config: ${syntheticConfig.enabled ? "enabled" : "disabled"}` : "scoped config: не загружен",
    serviceChannelFeedback ? `service-channel feedback: ${serviceChannelFeedback.observation_count}` : "service-channel feedback: не загружен",
    `active links: ${reachableLinks.length}/${latestLinks.length}`,
  ];
  const tabs = [
    ["overview", "Обзор"],
    ["network", "Сеть и адреса"],
    ["mesh", "Mesh"],
    ["services", labels.rolesAndServices],
    ["telemetry", "Телеметрия"],
    ["updates", "Обновления"],
    ["raw", "Raw"],
  ] as const;

  return (
    <div className="nodeDetails">
      <section className="nodePanel">
        <h4>Сводка runtime</h4>
        <div className="signalStrip compact nodeMetricGrid">
          <Signal label="Heartbeat" value={latestHeartbeat ? formatDate(latestHeartbeat.observed_at) : "н/д"} />
          <Signal label="Health" value={statusLabel(latestHeartbeat?.health_status || node.health_status)} />
          <Signal label="Listener" value={fabricListenerSummary(latestHeartbeat)} />
          <Signal label="Mesh links" value={`${reachableLinks.length}/${latestLinks.length}`} />
          <Signal label="Web ingress" value={webIngressReceiverSummary(latestHeartbeat)} />
          <Signal label="Update" value={updateStatusSummary(latestAnyUpdate, updatePlan)} />
        </div>
        <div className="summaryChips">
          <Status value={node.registration_status} />
          <Status value={node.membership_status} />
          <Status value={node.partition_state} />
          <span className="pill">{node.reported_version || latestHeartbeat?.reported_version || "версия неизвестна"}</span>
          {listenerReport?.one_way_connectivity === true && <span className="pill warn">one-way</span>}
          {listenerReport?.port_conflict === true && <span className="pill bad">port conflict</span>}
        </div>
      </section>

      <div className="nodeTabs" role="tablist" aria-label="Node analysis sheets">
        {tabs.map(([id, label]) => (
          <button key={id} className={activeTab === id ? "active" : ""} onClick={() => setActiveTab(id)} type="button">
            {label}
          </button>
        ))}
      </div>

      {activeTab === "overview" && (
        <div className="nodeDetailGrid">
          <section className="nodePanel">
            <h4>Идентичность и размещение</h4>
            <div className="stateList">
              <StateLine label="Node ID" value={node.id} />
              <StateLine label="Node key" value={node.node_key} />
              <StateLine label="Имя" value={node.name} />
              <StateLine label="Владение" value={statusLabel(node.ownership_type)} />
              <StateLine label="Owner org" value={shortId(node.owner_organization_id)} />
              <StateLine label="Группа" value={node.node_group_name || labels.ungroupedNodes} />
              <StateLine label="Создан" value={formatDate(node.created_at)} />
              <StateLine label="Обновлен" value={formatDate(node.updated_at)} />
            </div>
          </section>

          <section className="nodePanel">
            <h4>Участие в кластерах</h4>
            <div className="membershipList">
              {memberships.map((membership) => (
                <span key={membership.cluster.id} className={membership.node.id === node.id && membership.node.membership_status === "active" ? "pill good" : "pill"}>
                  {membership.cluster.name}: {statusLabel(membership.node.membership_status)}
                </span>
              ))}
            </div>
            <div className="stateList">
              <StateLine label="Функций фермы" value={String(activeRoles.length)} />
              <StateLine label="Desired workloads" value={String(desiredWorkloads.length)} />
              <StateLine label="Observed workloads" value={String(observedWorkloads.length)} />
              <StateLine label="Последний сигнал" value={formatDate(node.last_seen_at || latestHeartbeat?.observed_at)} />
            </div>
          </section>
        </div>
      )}

      {activeTab === "network" && (
        <>
          <div className="nodeDetailGrid">
            <section className="nodePanel">
              <h4>Локальный listener</h4>
              <div className="stateList">
                <StateLine label="Статус" value={listenerStatus} />
                <StateLine label="Режим порта" value={stringField(listenerReport, "listen_port_mode", "н/д")} />
                <StateLine label="Configured addr" value={listenerConfiguredAddr} />
                <StateLine label="Effective addr" value={listenerEffectiveAddr} />
                <StateLine label="Inbound" value={stringField(listenerReport, "inbound_reachability", reportedConnectivity)} />
                <StateLine label="One-way" value={stringField(listenerReport, "one_way_connectivity", "н/д")} />
                <StateLine label="Port conflict" value={stringField(listenerReport, "port_conflict", "false")} />
                <StateLine label="Failure" value={stringField(listenerReport, "failure_error", stringField(listenerReport, "failure_reason", "нет"))} />
              </div>
            </section>

            <section className="nodePanel">
              <h4>Desired listener</h4>
              <div className="stateList">
                <StateLine label="Состояние" value={desiredListenerConfig?.desired_state || "н/д"} />
                <StateLine label="Режим порта" value={desiredListenerConfig?.listen_port_mode || "н/д"} />
                <StateLine label="Listen addr" value={desiredListenerConfig?.listen_addr || "н/д"} />
                <StateLine label="Auto range" value={desiredListenerConfig ? `${desiredListenerConfig.auto_port_start || "н/д"}-${desiredListenerConfig.auto_port_end || "н/д"}` : "н/д"} />
                <StateLine label="Advertise endpoint" value={desiredListenerConfig?.advertise_endpoint || "auto-discovery"} />
                <StateLine label="Endpoint candidates" value={desiredEndpointCandidates.length > 0 ? String(desiredEndpointCandidates.length) : "auto-discovery"} />
                <StateLine label="Advertise transport" value={desiredListenerConfig?.advertise_transport || "н/д"} />
                <StateLine label="Connectivity" value={desiredListenerConfig?.connectivity_mode || "н/д"} />
                <StateLine label="NAT" value={desiredListenerConfig?.nat_type || "н/д"} />
                <StateLine label="Region/site" value={desiredListenerConfig?.region || "н/д"} />
                <StateLine label="Version" value={desiredListenerConfig?.config_version || "н/д"} />
              </div>
            </section>

            <section className="nodePanel">
              <h4>Что узел сообщает кластеру</h4>
              <div className="stateList">
                <StateLine label="Advertised endpoint" value={advertisedEndpoint || "не прислан"} />
                <StateLine label="Transport" value={reportedTransport} />
                <StateLine label="Connectivity" value={reportedConnectivity} />
                <StateLine label="NAT" value={reportedNat} />
                <StateLine label="Region/site" value={reportedRegion} />
                <StateLine label="Observed" value={reportedObservedAt} />
              </div>
            </section>
          </div>

          <section className="nodePanel">
            <h4>Исходящий control-channel</h4>
            <div className="stateList">
              <StateLine label="Status" value={stringField(outboundReport, "status", "не прислан")} />
              <StateLine label="Direction" value={stringField(outboundReport, "direction", "н/д")} />
              <StateLine label="Transport" value={stringField(outboundReport, "transport", "н/д")} />
              <StateLine label="Fabric control endpoint" value={stringField(outboundReport, "fabric_control_endpoint", "н/д")} />
              <StateLine label="Reverse usable" value={stringField(outboundReport, "usable_for_inbound_control", "н/д")} />
              <StateLine label="Inbound required" value={stringField(outboundReport, "inbound_listener_required", "н/д")} />
              <StateLine label="Relay ready" value={stringField(outboundReport, "peer_connection_relay_ready", "0")} />
              <StateLine label="Waiting rendezvous" value={stringField(outboundReport, "peer_connection_waiting", "0")} />
              <StateLine label="Rendezvous leases" value={stringField(outboundReport, "rendezvous_lease_count", "0")} />
              <StateLine label="Listener conflict" value={stringField(outboundReport, "listener_port_conflict", "false")} />
            </div>
          </section>

          <section className="nodePanel">
            <h4>Registry runtime</h4>
            <div className="stateList">
              <StateLine label="Status" value={stringField(registryRuntimeReport, "status", "не прислан")} />
              <StateLine label="Reason" value={stringField(registryRuntimeReport, "status_reason", "н/д")} />
              <StateLine label="Mode" value={stringField(registryRuntimeReport, "mode", "н/д")} />
              <StateLine label="Transport" value={stringField(registryRuntimeReport, "transport", "н/д")} />
              <StateLine label="Resolved services" value={String(numberField(registryRuntimeReport, "resolved_service_count", 0))} />
              <StateLine label="Resolved core services" value={String(numberField(registryRuntimeReport, "resolved_core_service_count", 0))} />
              <StateLine label="Active records" value={String(numberField(registryRuntimeReport, "active_service_count", 0))} />
              <StateLine label="Candidate records" value={String(numberField(registryRuntimeReport, "candidate_service_count", 0))} />
              <StateLine label="Last live probe" value={stringField(registryRuntimeReport, "last_live_probe_at", "н/д")} />
            </div>
          </section>

          <section className="nodePanel">
            <h4>Наличие сетевых отчетов</h4>
            <div className="summaryChips">
              {networkDiagnostics.map((item) => (
                <span key={item} className={item.includes("не прислан") || item.includes("не загружен") ? "pill warn" : "pill good"}>
                  {item}
                </span>
              ))}
            </div>
            {!endpointReport && !listenerReport && (
              <p className="muted">
                У этого узла есть heartbeat/mesh manager данные, но агент не передал адресный отчет. До обновления агента или включения endpoint/listener report панель может показать связи и config peers, но не может достоверно назвать локальный listen address.
              </p>
            )}
          </section>

          <section className="nodePanel">
            <h4>Endpoint candidates узла</h4>
            <DataTable
              columns={["id", "address", "transport", "reachability", "mode", "nat", "priority", "verified"]}
              rows={listenerCandidates.map((candidate) => [
                stringField(candidate, "endpoint_id", "н/д"),
                stringField(candidate, "address", "н/д"),
                stringField(candidate, "transport", "н/д"),
                stringField(candidate, "reachability", "н/д"),
                stringField(candidate, "connectivity_mode", "н/д"),
                stringField(candidate, "nat_type", "н/д"),
                stringField(candidate, "priority", "н/д"),
                stringField(candidate, "last_verified_at", "н/д"),
              ])}
            />
          </section>

          <div className="nodeDetailGrid">
            <section className="nodePanel">
              <h4>Рабочие peer endpoints из config</h4>
              <DataTable
                columns={["peer", "endpoint"]}
                rows={configuredPeerEndpoints.map(([peerID, endpoint]) => [nodeName(allNodes, peerID), endpoint])}
              />
            </section>
            <section className="nodePanel">
              <h4>Резервные кандидаты peer</h4>
              <DataTable
                columns={["peer", "address", "transport", "reachability", "mode", "priority"]}
                rows={reservePeerCandidates.slice(0, 20).map(({ peerID, candidate }) => [
                  nodeName(allNodes, peerID),
                  candidate.address,
                  candidate.transport,
                  candidate.reachability,
                  candidate.connectivity_mode,
                  String(candidate.priority),
                ])}
              />
            </section>
          </div>

          <section className="nodePanel">
            <h4>Активные связи этого узла</h4>
            <DataTable
              columns={["peer", "направление", "тип", "статус", "latency", "quality", "путь", "наблюдение"]}
              rows={latestLinks.slice(0, 20).map((link) => {
                const peerID = link.source_node_id === node.id ? link.target_node_id : link.source_node_id;
                return [
                  nodeName(allNodes, peerID),
                  link.source_node_id === node.id ? "out" : "in",
                  meshLinkObservationLabel(link),
                  link.link_status,
                  link.latency_ms == null ? "н/д" : `${link.latency_ms}мс`,
                  link.quality_score == null ? "н/д" : String(link.quality_score),
                  meshLinkRoutePathSummary(link, allNodes),
                  formatDate(link.observed_at),
                ];
              })}
            />
            {failedLinks.length > 0 && <p className="muted">Проблемных связей: {failedLinks.length}. Их статус виден в таблице выше.</p>}
          </section>

          <section className="nodePanel">
            <h4>Проверка адресов peer-to-peer</h4>
            <DataTable
              columns={["peer", "status", "selected endpoint", "candidate", "latency", "attempts", "failure"]}
              rows={managerProbeResults.slice(0, 20).map((result) => [
                nodeName(allNodes, stringField(result, "node_id", "")),
                stringField(result, "link_status", "н/д"),
                stringField(result, "selected_endpoint", stringField(result, "endpoint", "н/д")),
                stringField(result, "selected_candidate_id", "н/д"),
                stringField(result, "latency_ms", "н/д"),
                peerCandidateProbeSummary(result),
                stringField(result, "failure_reason", "нет"),
              ])}
            />
          </section>
        </>
      )}

      {activeTab === "mesh" && (
        <>
          <div className="nodeDetailGrid">
            <section className="nodePanel">
              <h4>Mesh control authority</h4>
              <div className="stateList">
                <StateLine label="Recovery" value={meshRecoverySummary(latestHeartbeat)} />
                <StateLine label="Intents" value={meshConnectionIntentSummary(latestHeartbeat)} />
                <StateLine label="Manager" value={meshConnectionManagerSummary(latestHeartbeat)} />
                <StateLine label="Rendezvous" value={meshRendezvousLeaseSummary(latestHeartbeat)} />
                <StateLine label="Path decisions" value={meshRoutePathDecisionSummary(latestHeartbeat)} />
                <StateLine label="Route generation" value={meshRouteGenerationSummary(latestHeartbeat)} />
                <StateLine label="Route health" value={meshRouteHealthConfigSummary(latestHeartbeat)} />
                <StateLine
                  label="Service-channel feedback"
                  value={
                    serviceChannelFeedback
                      ? `${serviceChannelFeedback.healthy_route_count} healthy / ${serviceChannelFeedback.degraded_route_count} degraded / ${serviceChannelFeedback.fenced_route_count} fenced`
                      : "н/д"
                  }
                />
                <StateLine
                  label="Recovery policy"
                  value={
                    serviceChannelFeedback?.recovery_policy
                      ? `${serviceChannelFeedback.recovery_policy.source} p${serviceChannelFeedback.recovery_policy.hysteresis_penalty} promote ${serviceChannelFeedback.recovery_policy.promotion_min_samples}`
                      : "н/д"
                  }
                />
                <StateLine
                  label="Route policy"
                  value={
                    syntheticConfig?.route_path_decisions?.recovery_policy
                      ? `${syntheticConfig.route_path_decisions.recovery_policy.source} fail/drop/slow ${syntheticConfig.route_path_decisions.recovery_policy.demotion_failure_threshold}/${syntheticConfig.route_path_decisions.recovery_policy.demotion_drop_threshold}/${syntheticConfig.route_path_decisions.recovery_policy.demotion_slow_threshold}`
                      : "н/д"
                  }
                />
                <StateLine label="Config version" value={syntheticConfig?.config_version || "н/д"} />
              </div>
            </section>
            <section className="nodePanel">
              <h4>Scoped config counts</h4>
              <div className="stateList">
                <StateLine label="Peer endpoints" value={String(configuredPeerEndpoints.length)} />
                <StateLine label="Endpoint candidates" value={String(configuredPeerCandidates.length)} />
                <StateLine label="Peer directory" value={String(syntheticConfig?.peer_directory?.length || 0)} />
                <StateLine label="Recovery seeds" value={String(syntheticConfig?.recovery_seeds?.length || 0)} />
                <StateLine label="Rendezvous leases" value={String(syntheticConfig?.rendezvous_leases?.length || 0)} />
                <StateLine label="Routes" value={String(syntheticConfig?.routes?.length || 0)} />
                <StateLine label="Fenced routes" value={String(serviceChannelFeedback?.fenced_route_count || 0)} />
                <StateLine label="Remediation commands" value={String(serviceChannelRemediationCommands.length)} />
                <StateLine
                  label="Feedback provenance"
                  value={
                    serviceChannelFeedback
                      ? `missing ${serviceChannelFeedback.missing_provenance_count || 0} / stale policy ${serviceChannelFeedback.stale_policy_count || 0} / stale gen ${serviceChannelFeedback.stale_generation_count || 0}`
                      : "н/д"
                  }
                />
              </div>
            </section>
          </div>
          <section className="nodePanel">
            <h4>Route decisions</h4>
            <DataTable
              columns={["route", "replacement", "source", "destination", "effective hops", "decision", "score", "expires"]}
              rows={(syntheticConfig?.route_path_decisions?.decisions || []).map((decision) => [
                shortId(decision.route_id),
                decision.replacement_route_id ? shortId(decision.replacement_route_id) : "нет",
                nodeName(allNodes, decision.source_node_id),
                nodeName(allNodes, decision.destination_node_id),
                decision.effective_hops.map((id) => trimNodeName(nodeName(allNodes, id))).join(" > "),
                decision.decision_source || (decision.selected_relay_id ? nodeName(allNodes, decision.selected_relay_id) : "direct"),
                decision.path_score == null ? "н/д" : String(decision.path_score),
                formatDate(decision.expires_at),
              ])}
            />
          </section>
          {serviceChannelRemediationCommands.length > 0 && (
            <section className="nodePanel">
              <h4>Service-channel remediation commands</h4>
              <DataTable
                columns={["channel", "action", "primary", "replacement", "guard", "execution", "reason", "expires"]}
                rows={serviceChannelRemediationCommands.slice(0, 20).map((command) => [
                  shortId(command?.channel_id || ""),
                  <span className="pill warn">{statusLabel(command?.action || "")}</span>,
                  command?.primary_route_id ? shortId(command.primary_route_id) : "н/д",
                  command?.replacement_route_id ? shortId(command.replacement_route_id) : "н/д",
                  <span className={`pill ${command?.guard_status === "rejected" ? "bad" : command?.guard_status === "allowed" ? "good" : ""}`}>
                    {command?.guard_status ? statusLabel(command.guard_status) : "н/д"}
                  </span>,
                  <span className={`pill ${remediationExecutionTone(command?.execution_status)}`}>
                    {command?.execution_status ? statusLabel(command.execution_status) : "н/д"}
                    {command?.execution_reason ? ` / ${statusLabel(command.execution_reason)}` : ""}
                  </span>,
                  command?.reason || "н/д",
                  command?.expires_at ? formatDate(command.expires_at) : "н/д",
                ])}
              />
            </section>
          )}
          <section className="nodePanel">
            <h4>Service-channel route feedback</h4>
            <DataTable
              columns={["route", "service", "status", "recovery", "score", "reasons", "failures", "duration", "expires"]}
              rows={serviceChannelFeedbackItems.slice(0, 40).map((item) => [
                shortId(item.route_id),
                item.service_class,
                <span className={`pill ${serviceChannelFeedbackTone(item.feedback_status)}`}>{statusLabel(item.feedback_status)}</span>,
                item.recovery_state ? (
                  <span className={`pill ${serviceChannelRecoveryTone(item.recovery_state)}`}>
                    {item.recovery_demoted ? `demoted ${item.recovery_reason ? statusLabel(item.recovery_reason) : ""}` : item.recovery_promoted ? "promoted" : statusLabel(item.recovery_state)}
                    {item.recovery_hysteresis_penalty ? ` -${item.recovery_hysteresis_penalty}` : ""}
                  </span>
                ) : item.stale_policy || item.stale_generation ? (
                  <span className="pill warn">{statusLabel(item.stale_reason || "stale")}</span>
                ) : item.provenance_missing ? (
                  <span className="pill warn">provenance missing</span>
                ) : (
                  "нет"
                ),
                String(item.score_adjustment),
                (item.reasons || []).join(", ") || "нет",
                String(item.consecutive_failures || 0),
                item.last_send_duration_ms == null ? "н/д" : `${item.last_send_duration_ms}мс`,
                formatDate(item.expires_at),
              ])}
            />
            {serviceChannelFeedbackItems.length === 0 && (
              <p className="muted">Пока нет свежих наблюдений. Узел будет присылать их после реального traffic через service-channel runtime.</p>
            )}
          </section>
        </>
      )}

      {activeTab === "services" && (
        <>
          <div className="nodeDetailGrid">
            <section className="nodePanel">
              <h4>{labels.nodeRoles}</h4>
              <div className="serviceTags">
                {activeRoles.length === 0 && <p className="muted">{labels.noRoles}</p>}
                {activeRoles.map((role) => (
                  <div className="serviceTag" key={role.id}>
                    <strong>{roleDisplayLabel(role.role)}</strong>
                    <span>{role.organization_id ? `organization: ${shortId(role.organization_id)}` : "cluster-wide"}</span>
                    <small>{formatDate(role.assigned_at)}</small>
                    <span className={`pill ${capabilityPillTone(role.role, latestHeartbeat)}`}>{capabilityLabel(role.role, latestHeartbeat, labels)}</span>
                  </div>
                ))}
              </div>
            </section>

            <section className="nodePanel">
              <h4>Capabilities</h4>
              <div className="summaryChips">
                {capabilityEntries.length === 0 && <span className="muted">Нет capability heartbeat.</span>}
                {capabilityEntries.slice(0, 40).map(([key, value]) => (
                  <span className={value === true ? "pill good" : "pill"} key={key}>
                    {key}
                  </span>
                ))}
              </div>
            </section>
          </div>

          <div className="nodeDetailGrid">
            <section className="nodePanel">
              <h4>{labels.desiredServices}</h4>
              <DataTable
                columns={["service", "desired", "runtime", "version", "updated"]}
                rows={desiredWorkloads.map((workload) => [
                  workload.service_type,
                  statusLabel(workload.desired_state),
                  workload.runtime_mode,
                  workload.version || "не закреплена",
                  formatDate(workload.updated_at),
                ])}
              />
            </section>

            <section className="nodePanel">
              <h4>{labels.observedServices}</h4>
              <DataTable
                columns={["service", "reported", "runtime", "version", "observed"]}
                rows={observedWorkloads.map((workload) => [
                  workload.service_type,
                  statusLabel(workload.reported_state),
                  workload.runtime_mode,
                  workload.version || "н/д",
                  formatDate(workload.observed_at),
                ])}
              />
            </section>
          </div>
        </>
      )}

      {activeTab === "telemetry" && (
        <>
          <section className="nodePanel">
            <h4>{labels.nodeTelemetry}</h4>
            <TelemetryStrip items={telemetry} emptyText={labels.noTelemetry} />
            <div className="stateList">
              <StateLine label="Disk" value={`${formatBytes(latestTelemetry?.disk_used_bytes)} / ${formatBytes(latestTelemetry?.disk_total_bytes)}`} />
              <StateLine label="Network RX/TX" value={`${formatBytes(latestTelemetry?.network_rx_bytes)} / ${formatBytes(latestTelemetry?.network_tx_bytes)}`} />
              <StateLine label="Payload" value={latestTelemetry?.payload ? compactJSON(latestTelemetry.payload) : "н/д"} />
            </div>
          </section>
          <section className="nodePanel">
            <h4>{labels.recentHeartbeats}</h4>
            <DataTable
              columns={["состояние", "версия", "listener", "mesh recovery", "mesh intents", "rv leases", "path decisions", "route gen", "route health", "наблюдение"]}
              rows={heartbeats.slice(0, 10).map((heartbeat) => [
                heartbeat.health_status,
                heartbeat.reported_version || "неизвестно",
                fabricListenerSummary(heartbeat),
                meshRecoverySummary(heartbeat),
                meshConnectionIntentSummary(heartbeat),
                meshRendezvousLeaseSummary(heartbeat),
                meshRoutePathDecisionSummary(heartbeat),
                meshRouteGenerationSummary(heartbeat),
                meshRouteHealthConfigSummary(heartbeat),
                formatDate(heartbeat.observed_at),
              ])}
            />
          </section>
        </>
      )}

      {activeTab === "updates" && (
        <>
          <div className="nodeDetailGrid">
            <section className="nodePanel">
              <h4>Текущая сборка</h4>
              <div className="stateList">
                <StateLine label="Node-agent version" value={node.reported_version || latestHeartbeat?.reported_version || "неизвестно"} />
                <StateLine label="План" value={updatePlan ? `${updatePlan.action}: ${updatePlan.reason}` : "не загружен"} />
                <StateLine label="Product" value={updatePlan?.product || "rap-node-agent"} />
                <StateLine label="Target" value={updatePlan?.target_version || "н/д"} />
                <StateLine label="Strategy" value={updatePlan?.strategy || "н/д"} />
                <StateLine label="Rollback" value={updatePlan?.rollback_allowed ? "разрешен" : "нет"} />
                <StateLine label="Artifact" value={updatePlan?.artifact ? `${updatePlan.artifact.kind} ${updatePlan.artifact.os}/${updatePlan.artifact.arch}` : "н/д"} />
              </div>
              <div className="actions">
                <button className="primary" disabled={!onSetUpdatePolicy} onClick={() => onSetUpdatePolicy?.(node, "rap-node-agent", null)}>
                  Node-agent latest
                </button>
                <button className="ghost" disabled={!onSetUpdatePolicy || !updatePlan?.target_version} onClick={() => onSetUpdatePolicy?.(node, "rap-node-agent", updatePlan?.target_version || null)}>
                  Повторить target
                </button>
                <button className="ghost" disabled={!onSetUpdatePolicy} onClick={() => onSetUpdatePolicy?.(node, "rap-host-agent", null)}>
                  Host-agent latest
                </button>
              </div>
              <p className="muted">
                Latest означает policy без закрепленной версии: updater будет брать свежий active release своего канала при следующем цикле или heartbeat hint.
              </p>
            </section>

            <section className="nodePanel">
              <h4>Последние отчеты updater</h4>
              <div className="stateList">
                <StateLine label="Updater health" value={`${updaterHealth.label}: ${updaterHealth.detail}`} />
                <StateLine label="rap-node-agent" value={updateStatusLine(latestNodeAgentUpdate)} />
                <StateLine label="rap-host-agent" value={updateStatusLine(latestHostAgentUpdate)} />
                <StateLine label="Всего отчетов" value={String(updateStatuses.length)} />
                <StateLine label="Последний отчет" value={formatDate(latestAnyUpdate?.observed_at)} />
              </div>
              <div className="summaryChips">
                <span className={`pill ${updaterHealth.tone}`}>{updaterHealth.label}</span>
                {latestNodeAgentUpdate && <span className={`pill ${updateStatusTone(latestNodeAgentUpdate)}`}>node-agent: {latestNodeAgentUpdate.status}</span>}
                {latestHostAgentUpdate && <span className={`pill ${updateStatusTone(latestHostAgentUpdate)}`}>host-agent: {latestHostAgentUpdate.status}</span>}
                {!latestNodeAgentUpdate && !latestHostAgentUpdate && <span className="pill warn">updater пока не отчитался</span>}
              </div>
            </section>
          </div>

          <section className="nodePanel">
            <h4>История обновлений</h4>
            <DataTable
              columns={["product", "current", "target", "phase", "status", "attempt", "error", "observed"]}
              rows={updateStatuses.slice(0, 40).map((status) => [
                status.product,
                status.current_version || "н/д",
                status.target_version || "н/д",
                status.phase,
                <span className={`pill ${updateStatusTone(status)}`}>{status.status}</span>,
                status.attempt_id ? shortId(status.attempt_id) : "н/д",
                status.error_message || "нет",
                formatDate(status.observed_at),
              ])}
            />
          </section>

          <section className="nodePanel">
            <h4>Windows repair/update command</h4>
            <p className="muted">
              Для существующего Windows-узла эта команда переустанавливает wrapper updater без нового join-token, сохраняет local state и запускает обновление до актуальной сборки.
            </p>
            <div className="stateList compact">
              <StateLine label="Когда выполнять" value="если updater stale, host-agent не отчитался или Windows-узел не доходит до target version" />
              <StateLine label="Fabric control endpoint" value={externalPreferredFabricControlEndpoint()} />
              <StateLine label="Join-token" value="не нужен для repair существующего узла" />
            </div>
            <div className="actions">
              <button
                className="primary"
                onClick={() => downloadTextFile(windowsRepairUpdaterCmdFileName(node), windowsRepairUpdaterCmdCommand(node, primaryClusterID))}
              >
                Скачать repair .cmd
              </button>
              <button
                className="ghost"
                onClick={() => void copyTextToClipboard(windowsRepairUpdaterCmdCommand(node, primaryClusterID))}
              >
                Скопировать команду
              </button>
            </div>
            <pre className="codePreview">{windowsRepairUpdaterCmdCommand(node, primaryClusterID)}</pre>
          </section>

          <section className="nodePanel">
            <h4>Linux repair/update command</h4>
            <p className="muted">
              Для существующего Ubuntu/Linux-узла эта команда восстанавливает systemd updater без нового join-token, сохраняет local state и делает одноразовую проверку обновления.
            </p>
            <div className="stateList compact">
              <StateLine label="Когда выполнять" value="если host-agent не отчитался, updater stale или Linux-узел не доходит до target version" />
              <StateLine label="Fabric control endpoint" value={externalPreferredFabricControlEndpoint()} />
              <StateLine label="Join-token" value="не нужен для repair существующего узла" />
            </div>
            <div className="actions">
              <button
                className="primary"
                onClick={() => downloadTextFile(linuxRepairUpdaterShFileName(node), linuxRepairUpdaterShCommand(node, primaryClusterID))}
              >
                Скачать repair .sh
              </button>
              <button
                className="ghost"
                onClick={() => void copyTextToClipboard(linuxRepairUpdaterShCommand(node, primaryClusterID))}
              >
                Скопировать команду
              </button>
            </div>
            <pre className="codePreview">{linuxRepairUpdaterShCommand(node, primaryClusterID)}</pre>
          </section>

          <section className="nodePanel">
            <h4>Payload последнего отчета</h4>
            <div className="rawDetailsGrid">
              <RawJSON title="rap-node-agent update status" value={latestNodeAgentUpdate} />
              <RawJSON title="rap-host-agent update status" value={latestHostAgentUpdate} />
              <RawJSON title="Update plan" value={updatePlan} />
            </div>
          </section>
        </>
      )}

      {activeTab === "raw" && (
        <section className="nodePanel">
          <h4>Raw данные узла</h4>
          <div className="rawDetailsGrid">
            <RawJSON title="Последний heartbeat metadata" value={latestHeartbeat?.metadata} />
            <RawJSON title="Heartbeat capabilities" value={latestHeartbeat?.capabilities} />
            <RawJSON title="Heartbeat service states" value={latestHeartbeat?.service_states} />
            <RawJSON title="Synthetic mesh config" value={syntheticConfig} />
            <RawJSON title="Listener report" value={listenerReport} />
            <RawJSON title="Endpoint report" value={endpointReport} />
            <RawJSON title="Peer recovery report" value={recoveryReport} />
            <RawJSON title="Connection intent report" value={intentReport} />
            <RawJSON title="Connection manager report" value={managerReport} />
            <RawJSON title="Rendezvous lease report" value={rendezvousReport} />
            <RawJSON title="Route decision report" value={routeDecisionReport} />
            <RawJSON title="Route generation report" value={routeGenerationReport} />
            <RawJSON title="Route health report" value={routeHealthReport} />
          </div>
        </section>
      )}
    </div>
  );
}

function RawJSON({ title, value }: { title: string; value: unknown }) {
  return (
    <details className="rawBlock">
      <summary>{title}</summary>
      <pre>{value == null ? "н/д" : JSON.stringify(value, null, 2)}</pre>
    </details>
  );
}

type NodeRuntimeConnectivity = {
  agentLabel: string;
  agentTone: string;
  clientLabel: string;
  clientTone: string;
  outboundLabel: string;
  outboundTone: string;
  inboundLabel: string;
  inboundTone: string;
  address: string;
  detail: string;
};

type NodeSignalFreshness = {
  state: "fresh" | "lagging" | "stale" | "no_signal";
  at?: string | null;
  ageSeconds?: number | null;
};

function RuntimeBadges({ runtime }: { runtime: NodeRuntimeConnectivity }) {
  return (
    <div className="runtimeBadges">
      <span className={`pill ${runtime.agentTone}`}>{runtime.agentLabel}</span>
      <span className={`pill ${runtime.clientTone}`}>{runtime.clientLabel}</span>
      <span className={`pill ${runtime.outboundTone}`}>{runtime.outboundLabel}</span>
      <span className={`pill ${runtime.inboundTone}`}>{runtime.inboundLabel}</span>
    </div>
  );
}

function NodeLinkEndpoint({
  node,
  fallback,
  heartbeatsByNode,
  meshLinks,
}: {
  node?: ClusterNode;
  fallback: string;
  heartbeatsByNode: Record<string, NodeHeartbeat[]>;
  meshLinks: MeshLink[];
}) {
  if (!node) {
    return fallback;
  }
  const runtime = nodeRuntimeConnectivity(node, heartbeatsByNode[node.id] || [], meshLinks);
  return (
    <div className="nodeEndpointCell">
      <strong>{node.name}</strong>
      <RuntimeBadges runtime={runtime} />
      <small>{runtime.address}</small>
    </div>
  );
}

function FabricTopology({
  nodes,
  links,
  heartbeatsByNode,
  rolesByNode,
  workloadsByNode,
  labels,
  emptyText,
}: {
  nodes: ClusterNode[];
  links: MeshLink[];
  heartbeatsByNode: Record<string, NodeHeartbeat[]>;
  rolesByNode: Record<string, RoleAssignment[]>;
  workloadsByNode: Record<string, WorkloadStatus[]>;
  labels: Record<string, string>;
  emptyText: string;
}) {
  const [hoverTooltip, setHoverTooltip] = useState<{ x: number; y: number; title: string; lines: string[] } | null>(null);
  if (nodes.length === 0) {
    return <EmptyState title="Нет узлов" text="Одобренные node-agent появятся на карте после первого heartbeat." />;
  }

  const latestLinks = latestLinkObservations(links).filter((link) => link.source_node_id !== link.target_node_id);
  const nodesById = new Map(nodes.map((node) => [node.id, node] as const));
  const directLinks = latestLinks
    .filter((link) => isDirectPeerConnectionLink(link) && !isMeshLinkStale(link, nodesById))
    .map((link) => ({ link, status: topologyLinkRuntimeStatus(link, latestLinks, nodesById), kind: "direct" as const }))
    .filter((item) => item.status === "reachable" || item.status === "one_way");
  const relayLinks = latestLinks
    .filter((link) => isRelayPeerConnectionLink(link) && !isMeshLinkStale(link, nodesById))
    .map((link) => ({ link, status: topologyLinkRuntimeStatus(link, latestLinks, nodesById), kind: "relay" as const }))
    .filter((item) => item.status === "reachable" || item.status === "one_way");
  const routeHealthLinks = latestLinks
    .filter((link) => meshLinkMetadataString(link, "observation_type") === "synthetic_route_health" && !isMeshLinkStale(link, nodesById) && link.link_status === "reachable")
    .map((link) => ({ link, status: "reachable" as TopologyLinkStatus, kind: "route" as const }));
  const visibleLinks = topologyVisibleTransportLinks(directLinks, relayLinks, routeHealthLinks);
  const staleLinks = latestLinks.filter((link) => isMeshLinkStale(link, nodesById));
  const problemLinks = latestLinks.filter((link) => !isMeshLinkStale(link, nodesById) && link.link_status !== "reachable");
  const bidirectionalPairs = countBidirectionalPairs(visibleLinks.map((item) => item.link));
  const nodeModes = new Map(nodes.map((node) => [node.id, fabricNodeRuntimeMode(heartbeatsByNode[node.id]?.[0])] as const));
  const activeNodes = [...nodeModes.values()].filter((mode) => mode.mode === "active").length;
  const passiveNodes = [...nodeModes.values()].filter((mode) => mode.mode === "passive").length;
  const mixedNodes = [...nodeModes.values()].filter((mode) => mode.mode === "mixed").length;
  const viewBox = topologyViewBox(nodes.length);
  const nodeRadius = topologyNodeRadius(nodes.length);
  const nodePositions = topologyNodePositions(nodes, viewBox.height, nodeRadius);
  const meshStatusByNode = new Map(nodes.map((node) => [node.id, topologyNodeMeshStatus(node.id, visibleLinks)] as const));

  return (
    <div className="topologyShell">
      <svg className="topologySvg" viewBox={`0 0 ${viewBox.width} ${viewBox.height}`} role="img" aria-label="Карта трафика узлов Fabric">
        <defs>
          <marker id="arrow" markerHeight="8" markerWidth="8" orient="auto" refX="7" refY="4">
            <path d="M0,0 L8,4 L0,8 Z" fill="currentColor" />
          </marker>
        </defs>

        {visibleLinks.map(({ link, status, kind }) => {
          const source = nodePositions.get(link.source_node_id);
          const target = nodePositions.get(link.target_node_id);
          if (!source || !target) {
            return null;
          }
          const reverseVisible = visibleLinks.some((item) => item.link.source_node_id === link.target_node_id && item.link.target_node_id === link.source_node_id);
          const laneSign = topologyStableLaneSign(link.source_node_id, link.target_node_id, kind);
          const edge = topologyRoutedEdgePath({
            source,
            target,
            sourceNodeID: link.source_node_id,
            targetNodeID: link.target_node_id,
            positions: nodePositions,
            nodeRadius,
            endpointOffset: nodeRadius + 8,
            laneOffset: reverseVisible ? 9 : 0,
            laneSign,
            routeKind: kind,
          });
          const tooltip = topologyTooltipFromText(topologyLinkTooltip(link, nodes, status));
          const tooltipPoint = topologyTooltipPoint(edge.labelX, edge.labelY, viewBox.width, viewBox.height);
          return (
            <g
              key={`${kind}-${link.id || `${link.source_node_id}-${link.target_node_id}`}`}
              className="topologyLinkGroup"
              onMouseEnter={() => setHoverTooltip({ ...tooltip, ...tooltipPoint })}
              onMouseLeave={() => setHoverTooltip(null)}
            >
              <title>{[tooltip.title, ...tooltip.lines].join("\n")}</title>
              <path
                d={edge.d}
                className={`topologyLink ${linkTone(link, status)} ${kind}`}
                markerEnd="url(#arrow)"
              />
              {visibleLinks.length <= Math.max(6, nodes.length) && (
                <text x={edge.labelX} y={edge.labelY - 8} className="topologyLinkLabel">
                  {meshLinkCompactLabel(link, status, kind)}
                </text>
              )}
            </g>
          );
        })}
        {nodes.map((node) => {
          const point = nodePositions.get(node.id)!;
          const labelSize = topologyNodeLabelSize(nodes.length);
          const meshStatus = meshStatusByNode.get(node.id) || "isolated";
          const mode = nodeModes.get(node.id) || { mode: "unknown", detail: "no heartbeat" };
          const webIngressStatus = webIngressReceiverStatus(heartbeatsByNode[node.id]?.[0]);
          const tooltip = topologyTooltipFromText(
            topologyNodeTooltip(node, mode, meshStatus, webIngressStatus, heartbeatsByNode[node.id]?.[0], rolesByNode[node.id] || [], workloadsByNode[node.id] || []),
          );
          const tooltipPoint = topologyTooltipPoint(point.x, point.y + nodeRadius + 12, viewBox.width, viewBox.height);
          return (
            <g
              key={node.id}
              className="topologyNode"
              onMouseEnter={() => setHoverTooltip({ ...tooltip, ...tooltipPoint })}
              onMouseLeave={() => setHoverTooltip(null)}
            >
              <title>{[tooltip.title, ...tooltip.lines].join("\n")}</title>
              <circle cx={point.x} cy={point.y} r={nodeRadius} className={`topologyNodeCircle ${node.health_status} ${mode.mode} web-${webIngressStatus}`} />
              <text x={point.x} y={point.y - labelSize.nameOffset} className="topologyNodeName" style={{ fontSize: labelSize.name }}>
                {trimNodeName(node.name, labelSize.maxChars)}
              </text>
              <text x={point.x} y={point.y + labelSize.metaOffset} className="topologyNodeMeta" style={{ fontSize: labelSize.meta }}>
                {topologyNodeCompactStatus(mode.mode, meshStatus)}
              </text>
            </g>
          );
        })}
        {visibleLinks.length === 0 && (
          <text x={viewBox.width / 2} y={viewBox.height - 34} className="topologyEmpty">
            {emptyText}
          </text>
        )}
        {hoverTooltip && (
          <foreignObject x={hoverTooltip.x} y={hoverTooltip.y} width="360" height="190" className="topologyTooltipObject">
            <div className="topologyTooltip">
              <strong>{hoverTooltip.title}</strong>
              {hoverTooltip.lines.slice(0, 6).map((line) => (
                <span key={line}>{line}</span>
              ))}
            </div>
          </foreignObject>
        )}
      </svg>
      <div className="topologyLegend">
        <span>
          <i className="legendLine observed" /> direct: {directLinks.length}
        </span>
        <span>
          <i className="legendLine relay" /> relay: {relayLinks.length}
        </span>
        <span>
          <i className="legendLine route" /> route-health: {routeHealthLinks.length}
        </span>
        <span>
          <i className="legendLine observed" /> bidirectional pairs: {bidirectionalPairs}
        </span>
        <span>
          <i className="legendLine stale" /> stale/problem: {staleLinks.length}/{problemLinks.length}
        </span>
        <span>
          <i className="legendDot webReady" /> web ready
        </span>
        <span>
          <i className="legendDot webDegraded" /> web degraded
        </span>
        <span>
          <i className="legendDot webBlocked" /> web blocked
        </span>
        <span>active/passive/mixed: {activeNodes}/{passiveNodes}/{mixedNodes}</span>
      </div>
      <details className="sectionBlock fabricNodeDiagnostics">
        <summary>Диагностика узлов ({nodes.length})</summary>
        <div className="serviceTags">
          {nodes.map((node) => (
            <div className="serviceTag" key={node.id}>
              <strong>{node.name}</strong>
              <span>{statusLabel(node.health_status)} / {statusLabel(nodeModes.get(node.id)?.mode || "unknown")} / mesh {statusLabel(meshStatusByNode.get(node.id) || "isolated")}</span>
              <small>{webIngressReceiverSummary(heartbeatsByNode[node.id]?.[0])}</small>
              <small>{summarizeRoles(rolesByNode[node.id] || [])}</small>
              <small>{summarizeWorkloads(workloadsByNode[node.id] || [])}</small>
            </div>
          ))}
        </div>
      </details>
    </div>
  );
}

type TopologyLinkStatus = "reachable" | "one_way" | "stale" | "degraded" | "unreachable" | "unknown";
type TopologyRouteKind = "direct" | "relay" | "route";
type TopologyLinkItem = { link: MeshLink; status: TopologyLinkStatus; kind: TopologyRouteKind };

function topologyVisibleTransportLinks(directLinks: TopologyLinkItem[], relayLinks: TopologyLinkItem[], routeHealthLinks: TopologyLinkItem[]) {
  const visible: TopologyLinkItem[] = [];
  const seen = new Set<string>();
  const add = (item: TopologyLinkItem) => {
    const key = `${item.link.source_node_id}->${item.link.target_node_id}`;
    if (seen.has(key)) {
      return;
    }
    seen.add(key);
    visible.push(item);
  };
  directLinks.forEach(add);
  relayLinks.forEach(add);
  routeHealthLinks.forEach(add);
  return visible;
}

function topologyNodeMeshStatus(nodeId: string, links: { link: MeshLink; status: TopologyLinkStatus }[]) {
  const peerLinks = links.filter((item) => item.link.source_node_id !== item.link.target_node_id && (item.link.source_node_id === nodeId || item.link.target_node_id === nodeId));
  if (peerLinks.some((item) => item.status === "reachable" || item.status === "one_way")) {
    return "connected";
  }
  if (peerLinks.some((item) => item.status !== "stale")) {
    return "degraded";
  }
  return "isolated";
}

function topologyNodeCompactStatus(mode: string, meshStatus: string) {
  const modeLabel = mode === "active" ? "A" : mode === "passive" ? "P" : mode === "mixed" ? "M" : "?";
  const meshLabel = meshStatus === "connected" ? "mesh" : meshStatus === "degraded" ? "degr" : "iso";
  return `${modeLabel} / ${meshLabel}`;
}

function topologyTooltipFromText(text: string) {
  const [title, ...lines] = text.split("\n").filter(Boolean);
  return { title: title || "Fabric", lines };
}

function topologyTooltipPoint(x: number, y: number, width: number, height: number) {
  const tooltipWidth = 360;
  const tooltipHeight = 190;
  return {
    x: Math.min(Math.max(18, x + 16), Math.max(18, width - tooltipWidth - 18)),
    y: Math.min(Math.max(18, y + 12), Math.max(18, height - tooltipHeight - 18)),
  };
}

function topologyNodeTooltip(
  node: ClusterNode,
  mode: { mode: string; detail: string },
  meshStatus: string,
  webIngressStatus: string,
  heartbeat: NodeHeartbeat | undefined,
  roles: RoleAssignment[],
  workloads: WorkloadStatus[],
) {
  return [
    node.name,
    `health: ${statusLabel(node.health_status)}`,
    `mode: ${statusLabel(mode.mode)} (${mode.detail})`,
    `mesh: ${statusLabel(meshStatus)}`,
    `web ingress: ${statusLabel(webIngressStatus)} - ${webIngressReceiverSummary(heartbeat)}`,
    `functions: ${summarizeRoles(roles)}`,
    `services: ${summarizeWorkloads(workloads)}`,
  ].join("\n");
}

function topologyLinkTooltip(link: MeshLink, nodes: ClusterNode[], status: TopologyLinkStatus) {
  const source = nodeName(nodes, link.source_node_id);
  const target = nodeName(nodes, link.target_node_id);
  const observed = formatDate(link.observed_at);
  const type = meshLinkMetadataString(link, "observation_type") || "link";
  const mode = meshLinkMetadataString(link, "transport_mode") || "direct";
  const endpoint = meshLinkRoutePathSummary(link, nodes);
  const latency = link.latency_ms == null ? "н/д" : `${link.latency_ms}мс`;
  return [
    `${source} -> ${target}`,
    `status: ${meshLinkTopologyLabel(link, nodes, status)}`,
    `type: ${type}`,
    `mode: ${mode}`,
    `latency: ${latency}`,
    `path: ${endpoint}`,
    `observed: ${observed}`,
  ].join("\n");
}

function meshLinkCompactLabel(link: MeshLink, status: TopologyLinkStatus, kind: TopologyRouteKind = "direct") {
  if (status === "one_way") {
    return "1w";
  }
  if (kind === "relay") {
    return "relay";
  }
  if (kind === "route") {
    return "route";
  }
  if (link.latency_ms != null && link.latency_ms > 0) {
    return `${link.latency_ms}мс`;
  }
  return "";
}

function topologyLinkRuntimeStatus(link: MeshLink, links: MeshLink[], nodesById: Map<string, ClusterNode>): TopologyLinkStatus {
  if (isMeshLinkStale(link, nodesById)) {
    return "stale";
  }
  if (link.link_status !== "reachable") {
    return link.link_status === "degraded" || link.link_status === "unreachable" ? link.link_status : "unknown";
  }
  const reverse = links.find((candidate) => candidate.source_node_id === link.target_node_id && candidate.target_node_id === link.source_node_id && !isMeshLinkStale(candidate, nodesById));
  if (!reverse || reverse.link_status !== "reachable") {
    return "one_way";
  }
  return "reachable";
}

function isDirectPeerConnectionLink(link: MeshLink) {
  if (link.link_status !== "reachable" || meshLinkMetadataString(link, "observation_type") !== "peer_connection_manager") {
    return false;
  }
  const mode = meshLinkMetadataString(link, "transport_mode");
  if (mode === "relay_quic" || meshLinkMetadataString(link, "relay_node_id")) {
    return false;
  }
  return link.metadata?.direct_candidate === true || mode === "direct_quic" || mode === "private_lan";
}

function isRelayPeerConnectionLink(link: MeshLink) {
  if (meshLinkMetadataString(link, "observation_type") !== "peer_connection_manager") {
    return false;
  }
  return meshLinkMetadataString(link, "transport_mode") === "relay_quic" || Boolean(meshLinkMetadataString(link, "relay_node_id"));
}

function countBidirectionalPairs(links: MeshLink[]) {
  const directed = new Set(links.map((link) => `${link.source_node_id}->${link.target_node_id}`));
  const pairs = new Set<string>();
  for (const link of links) {
    if (!directed.has(`${link.target_node_id}->${link.source_node_id}`)) {
      continue;
    }
    const ordered = [link.source_node_id, link.target_node_id].sort().join("<->");
    pairs.add(ordered);
  }
  return pairs.size;
}

function fabricNodeRuntimeMode(heartbeat?: NodeHeartbeat): { mode: "active" | "passive" | "mixed" | "unknown"; detail: string } {
  if (!heartbeat) {
    return { mode: "unknown", detail: "no heartbeat" };
  }
  const metadata = heartbeat.metadata || {};
  const endpointReport = objectField(metadata.mesh_endpoint_report);
  const listenerReport = objectField(metadata.mesh_listener_report);
  const managerReport = objectField(metadata.mesh_peer_connection_manager_report);
  const directReady = numberField(managerReport, "peer_connection_ready");
  const relayReady = numberField(managerReport, "peer_connection_relay_ready");
  const waitingRendezvous = numberField(managerReport, "peer_connection_waiting_rendezvous");
  const listenerStatus = stringField(listenerReport, "status", "");
  const connectivityMode = stringField(endpointReport, "connectivity_mode", "");
  const endpoint = firstStringField(endpointReport, ["peer_endpoint", "advertised_endpoint", "endpoint"]);
  const listening = listenerStatus === "listening" || listenerStatus === "auto_rebound";
  const passiveByMode = connectivityMode === "outbound_only" || waitingRendezvous > 0 || relayReady > directReady;
  const detailParts = [
    listening ? "listen" : "no-listen",
    directReady ? `direct${directReady}` : "",
    relayReady ? `relay${relayReady}` : "",
    endpoint ? endpoint.replace(/^quic:\/\//, "") : "",
  ].filter(Boolean);
  if (passiveByMode && directReady > 0) {
    return { mode: "mixed", detail: detailParts.join(" ") || "mixed" };
  }
  if (passiveByMode) {
    return { mode: "passive", detail: detailParts.join(" ") || "outbound/relay" };
  }
  if (listening || directReady > 0) {
    return { mode: "active", detail: detailParts.join(" ") || "direct" };
  }
  return { mode: "unknown", detail: detailParts.join(" ") || "no runtime" };
}

function webIngressReceiverSummary(heartbeat?: NodeHeartbeat) {
  const report = objectField(heartbeat?.metadata?.web_ingress_runtime_receiver_report);
  if (!report) {
    return "web ingress: no report";
  }
  const enabled = report.enabled === true || report.handler_installed === true;
  const keyCount = numberField(report, "trusted_key_count");
  const classes = arrayStrings(report.service_classes);
  const status = stringField(report, "status", "");
  const ready = report.quic_fabric_ready === true || status === "ready";
  const reason = stringField(report, "reason", enabled ? "ready" : "blocked");
  const error = stringField(report, "quic_fabric_error", "");
  const classText = classes.length > 0 ? classes.join(",") : "no classes";
  if (enabled) {
    const mode = ready ? "ready" : status || reason || "handler";
    return `web ingress: ${mode} / keys ${keyCount} / ${error || classText}`;
  }
  return `web ingress: ${reason}`;
}

function webIngressReceiverStatus(heartbeat?: NodeHeartbeat): "ready" | "degraded" | "blocked" | "missing" {
  const report = objectField(heartbeat?.metadata?.web_ingress_runtime_receiver_report);
  if (!report) {
    return "missing";
  }
  const status = stringField(report, "status", "");
  if (status === "ready" || status === "degraded" || status === "blocked") {
    return status;
  }
  if (report.handler_installed === true) {
    return "degraded";
  }
  return "blocked";
}

function webIngressReceiverClusterSummary(nodes: ClusterNode[], heartbeatsByNode: Record<string, NodeHeartbeat[]>) {
  const counts = { ready: 0, degraded: 0, blocked: 0, missing: 0 };
  for (const node of nodes) {
    const status = webIngressReceiverStatus(heartbeatsByNode[node.id]?.[0]);
    if (status === "ready") {
      counts.ready += 1;
    } else if (status === "blocked") {
      counts.blocked += 1;
    } else if (status === "degraded") {
      counts.degraded += 1;
    } else {
      counts.missing += 1;
    }
  }
  return {
    ...counts,
    label: `${counts.ready}/${nodes.length} ready, ${counts.degraded} degraded, ${counts.blocked} blocked`,
  };
}

function expectedWebIngressRuntimeClasses(roles: RoleAssignment[]) {
  void roles;
  return [];
}

function isMeshLinkStale(link: MeshLink, nodesById?: Map<string, ClusterNode>) {
  if (link.link_status === "stale" || link.metadata?.derived_link_stale === true) {
    return true;
  }
  const observedAt = new Date(link.observed_at).getTime();
  if (!Number.isFinite(observedAt) || Date.now() - observedAt > 15 * 60 * 1000) {
    return true;
  }
  if (!nodesById) {
    return false;
  }
  const source = nodesById.get(link.source_node_id);
  const target = nodesById.get(link.target_node_id);
  return source?.health_status !== "healthy" || target?.health_status !== "healthy";
}

function topologyPoint(x: number, index: number, count: number, top: number, bottom: number) {
  if (count <= 1) {
    return { x, y: Math.round((top + bottom) / 2) };
  }
  return { x, y: Math.round(top + ((bottom - top) * index) / (count - 1)) };
}

function topologyViewBox(nodeCount: number) {
  const columns = topologyColumnCount(nodeCount);
  const rows = Math.max(Math.ceil(nodeCount / columns), 1);
  return {
    width: 1280,
    height: Math.max(720, 220 + rows * 148),
  };
}

function topologyNodeRadius(nodeCount: number) {
  if (nodeCount > 48) {
    return 22;
  }
  if (nodeCount > 24) {
    return 26;
  }
  if (nodeCount > 12) {
    return 32;
  }
  if (nodeCount > 6) {
    return 40;
  }
  return 46;
}

function topologyNodeLabelSize(nodeCount: number) {
  if (nodeCount > 48) {
    return { name: 11, meta: 8, nameOffset: 5, metaOffset: 10, memoryOffset: 0, maxChars: 9 };
  }
  if (nodeCount > 24) {
    return { name: 13, meta: 9, nameOffset: 6, metaOffset: 12, memoryOffset: 0, maxChars: 11 };
  }
  if (nodeCount > 12) {
    return { name: 15, meta: 10, nameOffset: 7, metaOffset: 14, memoryOffset: 0, maxChars: 13 };
  }
  if (nodeCount > 6) {
    return { name: 18, meta: 12, nameOffset: 8, metaOffset: 15, memoryOffset: 0, maxChars: 15 };
  }
  return { name: 20, meta: 13, nameOffset: 9, metaOffset: 16, memoryOffset: 0, maxChars: 18 };
}

function topologyNodePositions(nodes: ClusterNode[], height: number, radius: number) {
  const columns = topologyColumnCount(nodes.length);
  const rows = Math.max(1, Math.ceil(nodes.length / columns));
  const left = radius + 98;
  const right = 1280 - radius - 98;
  const xStep = columns === 1 ? 0 : (right - left) / (columns - 1);
  const top = radius + 88;
  const bottom = height - radius - 88;
  const yStep = rows === 1 ? 0 : (bottom - top) / (rows - 1);
  return new Map(
    nodes.map((node, index) => {
      const column = index % columns;
      const row = Math.floor(index / columns);
      return [
        node.id,
        {
          x: Math.round(columns === 1 ? 560 : left + xStep * column),
          y: Math.round(rows === 1 ? (top + bottom) / 2 : top + yStep * row),
        },
      ] as const;
    }),
  );
}

function topologyColumnCount(nodeCount: number) {
  if (nodeCount > 48) {
    return 8;
  }
  if (nodeCount > 24) {
    return 6;
  }
  if (nodeCount > 12) {
    return 5;
  }
  if (nodeCount > 6) {
    return 4;
  }
  if (nodeCount > 3) {
    return 3;
  }
  return Math.max(1, nodeCount);
}

function topologyEdgePoints(source: { x: number; y: number }, target: { x: number; y: number }, offset: number) {
  const dx = target.x - source.x;
  const dy = target.y - source.y;
  const distance = Math.max(Math.sqrt(dx * dx + dy * dy), 1);
  const ox = (dx / distance) * offset;
  const oy = (dy / distance) * offset;
  return {
    x1: source.x + ox,
    y1: source.y + oy,
    x2: target.x - ox,
    y2: target.y - oy,
  };
}

function topologyDirectedEdgePoints(source: { x: number; y: number }, target: { x: number; y: number }, offset: number, laneOffset: number, laneSign: number) {
  const edge = topologyEdgePoints(source, target, offset);
  if (laneOffset === 0) {
    return edge;
  }
  const dx = target.x - source.x;
  const dy = target.y - source.y;
  const distance = Math.max(Math.sqrt(dx * dx + dy * dy), 1);
  const px = (-dy / distance) * laneOffset * laneSign;
  const py = (dx / distance) * laneOffset * laneSign;
  return {
    x1: edge.x1 + px,
    y1: edge.y1 + py,
    x2: edge.x2 + px,
    y2: edge.y2 + py,
  };
}

function topologyStableLaneSign(sourceNodeID: string, targetNodeID: string, kind: TopologyRouteKind) {
  const seed = `${sourceNodeID}:${targetNodeID}:${kind}`;
  let hash = 0;
  for (let index = 0; index < seed.length; index++) {
    hash = (hash * 31 + seed.charCodeAt(index)) | 0;
  }
  return hash % 2 === 0 ? 1 : -1;
}

function topologyRoutedEdgePath({
  source,
  target,
  sourceNodeID,
  targetNodeID,
  positions,
  nodeRadius,
  endpointOffset,
  laneOffset,
  laneSign,
  routeKind,
}: {
  source: { x: number; y: number };
  target: { x: number; y: number };
  sourceNodeID: string;
  targetNodeID: string;
  positions: Map<string, { x: number; y: number }>;
  nodeRadius: number;
  endpointOffset: number;
  laneOffset: number;
  laneSign: number;
  routeKind: TopologyRouteKind;
}) {
  const edge = topologyDirectedEdgePoints(source, target, endpointOffset, laneOffset, laneSign);
  const dx = edge.x2 - edge.x1;
  const dy = edge.y2 - edge.y1;
  const distance = Math.max(Math.sqrt(dx * dx + dy * dy), 1);
  const px = -dy / distance;
  const py = dx / distance;
  let obstacleCount = 0;
  let nearestObstacleDistance = Number.POSITIVE_INFINITY;
  for (const [nodeID, point] of positions) {
    if (nodeID === sourceNodeID || nodeID === targetNodeID) {
      continue;
    }
    const projection = ((point.x - edge.x1) * dx + (point.y - edge.y1) * dy) / (distance * distance);
    if (projection <= 0.06 || projection >= 0.94) {
      continue;
    }
    const closestX = edge.x1 + projection * dx;
    const closestY = edge.y1 + projection * dy;
    const nodeDistance = Math.sqrt((point.x - closestX) ** 2 + (point.y - closestY) ** 2);
    if (nodeDistance < nodeRadius + 34) {
      obstacleCount += 1;
      nearestObstacleDistance = Math.min(nearestObstacleDistance, nodeDistance);
    }
  }
  const routeOffset = routeKind === "relay" ? 28 : routeKind === "route" ? 44 : 0;
  const obstacleOffset = obstacleCount > 0 ? Math.max(72, (nodeRadius + 34 - nearestObstacleDistance) + obstacleCount * 28) : 0;
  const bend = (laneOffset + routeOffset + obstacleOffset) * laneSign;
  if (Math.abs(bend) < 1) {
    return {
      d: `M ${edge.x1} ${edge.y1} L ${edge.x2} ${edge.y2}`,
      labelX: (edge.x1 + edge.x2) / 2,
      labelY: (edge.y1 + edge.y2) / 2,
    };
  }
  const midX = (edge.x1 + edge.x2) / 2;
  const midY = (edge.y1 + edge.y2) / 2;
  const controlX = midX + px * bend;
  const controlY = midY + py * bend;
  return {
    d: `M ${edge.x1} ${edge.y1} Q ${controlX} ${controlY} ${edge.x2} ${edge.y2}`,
    labelX: (edge.x1 + 2 * controlX + edge.x2) / 4,
    labelY: (edge.y1 + 2 * controlY + edge.y2) / 4,
  };
}

function configuredTopologyLinks(nodes: ClusterNode[], configsByNode: Record<string, NodeSyntheticMeshConfig>) {
  const knownNodes = new Set(nodes.map((node) => node.id));
  const byPair = new Map<string, { id: string; source_node_id: string; target_node_id: string }>();
  for (const [nodeID, config] of Object.entries(configsByNode)) {
    for (const route of config.routes || []) {
      const hops = route.hops || [];
      for (let index = 0; index < hops.length - 1; index++) {
        const source = hops[index];
        const target = hops[index + 1];
        if (!knownNodes.has(source) || !knownNodes.has(target) || source === target) {
          continue;
        }
        byPair.set(`${source}->${target}`, {
          id: `configured-${nodeID}-${route.route_id}-${index}`,
          source_node_id: source,
          target_node_id: target,
        });
      }
    }
  }
  return [...byPair.values()];
}

function NodeGroupTree({ groups, nodes, labels }: { groups: ClusterNodeGroup[]; nodes: ClusterNode[]; labels: Record<string, string> }) {
  const rootGroups = groups
    .filter((group) => !group.parent_group_id)
    .sort((left, right) => left.sort_order - right.sort_order || left.name.localeCompare(right.name));
  const ungroupedNodes = nodes.filter((node) => !node.node_group_id);

  if (groups.length === 0 && nodes.length === 0) {
    return <EmptyState title="Нет узлов" text="Одобренные node-agent появятся здесь." />;
  }

  return (
    <div className="treeList">
      {rootGroups.map((group) => (
        <NodeGroupBranch key={group.id} group={group} groups={groups} nodes={nodes} depth={0} />
      ))}
      {ungroupedNodes.length > 0 && (
        <section className="treeBranch">
          <h4>{labels.ungroupedNodes}</h4>
          <div className="treeNodeList">
            {ungroupedNodes.map((node) => (
              <span className="pill" key={node.id}>
                {node.name}
              </span>
            ))}
          </div>
        </section>
      )}
    </div>
  );
}

function NodeGroupBranch({ group, groups, nodes, depth }: { group: ClusterNodeGroup; groups: ClusterNodeGroup[]; nodes: ClusterNode[]; depth: number }) {
  const childGroups = groups
    .filter((item) => item.parent_group_id === group.id)
    .sort((left, right) => left.sort_order - right.sort_order || left.name.localeCompare(right.name));
  const groupedNodes = nodes.filter((node) => node.node_group_id === group.id);

  return (
    <section className="treeBranch" style={{ marginLeft: `${depth * 18}px` }}>
      <h4>
        {group.name}
        <span className="pill">{groupedNodes.length}</span>
      </h4>
      {group.description && <p className="muted">{group.description}</p>}
      <div className="treeNodeList">
        {groupedNodes.map((node) => (
          <span className="pill good" key={node.id}>
            {node.name}
          </span>
        ))}
      </div>
      {childGroups.map((child) => (
        <NodeGroupBranch key={child.id} group={child} groups={groups} nodes={nodes} depth={depth + 1} />
      ))}
    </section>
  );
}

function FormGrid({ children }: { children: ReactNode }) {
  return <div className="formGrid">{children}</div>;
}

function DataTable({ columns, rows }: { columns: string[]; rows: ReactNode[][] }) {
  if (rows.length === 0) {
    return <EmptyState title="Нет данных" text="В текущей области пока нечего показать." />;
  }
  return (
    <div className="tableWrap">
      <table>
        <thead>
          <tr>
            {columns.map((column) => (
              <th key={column}>{column}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.map((row, index) => (
            <tr key={index}>
              {row.map((cell, cellIndex) => (
                <td key={`${index}-${cellIndex}`}>{cell}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function parseJSONObject(raw: string, label: string): Record<string, unknown> {
  const parsed = JSON.parse(raw || "{}") as unknown;
  if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") {
    throw new Error(`${label}: требуется JSON object.`);
  }
  return parsed as Record<string, unknown>;
}

function parseJSONArray(raw: string, label: string): unknown[] {
  const parsed = JSON.parse(raw || "[]") as unknown;
  if (!Array.isArray(parsed)) {
    throw new Error(`${label}: требуется JSON array.`);
  }
  return parsed;
}

function summarizeRoles(roles: RoleAssignment[]) {
  const activeRoles = activeFabricNodeRoleAssignments(roles);
  if (activeRoles.length === 0) {
    return "функции узла фермы не назначены";
  }
  return activeRoles.map((role) => `${roleDisplayLabel(role.role)}${role.organization_id ? ` @ ${shortId(role.organization_id)}` : ""}`).join(", ");
}

function activeRoleAssignments(roles: RoleAssignment[]) {
  return roles.filter((role) => role.status === "active");
}

function activeFabricNodeRoleAssignments(roles: RoleAssignment[]) {
  return activeRoleAssignments(roles).filter((role) => isFabricNodeRole(role.role));
}

function isFabricNodeRole(role: string) {
  return fabricNodeRoleOptions.includes(role);
}

function nodeFabricRoleSummary(roles: RoleAssignment[]) {
  if (roles.length === 0) {
    return "только базовый агент";
  }
  return roles.map((role) => roleDisplayLabel(role.role).replace(/\s*\([^)]*\)$/, "")).join(", ");
}

function roleDisplayLabel(role: string) {
  const name = roleDisplayNames[role];
  return name ? `${name} (${role})` : role;
}

function summarizeWorkloads(workloads: WorkloadStatus[]) {
  if (workloads.length === 0) {
    return "нет сервисов";
  }
  return workloads.map((workload) => `${workload.service_type}:${workload.reported_state}`).join(", ");
}

function nodeUpdateSummary(node: ClusterNode, plan: NodeUpdatePlan | undefined, releases: ReleaseVersion[]) {
  const latest =
    releases.find((release) => release.product === "rap-node-agent" && release.channel === "stable" && release.status === "active") ||
    releases.find((release) => release.product === "rap-node-agent" && release.status === "active");
  const current = node.reported_version || "";
  const target = plan?.target_version || latest?.version || "";
  if (node.version_state && node.version_state !== "unknown") {
    return { status: node.version_state, targetLabel: target ? `target ${target}` : "policy target unknown" };
  }
  if (!current) {
    return { status: "unknown", targetLabel: target ? `target ${target}` : "target unknown" };
  }
  if (plan?.action === "update") {
    return { status: "outdated", targetLabel: `target ${plan.target_version || target}` };
  }
  if (target && current !== target) {
    return { status: "outdated", targetLabel: `latest ${target}` };
  }
  if (target && current === target) {
    return { status: "current", targetLabel: `latest ${target}` };
  }
  return { status: plan?.reason === "no_update_policy" ? "no_policy" : "unknown", targetLabel: plan?.reason || "release policy unknown" };
}

function latestUpdateStatus(statuses: NodeUpdateStatus[], product: string) {
  return statuses.find((status) => status.product === product);
}

function updateStatusSummary(status: NodeUpdateStatus | undefined, plan: NodeUpdatePlan | undefined) {
  if (status) {
    return `${status.product}: ${status.phase}/${status.status}`;
  }
  if (plan) {
    return `${plan.action}: ${plan.reason}`;
  }
  return "нет отчета";
}

function updateStatusLine(status: NodeUpdateStatus | undefined) {
  if (!status) {
    return "нет отчета";
  }
  const target = status.target_version ? ` -> ${status.target_version}` : "";
  const rescue = updateStatusRescueLine(status);
  const error = status.error_message ? `, ошибка: ${status.error_message}` : "";
  return `${status.current_version || "н/д"}${target}, ${status.phase}/${status.status}, ${formatDate(status.observed_at)}${rescue}${error}`;
}

function updateStatusRescueLine(status: NodeUpdateStatus) {
  const payload = status.payload ?? {};
  const failureClass = typeof payload.failure_class === "string" ? payload.failure_class : "";
  const action = typeof payload.operator_action === "string" ? payload.operator_action : "";
  if (failureClass === "fabric_executor_upgrade_required") {
    return ", rescue: executor до fabric-artifact";
  }
  if (failureClass === "host_agent_binary_permission_denied") {
    return ", rescue: права host-agent";
  }
  if (action) {
    return `, rescue: ${action}`;
  }
  return "";
}

function vpnPacketStatLine(stats: VPNPacketStats[keyof VPNPacketStats] | undefined) {
  if (!stats) {
    return "нет данных";
  }
  return `push ${stats.pushed || 0} / pop ${stats.popped || 0} / q ${stats.queue_depth || 0} / drop ${stats.dropped || 0}`;
}

function updateStatusTone(status: NodeUpdateStatus | undefined) {
  if (!status) {
    return "warn";
  }
  if (status.payload?.rescue_required === true) {
    return "bad";
  }
  const value = `${status.phase}:${status.status}`.toLowerCase();
  if (value.includes("error") || value.includes("failed") || value.includes("rollback")) {
    return "bad";
  }
  if (value.includes("success") || value.includes("updated") || value.includes("noop") || value.includes("already_current")) {
    return "good";
  }
  if (value.includes("download") || value.includes("replace") || value.includes("plan") || value.includes("apply")) {
    return "warn";
  }
  return "";
}

function serviceChannelFeedbackTone(status: string) {
  const value = status.toLowerCase();
  if (value === "healthy") {
    return "good";
  }
  if (value === "fenced") {
    return "bad";
  }
  if (value === "degraded") {
    return "warn";
  }
  if (value === "operator_retry_cooldown") {
    return "warn";
  }
  return "";
}

function serviceChannelRecoveryTone(status: string) {
  const value = status.toLowerCase();
  if (value === "healthy") {
    return "good";
  }
  if (value === "recovered" || value === "cooldown" || value === "degraded") {
    return "warn";
  }
  if (value === "fenced" || value === "demoted") {
    return "bad";
  }
  return "";
}

function routeIntentLifecycle(item: MeshRouteIntent) {
  if (item.status === "disabled" || item.lifecycle_status === "disabled") {
    return "disabled";
  }
  if (item.is_expired || item.lifecycle_status === "expired") {
    return "expired";
  }
  const expiresAt = Date.parse(item.policy_expires_at || "");
  if (Number.isFinite(expiresAt) && expiresAt <= Date.now()) {
    return "expired";
  }
  return item.lifecycle_status || item.status || "active";
}

function routeIntentTone(item: MeshRouteIntent) {
  const lifecycle = routeIntentLifecycle(item);
  if (lifecycle === "active") {
    return "good";
  }
  if (lifecycle === "expired") {
    return "warn";
  }
  if (lifecycle === "disabled") {
    return "";
  }
  return "warn";
}

function routeIntentNodeSelector(selector: Record<string, unknown>) {
  const nodeID = typeof selector.node_id === "string" ? selector.node_id : "";
  if (nodeID) {
    return shortId(nodeID);
  }
  const nodeIDs = Array.isArray(selector.node_ids) ? selector.node_ids.filter((item): item is string => typeof item === "string") : [];
  if (nodeIDs.length > 0) {
    return nodeIDs.map(shortId).join(", ");
  }
  return "selector";
}

function nodeUpdaterSummary(statuses: NodeUpdateStatus[]) {
  const nodeAgent = latestUpdateStatus(statuses, "rap-node-agent");
  const hostAgent = latestUpdateStatus(statuses, "rap-host-agent");
  const reason = nodeUpdateStatusReason(nodeAgent) || nodeUpdateStatusReason(hostAgent);
  if (!nodeAgent && !hostAgent) {
    return { label: "updater: нет отчета", detail: "repair/update task не отчитался", tone: "bad", reason: "" };
  }
  const stale = [nodeAgent, hostAgent].some((status) => status && isUpdateStatusStale(status));
  const missingHost = !hostAgent;
  const stagedHost = hostAgent?.phase === "apply" && hostAgent?.status === "staged";
  const bad = [nodeAgent, hostAgent].some((status) => status && updateStatusTone(status) === "bad");
  const nodeLabel = nodeAgent ? `${nodeAgent.current_version || "?"}->${nodeAgent.target_version || "?"}` : "node ?";
  const hostLabel = hostAgent ? `${hostAgent.current_version || "?"}->${hostAgent.target_version || "?"}` : "host ?";
  const observed = formatDate((hostAgent || nodeAgent)?.observed_at);
  if (bad) {
    return { label: "updater: ошибка", detail: `${nodeLabel}; ${hostLabel}; ${observed}`, tone: "bad", reason };
  }
  if (missingHost) {
    return { label: "repair updater", detail: `host-agent не отчитался; ${nodeLabel}; ${observed}`, tone: "warn", reason };
  }
  if (stagedHost) {
    return { label: "host-agent staged", detail: `${hostLabel}; нужен следующий запуск updater`, tone: "warn", reason };
  }
  if (stale) {
    return { label: "updater: stale", detail: `${nodeLabel}; ${hostLabel}; ${observed}`, tone: "warn", reason };
  }
  return { label: "updater: ok", detail: `${nodeLabel}; ${hostLabel}; ${observed}`, tone: "good", reason };
}

function nodeUpdateStatusReason(status: NodeUpdateStatus | undefined) {
  if (!status?.payload) {
    return "";
  }
  const reason = status.payload.reason;
  if (typeof reason === "string" && reason) {
    return reason;
  }
  const failureClass = status.payload.failure_class;
  return typeof failureClass === "string" ? failureClass : "";
}

function isUpdateStatusStale(status: NodeUpdateStatus) {
  const observed = new Date(status.observed_at).getTime();
  return !Number.isFinite(observed) || Date.now() - observed > 15 * 60 * 1000;
}

function joinTokenName(token: NodeJoinToken) {
  const nodeName = typeof token.scope?.node_name === "string" ? token.scope.node_name : "";
  const purpose = typeof token.scope?.purpose === "string" ? token.scope.purpose : "";
  return nodeName || purpose || shortId(token.id);
}

function latestLinkObservations(links: MeshLink[]) {
  const byPair = new Map<string, MeshLink>();
  for (const link of links) {
    const key = `${link.source_node_id}->${link.target_node_id}:${meshLinkObservationKey(link)}`;
    const existing = byPair.get(key);
    if (!existing || new Date(link.observed_at).getTime() > new Date(existing.observed_at).getTime()) {
      byPair.set(key, link);
    }
  }
  return [...byPair.values()];
}

function meshLinkObservationKey(link: MeshLink) {
  const observationType = meshLinkMetadataString(link, "observation_type") || "default";
  if (observationType === "synthetic_route_health") {
    return `${observationType}:${meshLinkMetadataString(link, "route_id") || link.id}`;
  }
  if (observationType === "peer_connection_manager") {
    return `${observationType}:${meshLinkMetadataString(link, "transport_mode")}:${meshLinkMetadataString(link, "relay_node_id")}`;
  }
  return observationType;
}

function meshLinkObservationLabel(link: MeshLink) {
  const observationType = meshLinkMetadataString(link, "observation_type");
  if (observationType === "synthetic_route_health") {
    const drift = link.metadata?.route_path_drift_detected === true ? "drift" : "ok";
    const applied = link.metadata?.route_path_decision_applied === true ? "decision" : "route";
    return `route-health ${applied} ${drift}`;
  }
  if (observationType === "peer_connection_manager") {
    const mode = meshLinkMetadataString(link, "transport_mode") || "manager";
    const state = meshLinkMetadataString(link, "connection_state");
    return state ? `${mode} ${state}` : mode;
  }
  return observationType || "link";
}

function meshLinkRoutePathSummary(link: MeshLink, nodes: ClusterNode[]) {
  const routeID = meshLinkMetadataString(link, "route_id");
  const relayID = meshLinkMetadataString(link, "route_path_decision_selected_relay_id") || meshLinkMetadataString(link, "relay_node_id");
  const hops = meshLinkMetadataStringArray(link, "expected_effective_hops");
  const observed = meshLinkMetadataStringArray(link, "observed_ack_path");
  const path = hops.length > 0 ? hops : observed;
  const parts: string[] = [];
  if (routeID) {
    parts.push(shortId(routeID));
  }
  if (relayID) {
    parts.push(`via ${shortId(relayID)}`);
  }
  if (path.length > 0) {
    parts.push(path.map((id) => trimNodeName(nodeName(nodes, id))).join(" > "));
  }
  return parts.length > 0 ? parts.join(" / ") : "н/д";
}

function meshLinkTopologyLabel(link: MeshLink, nodes: ClusterNode[], status: TopologyLinkStatus = link.link_status === "reachable" ? "reachable" : "unknown") {
  if (status === "stale") {
    return "stale";
  }
  if (status === "one_way") {
    return "one-way";
  }
  const observationType = meshLinkMetadataString(link, "observation_type");
  if (observationType === "synthetic_route_health") {
    const relayID = meshLinkMetadataString(link, "route_path_decision_selected_relay_id");
    if (relayID) {
      return `relay ${trimNodeName(nodeName(nodes, relayID), 10)}`;
    }
    return link.metadata?.route_path_drift_detected === true ? "drift" : "route";
  }
  if (observationType === "peer_connection_manager") {
    const mode = meshLinkMetadataString(link, "transport_mode");
    const relayID = meshLinkMetadataString(link, "relay_node_id");
    if (mode === "relay_quic" || relayID) {
      return relayID ? `relay ${trimNodeName(nodeName(nodes, relayID), 10)}` : "relay";
    }
    if (mode === "direct_quic" || mode === "private_lan" || meshLinkMetadataString(link, "direct_candidate") === "true") {
      return link.latency_ms == null ? "direct" : `${link.latency_ms}мс`;
    }
    if (mode) {
      return statusLabel(mode);
    }
  }
  return link.latency_ms == null ? "связь" : `${link.latency_ms}мс`;
}

function meshLinkMetadataString(link: MeshLink, key: string) {
  const value = link.metadata?.[key];
  return typeof value === "string" ? value : "";
}

function meshLinkMetadataStringArray(link: MeshLink, key: string) {
  const value = link.metadata?.[key];
  return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
}

function objectField(value: unknown): Record<string, unknown> | undefined {
  return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
}

function arrayObjects(value: unknown): Record<string, unknown>[] {
  return Array.isArray(value) ? value.map((item) => objectField(item)).filter((item): item is Record<string, unknown> => Boolean(item)) : [];
}

function stringField(source: Record<string, unknown> | undefined, key: string, fallback = "") {
  const value = source?.[key];
  if (typeof value === "string") {
    return value;
  }
  if (typeof value === "number" || typeof value === "boolean") {
    return String(value);
  }
  return fallback;
}

function firstStringField(source: Record<string, unknown> | undefined, keys: string[]) {
  for (const key of keys) {
    const value = stringField(source, key, "");
    if (value) {
      return value;
    }
  }
  return "";
}

function nodeSignalFreshness(node: ClusterNode, heartbeat?: NodeHeartbeat): NodeSignalFreshness {
  const at = heartbeat?.observed_at || node.last_seen_at || null;
  if (!at) {
    return { state: "no_signal", at: null, ageSeconds: null };
  }
  const timestamp = Date.parse(at);
  if (Number.isNaN(timestamp)) {
    return { state: "no_signal", at, ageSeconds: null };
  }
  const ageSeconds = Math.max(0, Math.round((Date.now() - timestamp) / 1000));
  if (ageSeconds <= 90) {
    return { state: "fresh", at, ageSeconds };
  }
  if (ageSeconds <= 600) {
    return { state: "lagging", at, ageSeconds };
  }
  return { state: "stale", at, ageSeconds };
}

function nodeFreshnessTone(freshness: NodeSignalFreshness) {
  if (freshness.state === "fresh") {
    return "good";
  }
  if (freshness.state === "lagging") {
    return "warn";
  }
  return "bad";
}

function nodeFreshnessLabel(freshness: NodeSignalFreshness) {
  if (freshness.state === "fresh") {
    return `связь ${formatDateAgo(freshness.at)}`;
  }
  if (freshness.state === "lagging") {
    return `задержка ${formatDateAgo(freshness.at)}`;
  }
  if (freshness.state === "stale") {
    return `нет свежей связи ${formatDateAgo(freshness.at)}`;
  }
  return "нет heartbeat";
}

function nodeRuntimeConnectivity(node: ClusterNode, heartbeats: NodeHeartbeat[], meshLinks: MeshLink[]): NodeRuntimeConnectivity {
  const heartbeat = heartbeats[0];
  const metadata = heartbeat?.metadata || {};
  const listenerReport = objectField(metadata.mesh_listener_report);
  const endpointReport = objectField(metadata.mesh_endpoint_report);
  const outboundReport = objectField(metadata.mesh_outbound_session_report);
  const managerReport = objectField(metadata.mesh_peer_connection_manager_report);
  const recoveryReport = objectField(metadata.mesh_peer_recovery_report);
  const reportedCandidates = arrayObjects(endpointReport?.endpoint_candidates);
  const firstCandidate = reportedCandidates[0];
  const address =
    firstStringField(endpointReport, ["peer_endpoint", "advertised_endpoint", "endpoint"]) ||
    stringField(firstCandidate, "address", "") ||
    stringField(listenerReport, "effective_listen_addr", "") ||
    "адрес не прислан";
  const freshness = nodeSignalFreshness(node, heartbeat);
  if (!heartbeat && !node.last_seen_at) {
    return {
      agentLabel: "agent: no heartbeat",
      agentTone: "bad",
      clientLabel: "client: unknown",
      clientTone: "warn",
      outboundLabel: "outbound: no heartbeat",
      outboundTone: "bad",
      inboundLabel: "inbound: unknown",
      inboundTone: "warn",
      address,
      detail: "Узел создан/одобрен, но node-agent еще ни разу не прислал heartbeat.",
    };
  }
  if (freshness.state === "stale" || freshness.state === "no_signal") {
    return {
      agentLabel: freshness.state === "stale" ? `agent: stale ${formatDateAgo(freshness.at)}` : "agent: no heartbeat",
      agentTone: "bad",
      clientLabel: "peers: no fresh report",
      clientTone: "warn",
      outboundLabel: "outbound: no fresh report",
      outboundTone: "warn",
      inboundLabel: "inbound: no fresh report",
      inboundTone: "warn",
      address,
      detail: "Последний heartbeat устарел; старые QUIC/link данные не считаются текущей работоспособностью узла.",
    };
  }
  if (freshness.state === "lagging") {
    return {
      agentLabel: `agent: lag ${formatDateAgo(freshness.at)}`,
      agentTone: "warn",
      clientLabel: "peers: pending fresh report",
      clientTone: "warn",
      outboundLabel: "outbound: pending",
      outboundTone: "warn",
      inboundLabel: "inbound: pending",
      inboundTone: "warn",
      address,
      detail: "Heartbeat задерживается; дождитесь свежего отчета перед оценкой маршрутов.",
    };
  }

  const readyPeers =
    numberField(managerReport, "peer_connection_ready") ||
    numberField(recoveryReport, "peer_connection_ready") ||
    latestLinkObservations(meshLinks).filter((link) => (link.source_node_id === node.id || link.target_node_id === node.id) && link.link_status === "reachable").length;
  const totalPeers =
    numberField(managerReport, "peer_connection_total") ||
    numberField(recoveryReport, "peer_connection_total") ||
    latestLinkObservations(meshLinks).filter((link) => link.source_node_id === node.id || link.target_node_id === node.id).length;
  const managerFailed = numberField(managerReport, "failed");
  const listenerStatus = stringField(listenerReport, "status", "");
  const portConflict = listenerReport?.port_conflict === true;
  const oneWay =
    listenerReport?.one_way_connectivity === true ||
    stringField(endpointReport, "connectivity_mode", "") === "outbound_only" ||
    numberField(managerReport, "peer_connection_relay_ready") > 0;
  let inboundLabel = "inbound: no report";
  let inboundTone = "warn";
  if (listenerStatus === "listening" || listenerStatus === "auto_rebound") {
    inboundLabel = listenerStatus === "auto_rebound" ? "inbound: auto port" : "inbound: listening";
    inboundTone = "good";
  } else if (listenerStatus === "listen_failed") {
    inboundLabel = portConflict ? "inbound: port busy" : "inbound: failed";
    inboundTone = "bad";
  } else if (listenerStatus === "disabled") {
    inboundLabel = "inbound: disabled";
    inboundTone = oneWay ? "warn" : "bad";
  } else if (endpointReport) {
    inboundLabel = "inbound: advertised";
    inboundTone = "good";
  }

  let clientLabel = "client: no peers";
  let clientTone = "warn";
  if (readyPeers > 0) {
    clientLabel = `client: ready ${readyPeers}/${Math.max(totalPeers, readyPeers)}`;
    clientTone = "good";
  } else if (managerFailed > 0 || totalPeers > 0) {
    clientLabel = `client: backoff ${readyPeers}/${Math.max(totalPeers, managerFailed)}`;
    clientTone = "bad";
  }

  const outboundStatus = stringField(outboundReport, "status", "");
  const usableForInboundControl = outboundReport?.usable_for_inbound_control === true;
  const relayReady = numberField(outboundReport, "peer_connection_relay_ready");
  const rendezvousLeases = numberField(outboundReport, "rendezvous_lease_count");
  let outboundLabel = "outbound: no report";
  let outboundTone = "warn";
  if (outboundStatus === "ready") {
    outboundLabel = usableForInboundControl ? "outbound: ready reverse" : "outbound: ready";
    outboundTone = "good";
  } else if (outboundStatus === "backoff" || outboundStatus === "failed") {
    outboundLabel = `outbound: ${outboundStatus}`;
    outboundTone = "bad";
  } else if (oneWay || relayReady > 0 || rendezvousLeases > 0) {
    outboundLabel = "outbound: inferred";
    outboundTone = "warn";
  }

  const agentTone = node.health_status === "healthy" ? "good" : node.health_status === "unknown" ? "warn" : "bad";
  return {
    agentLabel: heartbeat ? "agent: heartbeat" : "agent: stale",
    agentTone,
    clientLabel: oneWay && readyPeers > 0 ? `${clientLabel} one-way` : clientLabel,
    clientTone,
    outboundLabel,
    outboundTone,
    inboundLabel,
    inboundTone,
    address,
    detail: stringField(listenerReport, "failure_error", stringField(listenerReport, "failure_reason", "")),
  };
}

function numberField(source: Record<string, unknown> | undefined, key: string, fallback = 0) {
  const value = source?.[key];
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
}

function staleNodeRecoveryRecommendation(node: StaleNodeRiskReport["nodes"][number]) {
  if (node.standard_updater_line) {
    return "Heartbeat жив, но узел всё ещё сидит на standard updater line: держать overlap, не ждать самопочинки от старого wake path и переводить узел на wake-capable updater/runtime line.";
  }
  if (node.updater_runtime_missing) {
    return "Heartbeat жив, но updater/runtime telemetry отсутствует: держать overlap, считать локальный updater loop отсутствующим или неработающим и добивать recovery-path, который не зависит от локального wake цикла.";
  }
  if (node.staged_self_update_pending) {
    return "Узел застрял на staged self-update host-agent: держать fabric recovery/control путь активным и добивать следующий updater cycle, который должен применить .next binary.";
  }
  if (node.standard_control_dependency) {
    return `Узел всё ещё зависит от старого control bridge (${node.standard_control_url || "standard"}): восстановить registry runtime и перевести узел на QUIC fabric control path.`;
  }
  if (node.independent_ingress_alert) {
    return `Узел держит недостаточно независимых ingress-путей: сейчас ${node.independent_ingress_count || 0}/${node.required_independent_ingress_count || 0}. Нужны дополнительные публичные QUIC advertise endpoints или альтернативные внешние edge-пути.`;
  }
  if (node.area_diversity_alert) {
    return `Узел держит прямые QUIC-связи без достаточного разброса по area: сейчас ${node.external_area_ready_count || 0}/${node.required_external_area_count || 0} внешних area. Нужны дополнительные direct peers через другие области и ingress/NAT пути.`;
  }
  if (node.direct_peer_alert) {
    return `У узла только ${node.direct_peer_ready_count || 0} из ${node.direct_peer_target_count || 3} готовых прямых QUIC-связей: добавить/починить advertise endpoints, NAT-forwarding или соседние relay-capable peers до минимума в 3 ready direct peers.`;
  }
  const missingArtifacts = node.products.filter((product) => !product.compatible_artifact_found).map((product) => product.product);
  if (missingArtifacts.length > 0) {
    return `Добавить recovery artifacts для ${missingArtifacts.join(", ")} и повторить fabric rollout.`;
  }
  const staleRecoveryContracts = node.risks
    .filter((risk) => risk.startsWith("stale_node_standard_recovery_contract_"))
    .map((risk) => risk.replace("stale_node_standard_recovery_contract_", ""));
  if (staleRecoveryContracts.length > 0) {
    if (node.recovery_bridge_replay_ready) {
      return `Узел застрял на устаревшем recovery-контракте (${staleRecoveryContracts.join(", ")}): recovery replay готов, нужен следующий heartbeat/update-цикл через fabric.`;
    }
    return `Узел застрял на устаревшем recovery-контракте (${staleRecoveryContracts.join(", ")}): восстановить fabric heartbeat и update-status перед rollout.`;
  }
  const unknownProfiles = node.risks
    .filter((risk) => risk.startsWith("stale_node_unknown_profile_"))
    .map((risk) => risk.replace("stale_node_unknown_profile_", ""));
  if (unknownProfiles.length > 0) {
    return `Неизвестен update profile (${unknownProfiles.join(", ")}): нужен свежий heartbeat/update-status и fabric update mapping для этой линии узла.`;
  }
  const unknownVersions = node.risks
    .filter((risk) => risk.startsWith("stale_node_unknown_") && risk.endsWith("_version"))
    .map((risk) => risk.replace("stale_node_unknown_", "").replace("_version", ""));
  if (unknownVersions.length > 0) {
    return `Нет подтвержденной версии (${unknownVersions.join(", ")}): проверить signed release mapping и last known good.`;
  }
  const missingStatuses = node.risks
    .filter((risk) => risk.startsWith("stale_node_no_") && risk.endsWith("_update_status"))
    .map((risk) => risk.replace("stale_node_no_", "").replace("_update_status", ""));
  if (missingStatuses.length > 0) {
    return `Узел молчит и не прислал update-status (${missingStatuses.join(", ")}): восстановить fabric recovery channel.`;
  }
  if (node.risks.includes("stale_heartbeat")) {
    return "Узел stale, но recovery artifacts уже есть: ждать исходящий recovery heartbeat и проверить fabric registry gossip.";
  }
  return "Риск под контролем: можно наблюдать heartbeat и готовить controlled cleanup после отдельной проверки.";
}

function staleNodeRecoveryReadiness(node: StaleNodeRiskReport["nodes"][number]) {
  if (node.standard_updater_line) {
    return "standard updater line: heartbeat is alive, but the node still lacks wake-capable updater runtime";
  }
  if (node.updater_runtime_missing) {
    return "updater runtime missing: heartbeat is alive but updater/runtime telemetry is absent";
  }
  if (node.staged_self_update_pending) {
    return "staged self-update pending: host-agent replacement is staged and still waiting for the next updater cycle";
  }
  if (node.post_update_heartbeat_gap) {
    return "post-update heartbeat gap: updater reported success but the node did not return with a fresh heartbeat/version";
  }
  if (node.updater_subscription_alert && node.updater_wake_unsupported) {
    return "fresh heartbeat but updater is lagging and current node-agent cannot wake the local updater yet";
  }
  if (node.updater_subscription_alert) {
    return "updater subscription alert: heartbeat is fresh but update-status is lagging";
  }
  if (node.standard_control_dependency) {
    return `standard control dependency: ${node.standard_control_url || "active"}`;
  }
  if (node.independent_ingress_alert) {
    return `independent ingress alert: ${node.independent_ingress_count || 0}/${node.required_independent_ingress_count || 0} ready`;
  }
  if (node.area_diversity_alert) {
    return `area diversity alert: ${node.external_area_ready_count || 0}/${node.required_external_area_count || 0} external area(s)`;
  }
  if (node.direct_peer_alert) {
    return `direct peer alert: ${node.direct_peer_ready_count || 0}/${node.direct_peer_target_count || 3} ready`;
  }
  const missingArtifacts = node.products.filter((product) => !product.compatible_artifact_found).map((product) => product.product);
  if (missingArtifacts.length > 0) {
    return `artifact gap: ${missingArtifacts.join(", ")}`;
  }
  const staleRecoveryContracts = node.risks
    .filter((risk) => risk.startsWith("stale_node_standard_recovery_contract_"))
    .map((risk) => risk.replace("stale_node_standard_recovery_contract_", ""));
  if (staleRecoveryContracts.length > 0) {
    if (node.recovery_bridge_replay_ready) {
      return `recovery replay ready: ${staleRecoveryContracts.join(", ")}`;
    }
    return `fabric recovery required: ${staleRecoveryContracts.join(", ")}`;
  }
  const unknownProfiles = node.risks
    .filter((risk) => risk.startsWith("stale_node_unknown_profile_"))
    .map((risk) => risk.replace("stale_node_unknown_profile_", ""));
  if (unknownProfiles.length > 0) {
    return `profile unknown: ${unknownProfiles.join(", ")}`;
  }
  const missingStatuses = node.risks
    .filter((risk) => risk.startsWith("stale_node_no_") && risk.endsWith("_update_status"))
    .map((risk) => risk.replace("stale_node_no_", "").replace("_update_status", ""));
  if (missingStatuses.length > 0) {
    return `waiting update status: ${missingStatuses.join(", ")}`;
  }
  const unknownVersions = node.risks
    .filter((risk) => risk.startsWith("stale_node_unknown_") && risk.endsWith("_version"))
    .map((risk) => risk.replace("stale_node_unknown_", "").replace("_version", ""));
  if (unknownVersions.length > 0) {
    return `version unknown: ${unknownVersions.join(", ")}`;
  }
  if (node.heartbeat_stale) {
    return "artifacts ready, waiting recovery heartbeat";
  }
  return "recovery ready";
}

function auditEventMatchesNode(event: AuditEvent, nodeId: string) {
  if (!nodeId) {
    return true;
  }
  if (event.target_id === nodeId) {
    return true;
  }
  const payload = objectField(event.payload);
  const candidateKeys = [
    "node_id",
    "target_node_id",
    "reporter_node_id",
    "entry_node_id",
    "exit_node_id",
    "selected_node_id",
  ];
  return candidateKeys.some((key) => stringField(payload, key, "") === nodeId);
}

function fabricListenerEndpointCandidatesToText(config: Record<string, unknown>) {
  const candidates = arrayObjects(config.endpoint_candidates);
  if (candidates.length > 0) {
    return candidates
      .map((candidate) => {
        const address = stringField(candidate, "address", "");
        if (!address) {
          return "";
        }
        const parts = [address];
        for (const key of ["reachability", "connectivity_mode", "nat_type", "region", "priority"] as const) {
          const value = stringField(candidate, key, "");
          if (value) {
            parts.push(`${key.replace("_mode", "").replace("_type", "")}=${value}`);
          }
        }
        const metadata = objectField(candidate.metadata);
        for (const key of ["provider", "interface", "maps_to"] as const) {
          const value = stringField(metadata, key, "");
          if (value) {
            parts.push(`${key}=${value}`);
          }
        }
        return parts.join(" ");
      })
      .filter(Boolean)
      .join("\n");
  }
  const endpoints = Array.isArray(config.advertise_endpoints) ? config.advertise_endpoints : [];
  if (endpoints.length > 0) {
    return endpoints.map((endpoint) => String(endpoint || "").trim()).filter(Boolean).join("\n");
  }
  return stringField(config, "advertise_endpoint", "");
}

function parseFabricListenerEndpointCandidates(
  draft: {
    endpointCandidates: string;
    advertiseEndpoint: string;
    advertiseTransport: string;
    connectivity: string;
    nat: string;
    region: string;
  },
  nodeID: string,
) {
  const lines = draft.endpointCandidates
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter((line) => line && !line.startsWith("#"));
  if (lines.length === 0 && draft.advertiseEndpoint.trim()) {
    lines.push(draft.advertiseEndpoint.trim());
  }
  const seen = new Set<string>();
  return lines.flatMap((line, index) => {
    const tokens = line.split(/\s+/).filter(Boolean);
    const address = (tokens.shift() || "").replace(/\/$/, "");
    if (!address || seen.has(address)) {
      return [];
    }
    seen.add(address);
    const options: Record<string, string> = {};
    for (const token of tokens) {
      const splitAt = token.indexOf("=");
      if (splitAt > 0) {
        options[token.slice(0, splitAt).trim().toLowerCase()] = token.slice(splitAt + 1).trim();
      } else if (["public", "private", "relay", "outbound_only", "unknown"].includes(token)) {
        options.reachability = token;
      } else if (["direct", "private_lan", "relay_required"].includes(token)) {
        options.connectivity = token;
      } else if (["none", "full_cone", "restricted", "port_restricted", "symmetric", "blocked"].includes(token)) {
        options.nat = token;
      }
    }
    const connectivity = options.connectivity || options.connectivity_mode || draft.connectivity || "direct";
    const reachability = options.reachability || reachabilityFromEndpointInput(address, connectivity);
    const nat = options.nat || options.nat_type || draft.nat || "unknown";
    const metadata = Object.fromEntries(
      Object.entries(options).filter(([key]) => !["reachability", "connectivity", "connectivity_mode", "nat", "nat_type", "priority", "region", "transport"].includes(key)),
    );
    return [
      {
        endpoint_id: `${nodeID}-operator-${index + 1}`,
        node_id: nodeID,
        address,
        transport: options.transport || draft.advertiseTransport || "direct_quic",
        reachability,
        connectivity_mode: connectivity,
        nat_type: nat,
        region: options.region || draft.region || undefined,
        priority: Number.isFinite(Number(options.priority)) ? Number(options.priority) : index + 1,
        policy_tags: ["operator-configured", "desired-fabric-listener"],
        metadata: {
          source: "web-admin.fabric-listener",
          verification_scope: reachability === "public" ? "external-network-required" : "local-or-peer-probe",
          ...metadata,
        },
      },
    ];
  });
}

function reachabilityFromEndpointInput(address: string, connectivity: string) {
  if (connectivity === "relay_required") {
    return "relay";
  }
  if (connectivity === "outbound_only") {
    return "outbound_only";
  }
  const host = address.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "").split(/[/:?#]/)[0] || "";
  if (
    host === "localhost" ||
    host.startsWith("127.") ||
    host.startsWith("10.") ||
    host.startsWith("192.168.") ||
    /^172\.(1[6-9]|2\d|3[0-1])\./.test(host)
  ) {
    return "private";
  }
  return "public";
}

function compactJSON(value: unknown) {
  if (value == null) {
    return "н/д";
  }
  const raw = JSON.stringify(value);
  return raw.length > 140 ? `${raw.slice(0, 137)}...` : raw;
}

function peerCandidateProbeSummary(result: Record<string, unknown>) {
  const candidates = arrayObjects(result.candidate_results);
  if (candidates.length === 0) {
    return "н/д";
  }
  return candidates
    .slice(0, 4)
    .map((candidate) => {
      const id = stringField(candidate, "candidate_id", "candidate");
      const status = stringField(candidate, "link_status", "unknown");
      const latency = stringField(candidate, "latency_ms", "");
      return latency && latency !== "0" ? `${id}:${status}:${latency}мс` : `${id}:${status}`;
    })
    .join(", ");
}

function countPeerEndpointCandidates(config: NodeSyntheticMeshConfig) {
  return Object.values(config.peer_endpoint_candidates || {}).reduce((sum, candidates) => sum + candidates.length, 0);
}

function rendezvousRelayPolicySummary(config?: NodeSyntheticMeshConfig) {
  const policy = config?.rendezvous_relay_policy;
  if (!policy) {
    return "none";
  }
  const parts = [`stale${policy.stale_relay_count}`, `wd${policy.withdrawn_lease_count}`, `repl${policy.replacement_lease_count}`];
  if (policy.scoring_mode.includes("synthetic_route_health_feedback")) {
    parts.push("rh feedback");
  }
  const selected = policy.decisions?.find((decision) => decision.selected_relay_id);
  if (selected?.selected_relay_id) {
    parts.push(`via ${shortId(selected.selected_relay_id)}`);
  }
  return parts.join(" ");
}

function routePathDecisionSummary(config?: NodeSyntheticMeshConfig) {
	const report = config?.route_path_decisions;
	if (!report) {
		return "none";
	}
	const parts = [`path${report.decision_count}`, `repl${report.replacement_decision_count}`];
	if ((report.degraded_decision_count || 0) > 0) {
		parts.push(`degr${report.degraded_decision_count}`);
	}
	const selected = report.decisions?.find((decision) => decision.selected_relay_id || decision.next_hop_id);
  if (selected?.selected_relay_id) {
    parts.push(`via ${shortId(selected.selected_relay_id)}`);
  } else if (selected?.next_hop_id) {
    parts.push(`next ${shortId(selected.next_hop_id)}`);
  }
  return parts.join(" ");
}

function nodeName(nodes: ClusterNode[], id: string) {
  return nodes.find((node) => node.id === id)?.name || shortId(id);
}

function groupPathLabel(group: ClusterNodeGroup, groups: ClusterNodeGroup[]) {
  const byId = new Map(groups.map((item) => [item.id, item]));
  const parts = [group.name];
  let parentID = group.parent_group_id;
  const seen = new Set<string>([group.id]);
  while (parentID && !seen.has(parentID)) {
    seen.add(parentID);
    const parent = byId.get(parentID);
    if (!parent) {
      break;
    }
    parts.unshift(parent.name);
    parentID = parent.parent_group_id;
  }
  return parts.join(" / ");
}

function groupPathLabelById(groupId: string, groups: ClusterNodeGroup[]) {
  const group = groups.find((item) => item.id === groupId);
  return group ? groupPathLabel(group, groups) : groupId;
}

function descendantGroupIds(groupId: string, groups: ClusterNodeGroup[]) {
  const result: string[] = [];
  const childrenByParent = new Map<string, ClusterNodeGroup[]>();
  for (const group of groups) {
    const parentKey = group.parent_group_id || "";
    childrenByParent.set(parentKey, [...(childrenByParent.get(parentKey) || []), group]);
  }
  const visit = (parentId: string) => {
    for (const child of childrenByParent.get(parentId) || []) {
      result.push(child.id);
      visit(child.id);
    }
  };
  visit(groupId);
  return result;
}

function buildNodeInventoryTreeRows(
  entries: NodeInventoryEntry[],
  groups: ClusterNodeGroup[],
  selectedClusterId: string,
  labels: Record<string, string>,
  collapsedGroupKeys: Set<string>,
): NodeInventoryTreeRow[] {
  const rows: NodeInventoryTreeRow[] = [];
  const entriesByGroup = new Map<string, NodeInventoryEntry[]>();
  const activeUngrouped: NodeInventoryEntry[] = [];
  const outsideActiveCluster: NodeInventoryEntry[] = [];

  for (const entry of entries) {
    const activeMembership = entry.memberships.find((membership) => membership.cluster.id === selectedClusterId);
    if (!activeMembership) {
      outsideActiveCluster.push(entry);
      continue;
    }
    const groupID = activeMembership.node.node_group_id;
    if (!groupID) {
      activeUngrouped.push(entry);
      continue;
    }
    entriesByGroup.set(groupID, [...(entriesByGroup.get(groupID) || []), entry]);
  }

  const childrenByParent = new Map<string, ClusterNodeGroup[]>();
  for (const group of groups) {
    const parentKey = group.parent_group_id || "";
    childrenByParent.set(parentKey, [...(childrenByParent.get(parentKey) || []), group]);
  }
  for (const childGroups of childrenByParent.values()) {
    childGroups.sort((left, right) => left.sort_order - right.sort_order || left.name.localeCompare(right.name));
  }

  const countByGroup = new Map<string, number>();
  const countGroupEntries = (group: ClusterNodeGroup): number => {
    const cached = countByGroup.get(group.id);
    if (cached != null) {
      return cached;
    }
    let count = entriesByGroup.get(group.id)?.length || 0;
    for (const child of childrenByParent.get(group.id) || []) {
      count += countGroupEntries(child);
    }
    countByGroup.set(group.id, count);
    return count;
  };

  const appendGroup = (group: ClusterNodeGroup, depth: number): number => {
    const ownEntries = [...(entriesByGroup.get(group.id) || [])].sort((left, right) => left.node.name.localeCompare(right.node.name));
    const childGroups = childrenByParent.get(group.id) || [];
    const rowKey = `group-${group.id}`;
    const count = countGroupEntries(group);
    rows.push({ kind: "group", key: rowKey, label: group.name, depth, count, groupId: group.id });
    if (!collapsedGroupKeys.has(rowKey)) {
      for (const entry of ownEntries) {
        rows.push({ kind: "node", key: `node-${group.id}-${entry.node.id}`, entry, depth: depth + 1 });
      }
      for (const child of childGroups) {
        appendGroup(child, depth + 1);
      }
    }
    return count;
  };

  for (const group of childrenByParent.get("") || []) {
    appendGroup(group, 0);
  }

  if (activeUngrouped.length > 0) {
    const rowKey = "group-ungrouped";
    rows.push({ kind: "group", key: rowKey, label: labels.ungroupedNodes, depth: 0, count: activeUngrouped.length });
    if (!collapsedGroupKeys.has(rowKey)) {
      for (const entry of activeUngrouped.sort((left, right) => left.node.name.localeCompare(right.node.name))) {
        rows.push({ kind: "node", key: `node-ungrouped-${entry.node.id}`, entry, depth: 1 });
      }
    }
  }

  if (outsideActiveCluster.length > 0) {
    const rowKey = "group-outside-active-cluster";
    rows.push({
      kind: "group",
      key: rowKey,
      label: labels.notMemberOfActiveCluster,
      depth: 0,
      count: outsideActiveCluster.length,
    });
    if (!collapsedGroupKeys.has(rowKey)) {
      for (const entry of outsideActiveCluster.sort((left, right) => left.node.name.localeCompare(right.node.name))) {
        rows.push({ kind: "node", key: `node-outside-${entry.node.id}`, entry, depth: 1 });
      }
    }
  }

  return rows;
}

function nodesWithRole(role: string, rolesByNode: Record<string, RoleAssignment[]>) {
  return Object.entries(rolesByNode)
    .filter(([, roles]) => roles.some((assignment) => assignment.role === role && assignment.status === "active"))
    .map(([nodeId]) => nodeId);
}

function buildJoinTokenScope(input: JoinTokenFormState): Record<string, unknown> {
  const meshEndpointCandidates = parseJoinTokenEndpointCandidates(input);
  const meshAdvertiseEndpoints = meshEndpointCandidates.map((candidate) => String(candidate.address || "")).filter(Boolean);
  const primaryMeshAdvertiseEndpoint = input.meshAdvertiseEndpoint.trim().replace(/\/$/, "") || meshAdvertiseEndpoints[0] || "";
  const scope: Record<string, unknown> = {
    roles: input.roles,
    node_name: input.nodeName.trim() || null,
    node_group_id: input.nodeGroupId || null,
    ownership_type: input.ownershipType,
    purpose: input.purpose.trim() || null,
    approval: {
      mode: "manual",
      auto_approve: false,
      role_assignment: "manual_after_approval",
    },
    source: "platform_owner_console",
  };
  if (input.installMode === "docker") {
    scope.install_profile = "docker";
    scope.image = input.dockerImage || "rap-node-agent:latest";
    if (input.dockerContainerName.trim()) {
      scope.container_name = input.dockerContainerName.trim();
    }
    const artifactEndpoints = csvValues(input.artifactEndpoints);
    if (artifactEndpoints.length > 0) {
      scope.artifact_endpoints = artifactEndpoints;
    }
    if (input.dockerImageArtifactSHA256.trim()) {
      scope.docker_image_artifact_sha256 = input.dockerImageArtifactSHA256.trim();
    }
    scope.network = input.dockerNetwork || "host";
    scope.restart_policy = "unless-stopped";
    scope.pull_image = Boolean(input.pullImage);
    scope.replace = input.replace !== false;
    scope.fabric_runtime_enabled = input.syntheticRuntime === true;
    scope.mesh_production_forwarding_enabled = false;
    scope.fabric_listen_addr = input.fabricListenAddr || "";
    scope.fabric_listen_port_mode = input.fabricListenPortMode || "auto";
    scope.fabric_listen_auto_port_start = input.fabricListenAutoPortStart || 19131;
    scope.fabric_listen_auto_port_end = input.fabricListenAutoPortEnd || 19231;
    if (primaryMeshAdvertiseEndpoint) {
      scope.mesh_advertise_endpoint = primaryMeshAdvertiseEndpoint;
    }
    if (meshEndpointCandidates.length > 0) {
      scope.mesh_advertise_endpoints_json = JSON.stringify(meshEndpointCandidates);
    }
    scope.mesh_advertise_transport = input.meshAdvertiseTransport || "direct_quic";
    scope.mesh_connectivity_mode = input.meshConnectivityMode || "private_lan";
    scope.mesh_nat_type = input.meshNATType || "unknown";
    scope.mesh_region = input.meshRegion || null;
  }
  if (input.installMode === "windows_service") {
    scope.install_profile = "windows_service";
    const artifactEndpoints = csvValues(input.artifactEndpoints);
    if (artifactEndpoints.length > 0) {
      scope.artifact_endpoints = artifactEndpoints;
    }
    scope.startup_mode = input.windowsStartupMode || "auto";
    if (input.windowsInstallDir.trim()) {
      scope.install_dir = input.windowsInstallDir.trim();
    }
    if (input.windowsNodeAgentSHA256.trim()) {
      scope.node_agent_artifact_sha256 = input.windowsNodeAgentSHA256.trim();
    }
    scope.fabric_runtime_enabled = input.syntheticRuntime === true;
    scope.mesh_production_forwarding_enabled = false;
    scope.fabric_listen_addr = input.fabricListenAddr || "";
    scope.fabric_listen_port_mode = input.fabricListenPortMode || "auto";
    scope.fabric_listen_auto_port_start = input.fabricListenAutoPortStart || 19131;
    scope.fabric_listen_auto_port_end = input.fabricListenAutoPortEnd || 19231;
    if (primaryMeshAdvertiseEndpoint) {
      scope.mesh_advertise_endpoint = primaryMeshAdvertiseEndpoint;
    }
    if (meshEndpointCandidates.length > 0) {
      scope.mesh_advertise_endpoints_json = JSON.stringify(meshEndpointCandidates);
    }
    scope.mesh_advertise_transport = input.meshAdvertiseTransport || "direct_quic";
    scope.mesh_connectivity_mode = input.meshConnectivityMode || "outbound_only";
    scope.mesh_nat_type = input.meshNATType || "unknown";
    scope.mesh_region = input.meshRegion || "windows";
  }
  if (input.installMode === "linux_binary") {
    scope.install_profile = "linux_binary";
    const artifactEndpoints = csvValues(input.artifactEndpoints);
    if (artifactEndpoints.length > 0) {
      scope.artifact_endpoints = artifactEndpoints;
    }
    scope.startup_mode = "systemd";
    if (input.linuxInstallDir.trim()) {
      scope.install_dir = input.linuxInstallDir.trim();
    }
    if (input.linuxNodeAgentSHA256.trim()) {
      scope.node_agent_artifact_sha256 = input.linuxNodeAgentSHA256.trim();
    }
    scope.replace = input.replace !== false;
    scope.fabric_runtime_enabled = input.syntheticRuntime === true;
    scope.mesh_production_forwarding_enabled = false;
    scope.fabric_listen_addr = input.fabricListenAddr || "";
    scope.fabric_listen_port_mode = input.fabricListenPortMode || "auto";
    scope.fabric_listen_auto_port_start = input.fabricListenAutoPortStart || 19131;
    scope.fabric_listen_auto_port_end = input.fabricListenAutoPortEnd || 19231;
    if (primaryMeshAdvertiseEndpoint) {
      scope.mesh_advertise_endpoint = primaryMeshAdvertiseEndpoint;
    }
    if (meshEndpointCandidates.length > 0) {
      scope.mesh_advertise_endpoints_json = JSON.stringify(meshEndpointCandidates);
    }
    scope.mesh_advertise_transport = input.meshAdvertiseTransport || "direct_quic";
    scope.mesh_connectivity_mode = input.meshConnectivityMode || "outbound_only";
    scope.mesh_nat_type = input.meshNATType || "unknown";
    scope.mesh_region = input.meshRegion || "linux";
  }
  return scope;
}

function joinTokenFormFromScope(scope: Record<string, unknown>, fallback: JoinTokenFormState): JoinTokenFormState {
  const roles = arrayStrings(scope.roles);
  const artifactEndpoints = arrayStrings(scope.artifact_endpoints).join(", ");
  return {
    ...fallback,
    roles: roles.length > 0 ? roles : fallback.roles,
    nodeName: stringField(scope, "node_name", "") || fallback.nodeName,
    nodeGroupId: stringField(scope, "node_group_id", "") || fallback.nodeGroupId,
    ownershipType: stringField(scope, "ownership_type", fallback.ownershipType),
    purpose: stringField(scope, "purpose", "") || fallback.purpose,
    installMode: stringField(scope, "install_profile", fallback.installMode),
    dockerImage: stringField(scope, "image", fallback.dockerImage),
    dockerContainerName: stringField(scope, "container_name", "") || fallback.dockerContainerName,
    dockerNetwork: stringField(scope, "network", fallback.dockerNetwork),
    windowsStartupMode: stringField(scope, "startup_mode", fallback.windowsStartupMode),
    windowsInstallDir: stringField(scope, "install_dir", "") || fallback.windowsInstallDir,
    windowsNodeAgentSHA256: stringField(scope, "node_agent_artifact_sha256", "") || fallback.windowsNodeAgentSHA256,
    linuxInstallDir: stringField(scope, "install_dir", "") || fallback.linuxInstallDir,
    linuxNodeAgentSHA256: stringField(scope, "node_agent_artifact_sha256", "") || fallback.linuxNodeAgentSHA256,
    fabricListenAddr: stringField(scope, "fabric_listen_addr", fallback.fabricListenAddr),
    fabricListenPortMode: stringField(scope, "fabric_listen_port_mode", fallback.fabricListenPortMode),
    fabricListenAutoPortStart: numberField(scope, "fabric_listen_auto_port_start", fallback.fabricListenAutoPortStart),
    fabricListenAutoPortEnd: numberField(scope, "fabric_listen_auto_port_end", fallback.fabricListenAutoPortEnd),
    meshAdvertiseEndpoint: stringField(scope, "mesh_advertise_endpoint", "") || fallback.meshAdvertiseEndpoint,
    meshAdvertiseEndpoints: joinTokenAdvertiseEndpointsToText(scope) || fallback.meshAdvertiseEndpoints,
    meshAdvertiseTransport: stringField(scope, "mesh_advertise_transport", fallback.meshAdvertiseTransport),
    meshConnectivityMode: stringField(scope, "mesh_connectivity_mode", fallback.meshConnectivityMode),
    meshNATType: stringField(scope, "mesh_nat_type", fallback.meshNATType),
    meshRegion: stringField(scope, "mesh_region", "") || fallback.meshRegion,
    artifactEndpoints: artifactEndpoints || fallback.artifactEndpoints,
    dockerImageArtifactSHA256: stringField(scope, "docker_image_artifact_sha256", "") || fallback.dockerImageArtifactSHA256,
    pullImage: booleanField(scope, "pull_image", fallback.pullImage),
    replace: booleanField(scope, "replace", fallback.replace),
    syntheticRuntime: booleanField(scope, "fabric_runtime_enabled", fallback.syntheticRuntime),
  };
}

function joinTokenAdvertiseEndpointsToText(scope: Record<string, unknown>) {
  const raw = stringField(scope, "mesh_advertise_endpoints_json", "");
  if (!raw) {
    return "";
  }
  try {
    const parsed = JSON.parse(raw);
    if (!Array.isArray(parsed)) {
      return "";
    }
    return parsed
      .map((item) => {
        const candidate = objectField(item);
        if (!candidate) {
          return "";
        }
        const address = stringField(candidate, "address", "");
        if (!address) {
          return "";
        }
        const parts = [address];
        for (const key of ["reachability", "connectivity_mode", "nat_type", "region", "priority"] as const) {
          const value = stringField(candidate, key, "");
          if (value) {
            parts.push(`${key.replace("_mode", "").replace("_type", "")}=${value}`);
          }
        }
        const metadata = objectField(candidate.metadata);
        for (const key of ["provider", "interface", "maps_to"] as const) {
          const value = stringField(metadata, key, "");
          if (value) {
            parts.push(`${key}=${value}`);
          }
        }
        return parts.join(" ");
      })
      .filter(Boolean)
      .join("\n");
  } catch {
    return "";
  }
}

function parseJoinTokenEndpointCandidates(input: JoinTokenFormState) {
  return parseFabricListenerEndpointCandidates(
    {
      endpointCandidates: input.meshAdvertiseEndpoints,
      advertiseEndpoint: input.meshAdvertiseEndpoint,
      advertiseTransport: input.meshAdvertiseTransport || "direct_quic",
      connectivity: input.meshConnectivityMode,
      nat: input.meshNATType,
      region: input.meshRegion,
    },
    input.nodeName.trim() || "install-node",
  );
}

function arrayStrings(value: unknown) {
  return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string").map((item) => item.trim()).filter(Boolean) : [];
}

function booleanField(source: Record<string, unknown>, key: string, fallback: boolean) {
  const value = source[key];
  return typeof value === "boolean" ? value : fallback;
}

function defaultArtifactEndpoint() {
  return "";
}

function csvValues(value: string) {
  return value
    .split(",")
    .map((item) => item.trim().replace(/\/$/, ""))
    .filter(Boolean);
}

function dockerConnectivityPreset(input: { meshConnectivityMode: string; meshNATType: string; meshAdvertiseEndpoint: string }) {
  if (input.meshConnectivityMode === "outbound_only") {
    return "outbound_only";
  }
  if (input.meshConnectivityMode === "private_lan") {
    return "private_lan";
  }
  if (input.meshNATType !== "none" && input.meshAdvertiseEndpoint.trim()) {
    return "nat_forward";
  }
  return "direct";
}

function applyDockerConnectivityPreset(input: JoinTokenFormState, mode: string): JoinTokenFormState {
  const next = { ...input };
  if (mode === "private_lan") {
    next.meshConnectivityMode = "private_lan";
    next.meshNATType = "none";
  } else if (mode === "direct") {
    next.meshConnectivityMode = "direct";
    next.meshNATType = "none";
  } else if (mode === "nat_forward") {
    next.meshConnectivityMode = "direct";
    next.meshNATType = "port_restricted";
  } else {
    next.meshConnectivityMode = "outbound_only";
    next.meshNATType = "symmetric";
    next.meshAdvertiseEndpoint = "";
  }
  return next;
}

function suggestedInstallNodeName(form: Pick<JoinTokenFormState, "nodeName">, cluster: Cluster | null) {
  if (form.nodeName.trim()) {
    return form.nodeName.trim();
  }
  const slug = safeShellSlug(cluster?.slug || cluster?.name || "rap-node");
  return `${slug}-node-1`;
}

function suggestedInstallContainerName(form: Pick<JoinTokenFormState, "nodeName" | "dockerContainerName">, cluster: Cluster | null) {
  if (form.dockerContainerName.trim()) {
    return form.dockerContainerName.trim();
  }
  return `rap-node-agent-${safeShellSlug(suggestedInstallNodeName(form, cluster))}`;
}

function externalPreferredFabricControlEndpoint() {
  return "QUIC fabric registry";
}

function joinBundleFileName(installMode: string, cluster: Cluster | null, form: JoinTokenFormState = defaultJoinTokenForm) {
  const nodeName = suggestedInstallNodeName(form, cluster);
  const suffix = installMode === "windows_service" ? "windows" : installMode === "linux_binary" ? "linux" : "docker";
  return `rap-join-${suffix}-${safeDownloadName(nodeName)}.json`;
}

function joinBundleRequestBody(token: CreatedJoinToken, cluster: Cluster | null, form: JoinTokenFormState = defaultJoinTokenForm) {
  const clusterID = cluster?.id || token.cluster_id;
  const nodeName = suggestedInstallNodeName(form, cluster);
  return JSON.stringify(
    {
      cluster_id: clusterID,
      install_token: token.token,
      node_name: nodeName,
    },
    null,
    2,
  );
}

function joinInstallCommand(token: CreatedJoinToken, cluster: Cluster | null, form: JoinTokenFormState = defaultJoinTokenForm) {
  if (form.installMode === "windows_service") {
    return joinWindowsInstallCommand(token, cluster, form);
  }
  if (form.installMode === "linux_binary") {
    return joinLinuxInstallCommand(token, cluster, form);
  }
  return joinDockerInstallCommand(token, cluster, form);
}

function joinDockerInstallCommand(token: CreatedJoinToken, cluster: Cluster | null, form: JoinTokenFormState = defaultJoinTokenForm) {
  const bundleFile = joinBundleFileName("docker", cluster, form);
  return [
    "chmod +x ./rap-host-agent",
    `./rap-host-agent install --join-bundle ${shellQuote(`./${bundleFile}`)}`,
  ].join(" && \\\n  ");
}

function joinLinuxInstallCommand(token: CreatedJoinToken, cluster: Cluster | null, form: JoinTokenFormState = defaultJoinTokenForm) {
  const bundleFile = joinBundleFileName("linux_binary", cluster, form);
  return [
    "chmod +x ./rap-host-agent",
    `sudo ./rap-host-agent install-linux --join-bundle ${shellQuote(`./${bundleFile}`)}`,
  ].join(" && \\\n  ");
}

function joinWindowsInstallCommand(token: CreatedJoinToken, cluster: Cluster | null, form: JoinTokenFormState = defaultJoinTokenForm) {
  const bundleFile = joinBundleFileName("windows_service", cluster, form);
  return [
    `$bundlePath = Join-Path $env:TEMP ${powershellQuote(bundleFile)}`,
    `$rapHostAgent = Join-Path (Get-Location) "rap-host-agent.exe"`,
    `& $rapHostAgent install-windows --join-bundle $bundlePath --startup-mode ${powershellQuote(form.windowsStartupMode || "auto")}`,
  ].join("\r\n");
}

function windowsRepairUpdaterCmdCommand(node: ClusterNode, clusterID: string) {
  const endpoint = externalPreferredFabricControlEndpoint();
  const nodeName = node.name || node.node_key || node.id;
  const nodeSlug = safeWindowsNodeSlug(nodeName);
  const installDir = `%ProgramFiles%\\RAP\\${nodeSlug}`;
  const taskName = `RAP Node Agent ${nodeSlug}`;
  const updaterTaskName = `RAP Host Agent Updater ${nodeSlug}`;
  const hostAgentPath = `${installDir}\\rap-host-agent.exe`;
  const stagedHostAgentPath = `${hostAgentPath}.next`;
  return [
    `@echo off`,
    `echo === RAP Windows updater repair: ${cmdEscape(nodeName)} ===`,
    `echo Node ID: ${node.id}`,
    `echo Fabric control endpoint: ${endpoint}`,
    `echo.`,
    `echo === Before repair: scheduled tasks ===`,
    `schtasks /Query /TN "${taskName}" /V /FO LIST`,
    `schtasks /Query /TN "${updaterTaskName}" /V /FO LIST`,
    `echo.`,
    `echo === Before repair: binaries ===`,
    `dir "${installDir}\\rap-*.exe*"`,
    `echo.`,
    `copy /Y rap-host-agent.exe "${hostAgentPath}"`,
    `echo.`,
    `echo === Applying staged host-agent if present ===`,
    `if exist "${stagedHostAgentPath}" copy /Y "${stagedHostAgentPath}" "${hostAgentPath}"`,
    `if exist "${stagedHostAgentPath}" del /F /Q "${stagedHostAgentPath}"`,
    `schtasks /End /TN "${updaterTaskName}"`,
    `schtasks /Run /TN "${updaterTaskName}"`,
    `echo.`,
    `echo === After repair: binaries ===`,
    `dir "${installDir}\\rap-*.exe*"`,
    `echo.`,
    `echo === After repair: updater task ===`,
    `schtasks /Query /TN "${updaterTaskName}" /V /FO LIST`,
    `echo.`,
    `echo Repair command finished. Check the admin panel for rap-node-agent and rap-host-agent plan/noop reports.`,
  ].join("\r\n");
}

function windowsRepairUpdaterCmdFileName(node: ClusterNode) {
  const nodeName = safeDownloadName(node.name || node.node_key || node.id || "node");
  return `rap-repair-updater-${nodeName}.cmd`;
}

function linuxRepairUpdaterShCommand(node: ClusterNode, clusterID: string) {
  const endpoint = externalPreferredFabricControlEndpoint();
  const nodeName = node.name || node.node_key || node.id;
  const nodeSlug = safeLinuxNodeSlug(nodeName);
  const installDir = `/opt/rap/${nodeSlug}`;
  const unitName = `rap-node-agent-${nodeSlug}.service`;
  const updaterUnitName = `rap-host-agent-updater-${nodeSlug}.service`;
  const hostAgentPath = `${installDir}/rap-host-agent`;
  return [
    `#!/usr/bin/env bash`,
    `set -euo pipefail`,
    `echo "=== RAP Linux updater repair: ${shDoubleQuote(nodeName)} ==="`,
    `echo "Node ID: ${node.id}"`,
    `echo "Fabric control endpoint: ${endpoint}"`,
    `echo`,
    `echo "=== Before repair: systemd units ==="`,
    `systemctl status ${shellQuote(unitName)} --no-pager || true`,
    `systemctl status ${shellQuote(updaterUnitName)} --no-pager || true`,
    `echo`,
    `echo "=== Before repair: binaries ==="`,
    `ls -la ${shellQuote(installDir)} || true`,
    `echo`,
    `rap_host_agent="./rap-host-agent"`,
    `chmod +x "$rap_host_agent"`,
    `sudo install -m 0755 "$rap_host_agent" ${shellQuote(hostAgentPath)}`,
    `sudo systemctl daemon-reload`,
    `sudo systemctl restart ${shellQuote(updaterUnitName)}`,
    `echo`,
    `echo "=== After repair: systemd updater ==="`,
    `systemctl status ${shellQuote(updaterUnitName)} --no-pager || true`,
    `echo "Repair command finished. Check the admin panel for rap-node-agent and rap-host-agent plan/noop reports."`,
  ].join("\n");
}

function linuxRepairUpdaterShFileName(node: ClusterNode) {
  const nodeName = safeDownloadName(node.name || node.node_key || node.id || "node");
  return `rap-repair-updater-${nodeName}.sh`;
}

function downloadTextFile(fileName: string, content: string) {
  if (typeof document === "undefined") {
    return;
  }
  const blob = new Blob([content.endsWith("\r\n") ? content : `${content}\r\n`], { type: "text/plain;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const anchor = document.createElement("a");
  anchor.href = url;
  anchor.download = fileName;
  document.body.appendChild(anchor);
  anchor.click();
  anchor.remove();
  URL.revokeObjectURL(url);
}

async function copyTextToClipboard(content: string) {
  await navigator.clipboard.writeText(content);
}

function safeDownloadName(value: string) {
  return value
    .trim()
    .replace(/[\\/:*?"<>|]+/g, "-")
    .replace(/\s+/g, "-")
    .replace(/-+/g, "-")
    .replace(/^-|-$/g, "")
    .slice(0, 80) || "node";
}

function safeWindowsNodeSlug(value: string) {
  return value
    .trim()
    .replace(/[\\/:*?"<>|]+/g, "-")
    .replace(/\s+/g, "-")
    .replace(/-+/g, "-")
    .replace(/^-|-$/g, "") || "node";
}

function safeLinuxNodeSlug(value: string) {
  return safeWindowsNodeSlug(value).slice(0, 48) || "node";
}

function shDoubleQuote(value: string) {
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\$/g, "\\$").replace(/`/g, "\\`");
}

function safeShellSlug(value: string) {
  return (
    value
      .trim()
      .toLowerCase()
      .replace(/[^a-z0-9-]+/g, "-")
      .replace(/^-+|-+$/g, "")
      .slice(0, 42) || "rap-node"
  );
}

function shellQuote(value: string) {
  return `'${value.replace(/'/g, `'\\''`)}'`;
}

function powershellQuote(value: string) {
  return `'${value.replace(/'/g, "''")}'`;
}

function cmdEscape(value: string) {
  return value.replace(/"/g, `""`);
}

function toggleArrayValue(values: string[], value: string) {
  return values.includes(value) ? values.filter((item) => item !== value) : [...values, value];
}

function groupNodeInventory(
  entries: NodeInventoryEntry[],
  selectedClusterId: string,
  search: string,
  groupBy: "membership" | "health" | "ownership" | "cluster_count",
  language: Language,
) {
  const normalizedSearch = search.trim().toLowerCase();
  const groups = new Map<string, NodeInventoryEntry[]>();

  for (const entry of entries) {
    if (normalizedSearch && !nodeInventoryMatches(entry, normalizedSearch)) {
      continue;
    }
    const key = nodeInventoryGroupLabel(entry, selectedClusterId, groupBy, language);
    groups.set(key, [...(groups.get(key) || []), entry]);
  }

  return Array.from(groups.entries())
    .map(([label, items]) => ({ label, items: items.sort((left, right) => left.node.name.localeCompare(right.node.name)) }))
    .sort((left, right) => left.label.localeCompare(right.label));
}

function nodeInventoryMatches(entry: NodeInventoryEntry, search: string) {
  const values = [
    entry.node.name,
    entry.node.node_key,
    entry.node.health_status,
    entry.node.ownership_type,
    entry.node.reported_version || "",
    ...entry.memberships.flatMap((membership) => [membership.cluster.name, membership.cluster.slug, membership.node.membership_status]),
  ];
  return values.some((value) => value.toLowerCase().includes(search));
}

function nodeInventoryGroupLabel(
  entry: NodeInventoryEntry,
  selectedClusterId: string,
  groupBy: "membership" | "health" | "ownership" | "cluster_count",
  language: Language,
) {
  if (groupBy === "health") {
    return statusLabel(entry.node.health_status);
  }
  if (groupBy === "ownership") {
    return statusLabel(entry.node.ownership_type);
  }
  if (groupBy === "cluster_count") {
    return clusterCountLabel(entry.memberships.length, language);
  }

  const activeMembership = entry.memberships.find((membership) => membership.cluster.id === selectedClusterId);
  if (!activeMembership) {
    return language === "en" ? "Not in active cluster" : "Не в активном кластере";
  }
  if (activeMembership.node.membership_status === "active") {
    return language === "en" ? "In active cluster" : "В активном кластере";
  }
  return `${language === "en" ? "Membership" : "Участие"}: ${statusLabel(activeMembership.node.membership_status)}`;
}

function capabilityState(role: string, heartbeat?: NodeHeartbeat) {
  const expectedKeys = capabilityKeysByRole[role] || [];
  if (expectedKeys.length === 0 || !heartbeat) {
    return "unknown";
  }
  if (isHeartbeatStale(heartbeat)) {
    return "stale";
  }
  const capabilities = heartbeat.capabilities || {};
  return expectedKeys.some((key) => Boolean(capabilities[key])) ? "confirmed" : "missing";
}

function isHeartbeatStale(heartbeat?: NodeHeartbeat) {
  if (!heartbeat?.observed_at) {
    return true;
  }
  const observedAt = new Date(heartbeat.observed_at).getTime();
  return !Number.isFinite(observedAt) || Date.now() - observedAt > 60 * 1000;
}

function capabilityPillTone(role: string, heartbeat?: NodeHeartbeat) {
  const state = capabilityState(role, heartbeat);
  if (state === "confirmed") {
    return "good";
  }
  if (state === "missing") {
    return "bad";
  }
  if (state === "stale") {
    return "warn";
  }
  return "";
}

function capabilityLabel(role: string, heartbeat: NodeHeartbeat | undefined, labels: Record<string, string>) {
  const state = capabilityState(role, heartbeat);
  if (state === "confirmed") {
    return labels.capabilityConfirmed;
  }
  if (state === "missing") {
    return labels.capabilityMissing;
  }
  if (state === "stale") {
    return "heartbeat устарел";
  }
  return labels.capabilityUnknown;
}

function capabilityOptionLabel(role: string, heartbeat: NodeHeartbeat | undefined, language: Language) {
  const state = capabilityState(role, heartbeat);
  if (language === "en") {
    return state === "confirmed" ? "capable" : state === "missing" ? "not reported" : state === "stale" ? "stale heartbeat" : "unknown";
  }
  return state === "confirmed" ? "подходит" : state === "missing" ? "не заявлено" : state === "stale" ? "heartbeat устарел" : "неизвестно";
}

function meshRecoverySummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_peer_recovery_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const mode = typeof fields.mode === "string" ? fields.mode : "unknown";
  const ready = typeof fields.ready_peer_count === "number" ? fields.ready_peer_count : null;
  const target = typeof fields.target_ready_peers === "number" ? fields.target_ready_peers : null;
  const deficit = typeof fields.deficit === "number" ? fields.deficit : 0;
  const base = ready == null || target == null ? mode : `${mode} ${ready}/${target}`;
  return deficit > 0 ? `${base} deficit ${deficit}` : base;
}

function meshConnectionIntentSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_peer_connection_intent_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return meshConnectionManagerSummary(heartbeat);
  }
  const fields = report as Record<string, unknown>;
  const intentCount = typeof fields.intent_count === "number" ? fields.intent_count : 0;
  const maintain = typeof fields.maintain_count === "number" ? fields.maintain_count : 0;
  const recover = typeof fields.recover_count === "number" ? fields.recover_count : 0;
  const rendezvous = typeof fields.rendezvous_required_count === "number" ? fields.rendezvous_required_count : 0;
  const resolved = typeof fields.rendezvous_resolved_count === "number" ? fields.rendezvous_resolved_count : 0;
  const relayQUIC = typeof fields.relay_quic_count === "number" ? fields.relay_quic_count : 0;
  const rvPart = [`rv${rendezvous}`];
  if (resolved > 0) {
    rvPart.push(`ok${resolved}`);
  }
  if (relayQUIC > 0) {
    rvPart.push(`relay${relayQUIC}`);
  }
  const base =
    rendezvous > 0 || resolved > 0 || relayQUIC > 0
      ? `${intentCount} intents m${maintain}/r${recover} ${rvPart.join("/")}`
      : `${intentCount} intents m${maintain}/r${recover}`;
  const manager = meshConnectionManagerSummary(heartbeat);
  return manager === "н/д" ? base : `${base}; ${manager}`;
}

function meshRendezvousLeaseSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_rendezvous_lease_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const total = typeof fields.lease_count === "number" ? fields.lease_count : 0;
  const active = typeof fields.active_count === "number" ? fields.active_count : 0;
  const relay = typeof fields.admitted_as_relay_count === "number" ? fields.admitted_as_relay_count : 0;
  const peer = typeof fields.admitted_as_peer_count === "number" ? fields.admitted_as_peer_count : 0;
  const renewal = typeof fields.renewal_needed_count === "number" ? fields.renewal_needed_count : 0;
  const ready = typeof fields.relay_quic_ready_count === "number" ? fields.relay_quic_ready_count : 0;
  const stale = typeof fields.stale_relay_count === "number" ? fields.stale_relay_count : 0;
  const refreshAttempts = typeof fields.refresh_attempt_count === "number" ? fields.refresh_attempt_count : 0;
  const refreshSuccess = typeof fields.refresh_success_count === "number" ? fields.refresh_success_count : 0;
  const parts = [`lease ${active}/${total}`];
  if (relay > 0) {
    parts.push(`relay${relay}`);
  }
  if (peer > 0) {
    parts.push(`peer${peer}`);
  }
  if (renewal > 0) {
    parts.push(`renew${renewal}`);
  }
  if (stale > 0) {
    parts.push(`stale${stale}`);
  }
  if (ready > 0) {
    parts.push(`ready${ready}`);
  }
  if (refreshAttempts > 0) {
    parts.push(`ref${refreshSuccess}/${refreshAttempts}`);
  }
  return parts.join(" ");
}

function meshRoutePathDecisionSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_route_path_decision_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const total = typeof fields.decision_count === "number" ? fields.decision_count : 0;
  const replacements = typeof fields.replacement_decision_count === "number" ? fields.replacement_decision_count : 0;
  const degraded = typeof fields.degraded_decision_count === "number" ? fields.degraded_decision_count : 0;
  const recoveryHysteresis = typeof fields.recovery_hysteresis_count === "number" ? fields.recovery_hysteresis_count : 0;
  const recoveryPromoted = typeof fields.recovery_promoted_count === "number" ? fields.recovery_promoted_count : 0;
  const recoveryDemoted = typeof fields.recovery_demoted_count === "number" ? fields.recovery_demoted_count : 0;
  const local = typeof fields.local_effective_path_count === "number" ? fields.local_effective_path_count : 0;
  const next = typeof fields.next_hop_available_count === "number" ? fields.next_hop_available_count : 0;
  const withdrawn = typeof fields.withdrawn_local_relay_count === "number" ? fields.withdrawn_local_relay_count : 0;
  const parts = [`path ${local}/${total}`];
  if (replacements > 0) {
    parts.push(`repl${replacements}`);
  }
  if (degraded > 0) {
    parts.push(`degr${degraded}`);
  }
  if (recoveryHysteresis > 0) {
    parts.push(`rec${recoveryHysteresis}`);
  }
  if (recoveryPromoted > 0) {
    parts.push(`prom${recoveryPromoted}`);
  }
  if (recoveryDemoted > 0) {
    parts.push(`dem${recoveryDemoted}`);
  }
  if (next > 0) {
    parts.push(`next${next}`);
  }
  if (withdrawn > 0) {
    parts.push(`wd${withdrawn}`);
  }
  return parts.join(" ");
}

function meshRouteGenerationSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_route_generation_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const active = typeof fields.active_decision_count === "number" ? fields.active_decision_count : 0;
  const applied = typeof fields.applied_decision_count === "number" ? fields.applied_decision_count : 0;
  const withdrawn = typeof fields.withdrawn_decision_count === "number" ? fields.withdrawn_decision_count : 0;
  const changed = fields.generation_changed === true;
  const parts = [`gen ${active}`];
  if (applied > 0) {
    parts.push(`ap${applied}`);
  }
  if (withdrawn > 0) {
    parts.push(`wd${withdrawn}`);
  }
  if (changed) {
    parts.push("chg");
  }
  return parts.join(" ");
}

function meshRouteHealthConfigSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_route_health_config_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const feedbackReport = heartbeat?.metadata?.mesh_route_health_feedback_refresh_report;
  const feedbackFields =
    feedbackReport && typeof feedbackReport === "object" && !Array.isArray(feedbackReport)
      ? (feedbackReport as Record<string, unknown>)
      : {};
  const routes = typeof fields.route_health_route_count === "number" ? fields.route_health_route_count : 0;
  const applied = typeof fields.route_path_decision_applied_count === "number" ? fields.route_path_decision_applied_count : 0;
  const replacements = typeof fields.replacement_route_health_route_count === "number" ? fields.replacement_route_health_route_count : 0;
  const drift = typeof fields.route_health_decision_drift_candidate_count === "number" ? fields.route_health_decision_drift_candidate_count : 0;
  const feedbackAttempts =
    typeof feedbackFields.feedback_refresh_attempt_count === "number"
      ? feedbackFields.feedback_refresh_attempt_count
      : typeof fields.feedback_refresh_attempt_count === "number"
        ? fields.feedback_refresh_attempt_count
        : 0;
  const feedbackSuccesses =
    typeof feedbackFields.feedback_refresh_success_count === "number"
      ? feedbackFields.feedback_refresh_success_count
      : typeof fields.feedback_refresh_success_count === "number"
        ? fields.feedback_refresh_success_count
        : 0;
  const feedbackSuppressed =
    typeof feedbackFields.feedback_refresh_suppressed_count === "number"
      ? feedbackFields.feedback_refresh_suppressed_count
      : typeof fields.feedback_refresh_suppressed_count === "number"
        ? fields.feedback_refresh_suppressed_count
        : 0;
  const parts = [`rh ${applied}/${routes}`];
  if (replacements > 0) {
    parts.push(`repl${replacements}`);
  }
  if (drift > 0) {
    parts.push(`drift${drift}`);
  }
  if (feedbackAttempts > 0 || feedbackSuppressed > 0) {
    parts.push(`fb${feedbackSuccesses}/${feedbackAttempts}`);
  }
  if (feedbackSuppressed > 0) {
    parts.push(`sup${feedbackSuppressed}`);
  }
  return parts.join(" ");
}

function meshConnectionManagerSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_peer_connection_manager_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  if (fields.enabled === false) {
    return "manager off";
  }
  const attempted = typeof fields.attempted === "number" ? fields.attempted : 0;
  const succeeded = typeof fields.succeeded === "number" ? fields.succeeded : 0;
  const deferred = typeof fields.deferred === "number" ? fields.deferred : 0;
  const relayQUIC = typeof fields.relay_quic_count === "number" ? fields.relay_quic_count : 0;
  const base = relayQUIC > 0 ? `mgr ${succeeded}/${attempted} relay${relayQUIC}` : `mgr ${succeeded}/${attempted}`;
  return deferred > 0 ? `${base} def${deferred}` : base;
}

function fabricListenerSummary(heartbeat?: NodeHeartbeat) {
  const report = heartbeat?.metadata?.mesh_listener_report;
  if (!report || typeof report !== "object" || Array.isArray(report)) {
    return "н/д";
  }
  const fields = report as Record<string, unknown>;
  const status = typeof fields.status === "string" ? fields.status : "unknown";
  const mode = typeof fields.listen_port_mode === "string" ? fields.listen_port_mode : "manual";
  const effective = typeof fields.effective_listen_addr === "string" ? fields.effective_listen_addr : "";
  const reason = typeof fields.failure_reason === "string" ? fields.failure_reason : "";
  if (status === "listening") {
    return effective ? `listen ${effective}` : "listen";
  }
  if (status === "auto_rebound") {
    return effective ? `auto ${effective}` : "auto rebound";
  }
  if (status === "listen_failed") {
    return reason ? `${mode} failed: ${reason}` : `${mode} failed`;
  }
  if (status === "disabled") {
    return mode === "disabled" ? "inbound off" : "inbound unavailable";
  }
  return status;
}

function clusterCountLabel(count: number, language: Language) {
  if (language === "en") {
    return count === 1 ? "1 cluster" : `${count} clusters`;
  }
  const mod10 = count % 10;
  const mod100 = count % 100;
  if (mod10 === 1 && mod100 !== 11) {
    return `${count} кластер`;
  }
  if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) {
    return `${count} кластера`;
  }
  return `${count} кластеров`;
}

function linkTone(link: MeshLink, status: TopologyLinkStatus = link.link_status === "reachable" ? "reachable" : "unknown") {
  if (status === "stale") {
    return "stale";
  }
  if (status === "one_way") {
    return "oneWay";
  }
  if (status !== "reachable" || link.link_status !== "reachable") {
    return "bad";
  }
  if (link.quality_score != null && link.quality_score < 70) {
    return "weak";
  }
  if (link.latency_ms != null && link.latency_ms > 80) {
    return "weak";
  }
  return "good";
}

function trimNodeName(value: string, maxLength = 16) {
  return value.length > maxLength ? `${value.slice(0, Math.max(1, maxLength - 2))}…` : value;
}

function confirmHighRisk(action: string) {
  return window.confirm(`${action}?\n\nЭто высокорисковая операция владельца платформы. Действие будет записано в аудит.`);
}

function shortId(value?: string | null) {
  if (!value) {
    return "нет";
  }
  return value.length > 12 ? `${value.slice(0, 8)}...${value.slice(-4)}` : value;
}

function formatDate(value?: string | null) {
  if (!value) {
    return "никогда";
  }
  return new Intl.DateTimeFormat(undefined, {
    dateStyle: "medium",
    timeStyle: "short",
  }).format(new Date(value));
}

function formatAgeSeconds(value?: number | null) {
  if (value == null || Number.isNaN(value)) {
    return "age n/a";
  }
  if (value < 60) {
    return `${Math.max(0, Math.round(value))}s ago`;
  }
  if (value < 3600) {
    return `${Math.round(value / 60)}m ago`;
  }
  if (value < 86400) {
    return `${Math.round(value / 3600)}h ago`;
  }
  return `${Math.round(value / 86400)}d ago`;
}

function formatDateAgo(value?: string | null) {
  if (!value) {
    return "time n/a";
  }
  const timestamp = Date.parse(value);
  if (Number.isNaN(timestamp)) {
    return "time n/a";
  }
  const deltaSeconds = Math.max(0, Math.round((Date.now() - timestamp) / 1000));
  return formatAgeSeconds(deltaSeconds);
}

function formatTime(value?: string | null) {
  if (!value) {
    return "н/д";
  }
  return new Intl.DateTimeFormat(undefined, {
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
  }).format(new Date(value));
}

function formatBytes(value?: number | null) {
  if (value == null || Number.isNaN(value)) {
    return "н/д";
  }
  const units = ["B", "KB", "MB", "GB", "TB"];
  let size = value;
  let index = 0;
  while (size >= 1024 && index < units.length - 1) {
    size /= 1024;
    index += 1;
  }
  return `${size.toFixed(index === 0 ? 0 : 1)} ${units[index]}`;
}

function formatTrafficClassCounts(value?: Record<string, number> | null) {
  if (!value || Object.keys(value).length === 0) {
    return "qos none";
  }
  return ["control", "interactive", "reliable", "bulk", "droppable"]
    .filter((key) => (value[key] || 0) > 0)
    .map((key) => `${key[0]}:${value[key]}`)
    .join(" ") || "qos none";
}

function formatRecommendedWindows(value?: Record<string, number> | null) {
  if (!value || Object.keys(value).length === 0) {
    return "n/a";
  }
  return ["control", "interactive", "reliable", "bulk", "droppable"]
    .filter((key) => (value[key] || 0) > 0)
    .map((key) => `${key[0]}:${value[key]}`)
    .join(" ") || "n/a";
}

function flowHealthPillClass(status?: string | null, dropped?: number | null) {
  if ((dropped || 0) > 0 || status === "critical") {
    return "bad";
  }
  if (status === "degraded") {
    return "warn";
  }
  if (status === "watch") {
    return "info";
  }
  return "good";
}

function remediationExecutionTone(status?: string) {
  switch (status) {
    case "applied":
    case "rebuild_request_applied":
      return "good";
    case "waiting_node_apply":
    case "pending_rebuild_request":
    case "pending_degraded_fallback":
    case "rebuild_request_recorded":
    case "rebuild_request_recorded_node_pending":
    case "rebuild_request_no_alternate":
    case "rebuild_request_deferred_by_policy":
    case "route_rebuild_no_safe_recovery":
      return "warn";
    case "expired":
    case "rejected_by_policy_guard":
    case "rebuild_request_rejected":
    case "rebuild_request_expired":
      return "bad";
    default:
      return status ? "bad" : "";
  }
}

function routeDecisionTone(source?: string, status?: string, reasons?: string[]) {
  if (source === "service_channel_feedback_no_alternate" || status === "pending_degraded_fallback" || (reasons || []).includes("no_unfenced_alternate_route")) {
    return "warn";
  }
  if (status === "applied" || (reasons || []).includes("service_channel_rebuild_applied")) {
    return "good";
  }
  if (source?.includes("replacement")) {
    return "info";
  }
  return source || status ? "info" : "";
}

function statusLabel(value: string) {
  const labels: Record<string, string> = {
    active: "активно",
    approved: "одобрено",
    authoritative: "authoritative",
    connecting: "подключается",
    connected: "связан",
    critical: "критично",
    current: "актуальна",
    degraded: "degraded",
    disabled: "выключено",
    enabled: "включено",
    failed: "ошибка",
    healthy: "здоров",
    watch: "наблюдение",
    flow_health_ready: "flow ready",
    flow_drops_reported: "flow drops",
    route_quality_window_drops_reported: "route drops",
    degraded_route_observed: "degraded route",
    route_quality_window_failures_reported: "route failures",
    route_quality_window_slow_samples_reported: "slow samples",
    route_send_latency_high: "high latency",
    flow_queue_pressure_high: "queue pressure high",
    bulk_pressure_with_interactive_qos_observed: "bulk+interactive",
    bulk_pressure_observed: "bulk pressure",
    flow_queue_pressure_observed: "queue pressure",
    flow_health_degraded: "flow degraded",
    bulk_window_reduced_to_protect_interactive: "bulk reduced",
    rebuild_request_applied: "planner applied",
    rebuild_request_recorded: "rebuild recorded",
    rebuild_request_recorded_node_pending: "node pending",
    rebuild_request_no_alternate: "no alternate",
    rebuild_request_deferred_by_policy: "deferred by policy",
    rebuild_request_rejected: "rebuild rejected",
    rebuild_request_expired: "rebuild expired",
    route_rebuild_no_safe_recovery: "no safe recovery",
    access_decision: "access decision",
    access_no_safe_recovery: "access no-safe",
    access_recovery_selected: "access recovery",
    access_rebuild_applied: "access applied",
    access_replacement_selected: "access replacement",
    inspect_access_no_safe_recovery_route_pool_and_signed_policy: "inspect no-safe route pool",
    watch_recovery_route_quality_and_confirm_post_recovery_traffic: "watch recovery traffic",
    confirm_applied_rebuild_runtime_traffic_stays_on_replacement: "confirm applied traffic",
    watch_replacement_route_quality_until_applied_or_recovered: "watch replacement",
    pending_degraded_fallback: "pending fallback",
    service_channel_feedback_no_alternate: "no safe route",
    service_channel_feedback_replacement: "replacement",
    service_channel_feedback_exit_pool_replacement: "exit replacement",
    service_channel_feedback_entry_pool_replacement: "entry replacement",
    service_channel_feedback_entry_exit_pool_replacement: "pool replacement",
    service_channel_remediation_command: "remediation",
    service_channel_feedback_rebuild_requested: "rebuild requested",
    remediation_rebuild_applied_to_alternate: "planner selected alternate",
    no_unfenced_alternate_route: "no safe alternate",
    active_lease_not_found_for_rebuild_resolution: "lease missing",
    remediation_command_ttl_expired: "command expired",
    durable_rebuild_route_request_recorded: "rebuild recorded",
    durable_rebuild_route_request_rejected: "request rejected",
    durable_rebuild_route_request_applied: "request applied",
    durable_rebuild_route_no_alternate: "no alternate",
    durable_rebuild_route_deferred_by_policy: "deferred by policy",
    durable_rebuild_route_expired: "request expired",
    isolated: "изолирован",
    offline: "нет связи",
    one_way: "односторонняя",
    outdated: "обновить",
    pending: "ожидает",
    platform_managed: "платформенный",
    promoted: "promoted",
    rejected: "отклонено",
    ready: "готово",
    revoked: "отозвано",
    running: "работает",
    customer_managed: "клиентский",
    no_policy: "нет политики",
    not_configured: "не задано",
    missing: "нет отчета",
    service_channel_recovery_demoted: "demoted",
    service_channel_recovery_demoted_degraded: "degraded",
    service_channel_recovery_demoted_degraded_fallback: "fallback",
    service_channel_recovery_demoted_failure: "failure",
    service_channel_recovery_demoted_fenced: "fenced",
    service_channel_recovery_demoted_rebuild: "rebuild",
    service_channel_recovery_demoted_slow: "slow",
    service_channel_feedback_provenance_missing: "provenance missing",
    service_channel_feedback_stale: "stale feedback",
    service_channel_feedback_stale_generation: "stale generation",
    service_channel_feedback_stale_policy: "stale policy",
    service_channel_feedback_stale_policy_and_generation: "stale policy+generation",
    schema_ready: "schema ready",
    schema_migration_required: "schema migration required",
    snapshots_warmed: "snapshots warmed",
    missing_snapshots_warmed_stale_deferred: "missing warmed, stale deferred",
    snapshot_warmup_partial: "warmup partial",
    stopped: "остановлено",
    stale: "устарело",
    unknown: "неизвестно",
  };
  return labels[value] || value;
}
