web/index.html:
- мобильное меню после раскрытия не держит анимационную высоту Bootstrap:
нижние пункты (Обзор/История/API-ключи) уезжали под .sidebar-footer и не нажимались
- на десктопе рельс #nav скроллится сам, футер не сжимается; активный пункт
доскролливается в область видимости
- failure() принимает заголовок: ошибка валидации источника больше не подписана
«Не удалось загрузить данные»
tools/reachability.py: общая проверка «элемент виден, но перекрыт другим» —
hit-test по центру с scrollIntoView, пропуск скрытых узлов и закрытых <details>.
tools/panel_scenarios.py: 11 сквозных сценариев реального пользователя —
deep-link фильтр, экспорт CSV/JSON по байтам, читалка и ссылка на оригинал,
дайджест, поиск источников, Telegram-сессия, форма источника (отказ без записи
в реестр), клавиатурный flow (/ ? Esc 1-9) со сверкой строк ленты с API,
мобильное меню, адаптивность 320-1920 без горизонтального переполнения, зум.
tools/ui_smoke.py: reachability-проверки десктопного рельса, контролов и мобильного меню.
tests: +3 регрессии на CSS/заголовки ошибок; pytest 93 passed, smoke exit 0,
сценарии exit 0, page_errors пуст.
- omni/vault.py: пул ключей парсеров (env-first, data/vault.json, ротация, cooldown 401/402/403=1ч, 429=10м), только маски в выводе
- tools/build_vault.py: сборка пула из MASTER_KEYS.csv и локальных дампов (значения не в git)
- tools/vault_check.py: живая проверка с маскированием
- searchers: firecrawl/tavily/exa/serper/jina/apify берут ключ из vault, если нет env
- omni radar: домены+каналы из radar_server.db -> реестр, --import-posts заливает посты каналов
- radar-источники помечены opt_in: общий обход не тормозят (869 против 3337 всего)
- omni/sources_cn.py + tools/wave_cn.py: 9 живых китайских источников (52pojie, nodeseek, kanxue, anquanke, 4hou, xz.aliyun, ithome, cnbeta, v2ex)
- net.get(proxy=...): принудительный прокси для CF-площадок
- /api/keys + строка ключей в панели
- tests/test_vault_radar.py: 7 тестов, всего 29 passed