Andrey Epifancev 8897152378 docs(openspec): архив рулингов агента bridge-core (спека — в jira-hub)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:49:05 +04:00

7.1 KiB
Raw Permalink Blame History

bridge-core (агент) — решения

Спека изменения лежит в репозитории jira-hub: jira-hub/openspec/changes/bridge-core/ (specs/agent, specs/commands, specs/hub-api, design.md). Здесь — только решения, принятые при реализации агента без обсуждения с человеком.

Decisions made without discussion

# Дата Решение Обоснование Цена ошибки
1 2026-10-11 tests/__init__.py добавляет каталог tests/ в sys.path (R-1) Тесты из плана импортируют _common/fake_jira по простому имени, при discover -s tests -t . иначе ImportError Мелкая: переписать импорты в тестах на относительные
2 2026-10-11 Потолок на Retry-After не вводим (R-2) Спека: «ждать Retry-After»; потолок тихо нарушает требование сервера Агент может уснуть надолго при аномальном заголовке; лечится потолком позже
3 2026-10-11 Журнал: не лечим права существующего файла и не блокируем prune/append flock'ом; запрет prune при работающем агенте — в README (R-3) Журнал создаётся этим же кодом (0600); prune — ручная команда раз в месяц Редкая потеря записи журнала при гонке prune/run; лечится flock
4 2026-10-11 Minor-замечания ревью Task 3 (T3.1, T3.3–T3.6, T3.8: пагинация поиска дубля, флаги existed/created, режим epic_link, префикс маркера, общий except в run, тесты) чиним одной финальной волной, а не по месту (R-4) Не блокируют Task 4–5; одна волна дешевле Task 4–5 унаследуют общий run; ошибки будут чиниться после
5 2026-10-11 Неизвестный link_type берётся как сырое имя типа Jira (fallback), без failed (R-5) Так же делает хаб в check_confirmed; допускает ручной ввод имён Jira Опечатка в типе даст HTTP-ошибку Jira вместо понятной ошибки агента
6 2026-10-11 Спринт в refresh берётся из Agile API по активным/будущим спринтам доски, а не из поля search; закрытые спринты дают sprint = null (R-6) В настройках хаба нет id поля спринта (field_ids его не содержит); план Task 5 выбрал Agile Исторические имена спринтов затрутся при полном refresh; лечится полем спринта в настройках
7 2026-10-11 Бисекция чанка key in (...) при 400 принята без лимита вызовов (до ~2·m·log2(n)); если не найден ни один ключ — ошибка, а не missing (R-7) Иначе refresh с удалённой задачей падает целиком; лимит вызовов усложняет без выгоды при редких удалениях При массовом удалении задач — всплеск запросов и риск 429 (агент их переживает)
8 2026-10-11 Общий except Exception стоит в Runner.execute (не в Executor.run); minor-находки T3.x/T5.x/T6.x чиним одной финальной волной, включая ложный failed для ensure_issue при ConnectionError из Jira (R-8) Исключение вне HttpError/ConnectionError не должно ронять цикл и вызывать зацикленное восстановление; одна волна дешевле Ложный failed у ensure_issue оставит временный ключ неразрешённым, а задача в Jira уже создана
9 2026-10-12 В журнал пишется запись claimed сразу после claim, до паузы; unfinished_started, recover, prune считают её открывающей; started по-прежнему после паузы (R-9) Иначе остановка агента в паузе/claim оставляет команду claimed в хабе навсегда (хаб не переиздаёт), а лечение cancel+retry не восстанавливает зависимые команды пакета Формат журнала шире, чем в спеке (лишний kind); старые журналы совместимы
10 2026-10-12 Runner.execute повторяет команду до 3 раз через проверку при ConnectionError/HTTP 5xx, не записывая finished; затем failed «результат неизвестен, повтор безопасен» (R-10) Неоднозначный исход записи в Jira (обрыв после POST) нельзя отдавать как failed: для ensure_issue хаб пропустит зависимые команды; все команды идемпотентны Лишние задержки при недоступной Jira
11 2026-10-12 Запрошенное, но не настроенное поле (epic_key, planned_start/end) даёт failed, а не молчаливый done (R-11) Ложный успех хаб запишет в зеркало как выполненный Команды падают, пока хаб не настроен
12 2026-10-12 agent_version добавляется в отчёт и в /agent/state (R-12) Спека: версия «в каждом отчёте»; хаб лишние поля игнорирует Нет
13 2026-10-12 F-1 (повтор по R-10 не ждёт 30 с, если Jira недоступна с первого вызова и last_call_at старый) сначала отложен контроллером (вторая волна фиксов не предусмотрена), затем исправлен по команде владельца: ожидание перед повтором — фиксированное max(pause, 30) от момента отказа (Runner.wait_seconds), не от последнего успешного вызова Jira Обрыв соединения не обновляет last_call_at, поэтому пауза «от последнего вызова» при старом значении была нулевой и три повтора шли подряд Повтор ждёт полные 30 с даже если с последнего вызова Jira прошло больше; лишнее ожидание не дольше 30 с на попытку