# NATS / YouTrack agents

Наблюдаемый событийный контур: постановка задания, настоящая очередь, обработка, результат и повтор. Внешний трекер и агент заменены безопасными моками.

Статус: passed

Версия: `2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c`. История репозитория: с 22 мая 2026. Публичный безопасный контур: 7 сентября 2026.

## Задача

Долгая агентная обработка не должна терять задание после разрыва соединения или повторно применять уже готовый результат.

## Аудитория

Разработчики автоматизации трекеров и событийных worker-систем.

## Личный вклад

- Интеграционная схема webhook → JetStream → worker → результат.

- Durable consumer, ACK/NAK, повторная доставка и защита завершённого задания.

- Безопасный публичный runtime без Codex SDK, shell runner и MCP-доступа.

## Решения

- Используется исходный модуль jetstream.js и общий dryAnalysis, вынесенный без изменения алгоритма.

- Учебный отказ выполняет NAK; повтор доставляется реальным JetStream через 2,5 секунды.

- Worker проверяет completed, а gateway применяет результат один раз.

- SQLite WAL хранит сессионную историю; события добавляются атомарным SQL, чтобы параллельные обновления не терялись.

## Границы и ограничения

- YouTrack, MCP и агент — явные моки. Публичного запуска shell/Codex и отправки комментариев нет.

- Искусственная задержка 700 мс показывает этапы; это не измерение скорости настоящего агента.

- Два контейнера по 128 MiB. 20 заданий на сессию, 1000 всего; stream до 8 MiB / 1000 сообщений / одного часа.

## Что попробовать

- Выберите учебное задание и проследите timeline обработки.

- Повторите завершённое задание: появится duplicate_ignored без второй выдачи результата.

- Запустите прерывание до ACK и дождитесь повторной доставки.

- Откройте пример нехватки контекста, проверьте отдельную сессию и сброс.

## Проверки

- Три unit-теста: исходный dryAnalysis, ownership/TTL/quota и атомарная запись событий. Реальный restart worker подтверждён production QA.

- Real JetStream jobs/results; duplicate_ignored and exactly one result application

- Signed cookie; cross-session read/replay/reset isolation

- {"scenario": "Actual worker container restart with pending delivery", "restartAt": "2026-09-07T00:01:22.460Z", "jobId": "09a53fd9-c9b4-4aa7-9d54-8a0c58fc2972", "completedAt": "2026-09-07T00:01:26.504Z"}

- Arbitrary command fields rejected; no shell endpoint

- Подтверждённого GitHub CI для этого SHA нет; перечислены выполненные локальные проверки и сценарии опубликованной версии. Исторические CI-ссылки, если есть, отмечены отдельно.

## Результаты

- Сохранено 13 содержательных кадров фактического интерфейса.

- Дата, сценарий и версия указаны у каждого кадра.

- Максимум RAM контейнеров в коротком тесте: 59.63 MiB. Общие службы учитываются отдельно; магазин включает свою БД.

- Измерено 6 повторений сценария; медиана 1712.5 мс, максимум 2953 мс. Время включает браузер и HTTPS; методика и ограничения приложены.

## Запуск и эксплуатация

- Исходный контур предполагал YouTrack webhook, Codex worker, MCP и комментарий в трекере. Публичный образ не содержит этих исполняющих интеграций; схема демо показана отдельно.

- Сборка Dockerfile.portfolio выполняется вне VPS. Два контейнера разделяют SQLite volume и отдельную учётную запись NATS AGENTS. API доступен только через localhost:18405/Nginx.

- Readiness API проверяет NATS, worker — свежий heartbeat. Реальный docker restart worker выполнен в эксплуатационной проверке во время незавершённого задания: после старта оно завершилось, результат применился один раз. Публичной кнопки остановки процесса нет.

- Общие правила эксплуатации: готовые файлы и закреплённые образы собираются вне VPS; секреты не входят в артефакты. Общесерверный docker prune не применяется. Логи backend ограничены ротацией, изменения log options требуют пересоздания контейнера.

- Перед изменением пройти code-map от функции к экрану/API, модулю и данным. После изменения обновить карту и схемы, выполнить связанные сценарии, включая ошибку, повтор и сброс. Источник истины — конкретная версия кода, а не старая диаграмма.

- Откат проверен 2026-09-07T01:06:02.122021+00:00: 20260907-verified → 20260907 → 20260907-verified. После каждого переключения подтверждены HTTPS, readiness и SHA. Это проверка конфигурации и артефактов на одном проверенном SHA; обратная миграция БД не выполнялась.

## Стек и роль

- **Node.js 24**: HTTP gateway, безопасный worker и исходный dry-run formatter.
- **NATS JetStream**: Настоящие subjects jobs/results, durable consumers и ACK/NAK.
- **SQLite WAL**: Общая API/worker история, ownership и атомарные append.

## Code-map

|Функция|Экран / API|Модуль|Данные / проверка|
|---|---|---|---|
|Учебный webhook|POST api/jobs|portfolio-gateway, portfolio-store.create|фиксированный corpus, SQLite jobs; quota test|
|Очередь|схема / api/state|jetstream.openJetStream|NATS stream + consumers; production QA|
|Анализ|timeline|portfolio-worker, dry-analysis|исходный dry-run formatter; missing context test|
|Повтор|POST api/jobs/id/replay|worker completed guard|тот же ID, duplicate_ignored; production QA|
|Изоляция / сброс|GET state / DELETE jobs|portfolio-store.owned|owner SHA-256, TTL; isolation + expiry tests|

## Схемы

- Компоненты опубликованного демо — `diagrams/components.mmd`
- Основной сценарий — `diagrams/scenario.mmd`
- Размещение опубликованной версии — `diagrams/deployment.mmd`
- Состав данных и границы хранения — `diagrams/data.mmd`
- Исходный интеграционный контур — не развёрнут в демо — `diagrams/original.mmd`

## Индекс изображений

- 01-overview: Назначение очереди и границы реальных/моковых компонентов; 2026-09-07T00:01:17.068Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 02-empty: Создание задания и действующий heartbeat worker; 2026-09-07T00:01:17.443Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 03-queued: JetStream принял синтетический webhook; 2026-09-07T00:01:17.944Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 04-completed: Gateway получил результат по отдельному subject; 2026-09-07T00:01:20.378Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 05-analysis: Исходный dry-run formatter: явное отсутствие реального анализа кода; 2026-09-07T00:01:20.758Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 06-idempotency: Повтор доставлен, результат не применяется повторно; 2026-09-07T00:01:21.844Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 07-nak: NAK перед ACK: реальная отложенная повторная доставка; 2026-09-07T00:01:22.459Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 08-worker-recovered: После реального перезапуска worker то же задание завершилось; 2026-09-07T00:01:26.614Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 09-missing-context: Неполный webhook: явный запрос контекста; 2026-09-07T00:01:29.077Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 10-contract: Структура задания и цепочка событий; 2026-09-07T00:01:29.473Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 11-mobile-overview: Мобильное объяснение очереди и моков; 2026-09-07T00:01:29.821Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 12-mobile-timeline: Мобильная цепочка событий; 2026-09-07T00:01:30.160Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c
- 13-reset: Удаление своей истории без воздействия на другие сессии; 2026-09-07T00:01:30.534Z; SHA 2a7c7e8565054d4c09e7e5c60d7b8da81e275e3c

## Подробности runtime из репозитория

# NATS / YouTrack agents: публичное демо

Адрес https://agents.komaroff-dev.ru/. Подготовлено 7 сентября 2026 года.
Дата подготовки демо не заменяет дату разработки исходного проекта.

## Реальная и демонстрационная части

Исходный контур: YouTrack webhook → JetStream → Codex worker → MCP → комментарий YouTrack.
Публичный контур: фиксированный webhook → исходный модуль JetStream → безопасный worker
с исходным `dryAnalysis` → настоящий subject результата → gateway → сессионная история.
`dryAnalysis` вынесен без изменения алгоритма в общий модуль и используется обоими worker.
Публичный образ не содержит Codex SDK, shell runner, MCP-клиент или рабочий gateway.
Внешние YouTrack URL, заголовки, ключи и корпоративные данные не передаются в образ.

## Доставка и восстановление

NATS account AGENTS, stream PORTFOLIO_AGENTS, отдельные subjects jobs/results,
два durable consumer с explicit ACK. ACK wait 3 секунды, не более пяти доставок,
1000 сообщений / 8 MiB / один час. Worker обрабатывает одно сообщение за раз.
Встроенный сценарий возвращает NAK один раз, затем повторная доставка через 2,5 секунды
обрабатывается обычным путём. Это симуляция ошибки до ACK, а не остановка процесса.
Реальный перезапуск контейнера проверяется отдельно при эксплуатационной проверке.
Повтор завершённого задания записывает duplicate_ignored и не применяет результат снова.

Состояния хранятся в SQLite WAL на общем томе API/worker. Cookie подписана HMAC,
Secure/HttpOnly/SameSite=Lax. Все чтения, повторы и сброс фильтруются по хешу сессии.
20 заданий на сессию, 1000 всего; очистка по TTL один час каждые пять минут и при запросе.
Публичных управляющих методов остановки контейнера или запуска команды нет.

## Code-map

| Функция | Экран/API | Модуль | Данные / проверка |
|---|---|---|---|
| Учебный webhook | POST api/jobs | portfolio-gateway, portfolio-store.create | фиксированный corpus, SQLite jobs; quota test |
| Очередь | схема / api/state | jetstream.openJetStream | NATS stream + consumers; production QA |
| Анализ | timeline | portfolio-worker, dry-analysis | исходный dry-run formatter; missing context test |
| Повтор | POST api/jobs/id/replay | worker completed guard | тот же ID, duplicate_ignored; production QA |
| Изоляция / сброс | GET state / DELETE jobs | portfolio-store.owned | owner SHA-256, TTL; isolation + expiry tests |

Перед правкой пройти связи экран → API → consumer → результат → хранилище, после правки
обновить карту и схемы, проверить повторную доставку и изоляцию. Исходный CODE_MAP.md
описывает рабочую интеграцию; публичное демо имеет отдельную карту выше.

## Сборка / эксплуатация

Node24 base закреплён digest. `portfolio/package-lock.json` фиксирует минимальные
runtime-зависимости. Dockerfile.portfolio собирается вне VPS, запуск по image digest.
Два контейнера по 128 MiB / 0.4 CPU, logs 3×5 MB. API healthcheck проверяет NATS,
worker healthcheck — свежий heartbeat. Nginx проксирует localhost:18405, NATS снаружи закрыт.
Числа времени в интерфейсе — фактические timestamps событий, состояние очереди — consumer info.
Встроенная задержка 700 мс нужна для наблюдения этапов и не является бенчмарком агента.
