Список проблем, выявленных в ходе аудита 2026-05-16. Решаем по одной, сверху вниз. После исправления каждого пункта — отмечать галочкой и обновлять этот файл.
navi/core/agent.pySeverity: Critical Файл: navi/core/agent.py (1349 строк) Проблема: Класс Agent одновременно управляет тремя режимами (run, run_stream, run_ephemeral), компрессией контекста (3 уровня fallback), планированием, анти-столлингом, адаптивным репланингом, подсчётом токенов, stall-детекцией, обработкой изображений и под-агентами. Почему блокер: Любое изменение в одной подсистеме требует правки одного файла. Параллельная работа нескольких разработчиков невозможна без конфликтов. Unit-тесты вынуждены инициализировать весь агент даже для проверки одного метода. Направление: Выделить PlanningOrchestrator, ContextCompressor, SubAgentRunner, AntiStallMonitor в отдельные сервисы. Agent должен остаться только координатором.
navi/api/deps.pySeverity: Critical Файл: navi/api/deps.py (строки 46–170) Проблема: _memory_store, _registries, _mcp_manager, _scheduler, _kv_store, _session_store, _workers — создаются при первом обращении и живут до перезапуска процесса. Нет явного lifecycle management (shutdown pools, close connections). Почему блокер: Невозможно подменить реализацию в тестах без monkeypatch на уровне модуля. Горизонтальное масштабирование (несколько процессов) невозможно, потому что состояние привязано к процессу. Направление: Заменить на явный AppContainer или asynccontextmanager-зависимости FastAPI с yield.
Severity: High Файл: navi/api/websocket.py (443 строки) Проблема: WebSocket handler занимается: heartbeat, replay/reconnect, оркестрацией запуска агента, аутентификацией, валидацией изображений, управлением глобальным состоянием сессий (_runs, _busy_sessions, _session_sockets), созданием Agent напрямую. Почему блокер: При добавлении нового транспорта (SSE, gRPC) придётся дублировать всю оркестрацию. Бизнес-логика просочилась в слой сериализации. Направление: Ввести AgentSessionOrchestrator между WebSocket и Agent. WebSocket должен заниматься только сериализацией/десериализацией.
settingsSeverity: High Файл: navi/config.py Проблема: settings = Settings() доступен из любого модуля. Поля не readonly. extra="ignore" означает, что опечатки в .env игнорируются без предупреждения. Почему блокер: Любой модуль может изменить settings.ollama_num_ctx во время выполнения, что приведёт к race condition при параллельных запросах. Направление: Сделать Settings immutable (frozen=True). Передавать экземпляр в конструкторы вместо глобального импорта.
Severity: High Файлы: navi/memory/store.py, navi/store/__init__.py, navi/core/pg_session_store.py Проблема: Каждый стор создаёт свой asyncpg.create_pool(self._dsn) с одинаковым DSN. У каждого своя asyncio.Lock для lazy-инициализации. Почему блокер: При росте нагрузки количество соединений к PostgreSQL утраивается. Нет единого менеджера пула. Направление: Вынести asyncpg.Pool в отдельный Database сервис. Передавать pool конструктором в сторы.
registry.pySeverity: High Файл: navi/core/registry.py (строки 164–254) Проблема: build_default_registries() создаёт все реестры, а затем вручную прописывает кросс-ссылки (list_tool._profile_registry = profiles, spawn_tool._backend_registry = backends). Почему блокер: Циклические зависимости разрешаются через "патч после создания". Добавление нового инструмента требует редактирования фабрики. Направление: Внедрить двухфазную инициализацию: create() → wire().
tool_executor.pySeverity: Medium Файл: navi/core/tool_executor.py (строки 60–187) Проблема: Три метода (_run_single_tool, _execute_tool_calls, _execute_tool_calls_streaming) содержат идентичную логику: resolve → middleware → execute → image extraction → build message. Почему блокер: Любой баг в middleware или image-обработке нужно править в трёх местах. Направление: Единый метод _execute_one(tc, tool_map) -> (event, msg, image_msg), используемый всеми тремя путями.
Severity: Medium Файл: navi/tools/_internal/base.py (строки 19–42) Проблема: 7 глобальных ContextVar (current_session_id, current_event_sink, current_stop_event, current_model, current_user_id, current_user_role, current_user_info). Инструменты читают их неявно. Почему блокер: Инструмент нельзя вызвать вне контекста агента (из CLI, фоновой задачи, теста) без установки всех ContextVar. Направление: Передавать контекст выполнения явным параметром в execute(). ContextVar оставить как optional fallback.
Severity: Medium Файл: navi/api/websocket.py (строки 80–86, 403–406) Проблема: _runs, _busy_sessions, _session_sockets — глобальные mutable dict без явной синхронизации. При горизонтальном масштабировании (несколько процессов) состояние запуска не реплицируется. Почему блокер: Сессия может быть запущена на инстансе A, а WebSocket подключён к инстансу B. Направление: Вынести состояние запуска в SessionStore (PostgreSQL) или Redis. _session_sockets заменить на pub/sub.
Severity: Medium Файлы: navi/mcp/manager.py, navi/mcp/client.py Проблема: resolve_group() и get_instructions() вызывают load_mcp_servers() при каждом обращении. Нет кэширования. McpClient делает reconnect без backoff. Почему блокер: При частых запросах — лишний дисковый I/O. Если MCP-сервер упал, каждый запрос порождает две попытки подключения без задержки. Направление: Закэшировать конфигурацию в McpManager. Добавить exponential backoff на reconnect в McpClient.
agent.py — Step 1 complete: ContextCompressor extracteddeps.pysettingstool_executor.py