docs(agent): журнал claimed, повторы при обрыве связи, остановка в паузе, версия, 3.9
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Typ5sXWNMFirr2va2uL8o
This commit is contained in:
parent
2e6f47a514
commit
22018318d1
@ -1,7 +1,7 @@
|
||||
# Архитектура
|
||||
|
||||
Агент — один файл `src/agent.py` (Python 3.9, только стандартная библиотека). Тесты в `tests/` работают на фейках
|
||||
Jira и хаба. Спека: `../jira-hub/openspec/changes/bridge-core/`, план: `../jira-hub/docs/superpowers/plans/2026-10-11-bridge-core-hub.md`.
|
||||
Jira и хаба. Спека: `../jira-hub/openspec/changes/bridge-core/`, план агента: `docs/superpowers/plans/2026-10-11-bridge-core-agent.md` (план хаба: `../jira-hub/docs/superpowers/plans/2026-10-11-bridge-core-hub.md`).
|
||||
|
||||
## Разделы файла `src/agent.py`
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
## Стек и ограничения
|
||||
- Python 3.9.6 (как на виртуалке), только стандартная библиотека, без venv и зависимостей.
|
||||
- Запрещено: синтаксис 3.10+ и сторонние импорты.
|
||||
`tests/test_py39.py` ловит синтаксис 3.10+ (match и т. п.) и сторонние импорты; `X | Y` в аннотациях и API новее 3.9 подтверждает только прогон на /usr/bin/python3 3.9.6.
|
||||
`tests/test_py39.py` ловит синтаксис 3.10+ (match и т. п.) и сторонние импорты; `X | Y` — синтаксис 3.10: в 3.9 аннотации функций вычисляются при импорте, и прогон тестов на /usr/bin/python3 3.9.6 это ловит; аннотации локальных переменных не вычисляются, их и API новее 3.9 проверяет только ревью.
|
||||
- `agent.json` содержит учётные данные Jira — не коммитить, не отправлять в хаб, не выносить с виртуалки.
|
||||
Шаблон без секретов — `src/agent.example.json`.
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
## Первая подсистема
|
||||
Исполнитель команд и цикл агента (спека `agent/spec.md`, `commands/spec.md`) — реализованы целиком: все типы команд,
|
||||
журнал, восстановление после перезапуска, CLI `run|check|prune`.
|
||||
План и спека живут в `jira-hub`: `openspec/changes/bridge-core/` и `docs/superpowers/plans/2026-10-11-bridge-core-hub.md`.
|
||||
План и спека живут в `jira-hub`: `openspec/changes/bridge-core/` и `docs/superpowers/plans/2026-10-11-bridge-core-hub.md`; план агента лежит здесь: `docs/superpowers/plans/2026-10-11-bridge-core-agent.md`.
|
||||
|
||||
## OpenSpec и superpowers
|
||||
- Вход в любую задачу — superpowers:brainstorming. Skills openspec-propose и openspec-explore сами по себе не запускать.
|
||||
|
||||
31
README.md
31
README.md
@ -56,8 +56,8 @@ nohup python3 -u agent.py > agent.log 2>&1 &
|
||||
```
|
||||
|
||||
Остановка: Ctrl-C или `kill <pid>`. Первый сигнал — агент доделывает текущую команду, отправляет отчёт и выходит.
|
||||
Повторный сигнал — немедленный выход (код 130). Команда, которая не успела записаться в журнал `started`, при этом
|
||||
остаётся `claimed` в хабе (см. ограничение 2).
|
||||
Повторный сигнал — немедленный выход (код 130). Остановка во время паузы перед командой безопасна: команда уже
|
||||
записана в журнал как `claimed`, при следующем запуске агент запрашивает её у хаба и выполняет через проверку (без паузы).
|
||||
|
||||
## Автозапуск через launchd (опционально)
|
||||
|
||||
@ -95,11 +95,12 @@ launchctl unload ~/Library/LaunchAgents/ru.aepif.jira-agent.plist
|
||||
|
||||
## Журнал
|
||||
|
||||
`journal.jsonl` лежит рядом с `agent.py`. Это только дозапись: на каждую команду пишутся `started` (после паузы,
|
||||
перед обращением к Jira), `finished` (результат и счётчики вызовов) и `acked` (хаб подтвердил приём отчёта).
|
||||
По журналу агент после перезапуска досылает неподтверждённые отчёты и находит команды, начатые, но не завершённые.
|
||||
`journal.jsonl` лежит рядом с `agent.py`. Это только дозапись: на каждую команду пишутся `claimed` (сразу после получения
|
||||
из хаба, до паузы), `started` (после паузы, перед обращением к Jira), `finished` (результат и счётчики вызовов) и `acked` (хаб подтвердил приём отчёта).
|
||||
По журналу агент после перезапуска досылает неподтверждённые отчёты и находит команды, полученные или начатые, но не завершённые.
|
||||
|
||||
Журнал содержит параметры команд, то есть тексты задач и комментариев. Не выносить его с виртуалки.
|
||||
В журнале нет параметров команд (текстов задач и комментариев): только id команды, статус, `result`, `error` и счётчики
|
||||
вызовов. Но `result` и `error` могут содержать ключи задач и фрагменты ответов Jira, поэтому журнал лучше не выносить с виртуалки.
|
||||
|
||||
Очистка подтверждённых записей старше 30 дней:
|
||||
|
||||
@ -131,8 +132,13 @@ python3 agent.py prune
|
||||
- **Отчёт до подтверждения.** Отчёт повторяется каждые 10 с, пока хаб не подтвердит. Ответы 404/409/422 хаб
|
||||
выдаёт, когда команда уже отменена или удалена: агент считает её закрытой и не зацикливается.
|
||||
- **429 и 503.** Агент ждёт `Retry-After` из ответа Jira и повторяет запрос: до 5 запросов, то есть не более 4 ожиданий;
|
||||
на пятой неудаче — ошибка команды. Если заголовка нет или он в формате HTTP-date (не разбирается), ждёт 60 с, умноженные на номер попытки. Число ожиданий идёт в `rate_limited` отчёта.
|
||||
- **Версия.** Константа `AGENT_VERSION` в `agent.py` (сейчас 1) отправляется в каждом `claim`.
|
||||
на пятой неудаче — ошибка команды. Если заголовка нет или он в формате HTTP-date (не разбирается), ждёт 60 с, умноженные на номер попытки. Число ответов 429/503 идёт в `rate_limited` отчёта.
|
||||
- **Обрыв связи с Jira (R-10).** Если Jira оборвала соединение или ответила 5xx, исход записи неизвестен: агент не пишет
|
||||
`finished`, ждёт не меньше 30 с и повторяет команду через проверку («проверь, потом сделай») до 3 раз. Счётчики
|
||||
суммируются. После исчерпания — `failed` «результат неизвестен (обрыв связи с Jira), повтор безопасен». При остановке
|
||||
по сигналу команду подхватит восстановление.
|
||||
- **Версия.** Константа `AGENT_VERSION` в `agent.py` (сейчас 1) отправляется в каждом `claim`, в каждом отчёте
|
||||
(`agent_version`) и в `/agent/state`.
|
||||
Если хаб назначил `min_agent_version` выше, он пишет в `agent_status.warning`: «обновите агента»; команды
|
||||
при этом выдаются по-прежнему.
|
||||
|
||||
@ -157,9 +163,10 @@ python3 agent.py prune
|
||||
|
||||
1. **`prune` не запускать при работающем агенте.** Блокировки нет. Запись, добавленная агентом во время `prune`,
|
||||
может пропасть при перезаписи файла. Сначала остановить агента.
|
||||
2. **Ctrl-C во время паузы перед командой.** Команда остаётся `claimed` в хабе, в журнале о ней ничего нет.
|
||||
Хаб сам её не переиздаёт. Лечение: в хабе отменить команду с force и повторить:
|
||||
`POST /commands/{id}/cancel` с телом `{"force": true}`, затем `POST /commands/{id}/retry`.
|
||||
2. **Остановка во время паузы или между claim и выполнением (R-9).** Команда остаётся `claimed` в хабе, но в журнале
|
||||
есть запись `claimed`: при перезапуске агент запрашивает её у хаба и выполняет без паузы. Отмена с force и повтор
|
||||
больше не нужны. Если журнал потерян, команду придётся отменить с force (`POST /commands/{id}/cancel`,
|
||||
`{"force": true}`) и повторить (`POST /commands/{id}/retry`).
|
||||
3. **HTTPS хаба с корпоративным CA не поддержан.** `HubClient` работает без `ca_bundle` и `verify_ssl`: `hub_url`
|
||||
должен быть `http://`. Для Jira `verify_ssl` и `ca_bundle` работают.
|
||||
4. **Спринт в `refresh` — только активные и будущие спринты доски.** Поле `sprint` берётся из Agile API по
|
||||
@ -171,4 +178,4 @@ python3 agent.py prune
|
||||
записи. Наблюдать на реальной Jira.
|
||||
7. **429/503 без потолка.** Агент ждёт `Retry-After` в секундах сколько бы он ни был (без верхней границы): не более 4 ожиданий,
|
||||
на пятой неудаче — ошибка. Длинный `Retry-After` держит очередь. Формат HTTP-date в `Retry-After` не разбирается:
|
||||
тогда ждётся 60 с × номер попытки.
|
||||
тогда ждётся 60 с × номер попытки. Нецелый `Retry-After` (например, `1.5`) тоже не разбирается: те же 60 с × попытка.
|
||||
|
||||
@ -5,8 +5,8 @@ import unittest
|
||||
from _common import SRC
|
||||
|
||||
# Ограничение проверки: ast.parse(feature_version=(3, 9)) ловит синтаксис 3.10+ (match и т. п.) и сторонние
|
||||
# импорты; API и конструкции, новые в 3.9 (например, `X | Y` в аннотациях), не проверяет. Их подтверждает только
|
||||
# прогон на /usr/bin/python3 (3.9.6).
|
||||
# импорты; API и конструкции новее 3.9 (например, `X | Y` — синтаксис 3.10: аннотации функций
|
||||
# вычисляются при импорте и их ловит прогон на /usr/bin/python3 3.9.6, аннотации локальных переменных не вычисляются), не проверяет.
|
||||
|
||||
|
||||
class Py39Test(unittest.TestCase):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user