server-monitor-manager/agents/hermes/notes/salvage-2026-08-18/hermes-desktop-attachments/desktop-attachments/c5-nats-events.md
Ochenstarik 23eb3f5233 chore(agents): разбор рабочих папок с диска на 2026-08-18
Задания, отчёты и патчи, лежавшие в C:\Users\Ochenstarik\projects и в
домашней папке, перенесены в agents/. Разложено по агентам там, где имя
файла позволяло определить автора; остальное — в _salvage-2026-08-18/
и разбирается вручную.

Патчи в notes/salvage-2026-08-18/ — незакоммиченная работа из брошенных
рабочих копий: она существовала только на диске.

Тяжёлое (релизные архивы, инсталляторы, наборы данных) в репозиторий не
попало: оно лежит рядом, в Agent_projects/_archive и Agent_projects/_data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 14:19:54 +07:00

7 KiB
Raw Blame History

Правила работы — AGENTS.md в корне репозитория.

Репозиторий: https://github.com/ochenstarik-ui/kagent, база — свежий main Ветка: новая от origin/main, wt/c5-nats-events

Зависимостей нет. Задача трогает Python-сервисы и конфигурацию, с c1 и c4 по файлам не пересекается и может идти параллельно.

Проблема

services/nats/src/events.py — клиент JetStream: подключение, публикация доменного события, подписка durable-консьюмером, запрос-ответ. Модуль не импортируется ни одним сервисом и попал в docs/known-drift.json.

Кроме того, он не заработал бы и при подключении: subscribe() вызывает pull_subscribe с именем потока, который нигде не создаётся. Вызова add_stream в модуле нет. Первая же подписка упадёт на отсутствующем потоке.

Каталог services/nats при этом не является сервисом: в нём нет ни requirements.txt, ни Dockerfile, ни записи в docker-compose.yml. Это библиотека, лежащая в каталоге сервисов.

Что сделать

1. Починить клиент

  • создавать поток идемпотентно перед публикацией и подпиской: если поток отсутствует — создать с предметами по префиксу, если существует — использовать существующий;
  • имя потока и набор предметов вычислять по одному правилу, а не двумя разными местами в коде;
  • подтверждение и отрицательное подтверждение сообщения уже есть — сохранить;
  • при недоступности брокера соединение повторяется с ограничением, а не бесконечно.

2. Переместить как библиотеку

services/nats — не сервис. Перенести модуль туда, где он является общей библиотекой Python-сервисов, например packages/py-events либо services/_shared, и подключить как зависимость к использующим сервисам. Выбранный вариант обосновать одной строкой в отчёте: структура каталогов описана в ТЗ, раздел 7, и не должна расходиться с фактом.

3. Подключить к одному сервису

Достаточно одного настоящего потребителя, чтобы возможность считалась подключённой. Выбрать services/pipeline: он уже выполняет шаги и знает об их результате.

Публиковать доменные события жизненного цикла шага с именами из ТЗ, раздел 10: task.started, agent.started, agent.completed, artifact.created, task.failed. Событие содержит идентификатор, тип, версию схемы, время, идентификаторы проекта и задачи, корреляционный идентификатор — как требует ADR-0002.

  • адрес брокера из NATS_URL, значение по умолчанию и запись в .env.example;
  • nats-py добавить в requirements.txt сервиса; версия уже используется в services/orchestrator, взять ту же;
  • в docker-compose.yml добавить зависимость pipeline от nats по состоянию работоспособности;
  • недоступность брокера не должна ронять пайплайн. Публикация — побочный эффект, а не условие выполнения шага. При недоступности брокера событие теряется с записью в лог, шаг продолжается. Это осознанный выбор на текущем этапе: гарантированная доставка требует outbox из ADR-0010, которого ещё нет. Отметить это в отчёте.

4. Доказательство

Модульные тесты на заглушке брокера: событие сериализуется с обязательными полями, имя потока вычисляется одинаково для публикации и подписки, недоступность брокера не прерывает работу.

Интеграционный тест с настоящим брокером в непрерывной интеграции: сервисный контейнер nats:2.11-alpine с включённым JetStream, публикация и получение события подписчиком, повторное создание потока не ломает работу.

Добавить возможность в docs/capabilities.json со ссылкой на имя нового job как на доказательство и снять запись из docs/known-drift.json.

Чего не делать

  • публикация событий из Control Plane на TypeScript — отдельная задача, там понадобится своя реализация клиента;
  • outbox и гарантированная доставка — ADR-0010, отдельный этап;
  • подключение оркестратора: он вообще отсутствует в docker-compose.yml, это отдельная проблема.

Критерий приёмки

ruff check services scripts
python -m pytest tests/unit -q
python scripts/drift_check.py
  • модуль импортируется настоящим сервисом, а не только тестом;
  • drift_check.py не сообщает про модуль событий; в known-drift.json осталось две записи либо одна, если c3 уже принята;
  • job с брокером в CI зелёный, интеграционный тест публикует и получает событие;
  • roadmap_status.py показывает возможность событийного потока подтверждённой доказательством — вывод до и после в отчёте;
  • ссылка на зелёный прогон приложена.