## MODIFIED Requirements ### Requirement: Маршруты агента Хаб SHALL предоставлять агенту следующие маршруты (все под агентским токеном): - `POST /agent/claim` `{agent_version, settings_version, last_jira_call_at, jira_user?, symmetric_link_types?}` — долгий запрос до 30 с; ответ `{command: {id, type, params, pause_seconds}, settings_version}` или `{command: null, settings_version}`; обновляет `agent_status` (непустые `jira_user` и `symmetric_link_types` записываются, отсутствующие не стирают прежние значения). Если есть команда в `claimed`, `claim` SHALL выдать её снова (повторная выдача, см. `commands`), а не следующую из очереди. - `GET /agent/settings` — настройки для агента (без токенов). - `GET /agent/commands/{id}` — команда по id (для восстановления из журнала), включая `pause_seconds`. - `POST /agent/commands/{id}/result` `{status, result, error, jira_calls, rate_limited}` — идемпотентно: повторный отчёт по команде в терминальном статусе отвечает 200 без изменений, кроме позднего отчёта `done` с `result.key` по отменённой `ensure_issue` (результат записывается, статус остаётся `cancelled`, заметка `new:N` переносится на ключ). Отчёт по команде в `queued` SHALL отвергаться 409 «команда не выдана». - `POST /agent/state` `{command_id, issues: [...], links: [...], neighbor_keys: [...], page, last_page}` — загрузка состояния пачками; `neighbor_keys` — ключи вне базовой JQL, дочитанные по связям; хаб обновляет зеркало и `sync_run`. - `GET /agent/known-keys` — ключи зеркала (для определения соседей). #### Scenario: Выдача с подстановкой ключа - **WHEN** следующая команда ссылается на `new:60`, а `ensure_issue` для `new:60` завершилась с `AURORA-1590` - **THEN** `claim` отдаёт команду с `AURORA-1590` в параметрах #### Scenario: Повторный отчёт - **WHEN** агент дважды прислал `result` для команды 15 - **THEN** второй ответ 200, статус и результат не изменились #### Scenario: Отчёт по невыданной команде - **WHEN** `POST /agent/commands/16/result` с `status = done`, команда 16 в `queued` - **THEN** 409, команда осталась `queued` #### Scenario: Факты агента в claim - **WHEN** агент v3 прислал `claim` с `jira_user = "bridge-user"` и `symmetric_link_types = ["ASUPR_Связанные"]`, затем агент v2 прислал `claim` без этих полей - **THEN** `agent_status.jira_user` и `symmetric_link_types` сохранили значения от первого `claim` ### Requirement: Маршруты интерфейсов Хаб SHALL предоставлять интерфейсам (MCP, позже просмотрщик) следующие маршруты под клиентским токеном: - `GET /issues` с фильтрами `sprint`, `assignee`, `work_kind`, `fact_status`, `status`, `label`, `epic`, `neighbor`, `q` (подстрока темы), `limit`/`offset` — компактные карточки (ключ, тема, статус, приоритет, срок, исполнитель, спринт, эпик, заметки кратко). - `GET /issues/{key}` — задача целиком: поля, связи в обе стороны, заметки, последние 10 команд по ней. - `PUT /issues/{key}/note` — заметки (частичное обновление, `updated_by` из тела). - `POST /batches` `{title, author, commands: [...]}` → `{id, estimate_seconds}`; 422 при неизвестном типе, неверных параметрах, временном ключе без `ensure_issue`, двух и более `ensure_issue` с одинаковой `summary` (сравнение после обрезки пробелов по краям; в ответе перечислены повторяющиеся темы). - `GET /batches?limit=`, `GET /batches/{id}` (с командами), `POST /batches/{id}/cancel`. - `POST /commands/{id}/retry` — новая команда с теми же параметрами в новом пакете «Повтор команды N». - `POST /commands/{id}/cancel` — только для `queued`; для `claimed` — 409, если не передан `force: true`. - `POST /refresh` `{keys | jql | full: true}` → пакет из одного `refresh`. - `GET /agent`, `GET /sync-runs?limit=`, `GET /settings`, `PUT /settings` (частично; поднимает `settings_version`). #### Scenario: Фильтр по спринту - **WHEN** `GET /issues?sprint=Спринт 2` - **THEN** только задачи с таким `sprint`, отсортированы по сроку, затем по ключу #### Scenario: Отмена взятой команды - **WHEN** `POST /commands/15/cancel` без `force`, команда `claimed` - **THEN** 409 с `claimed_at`; с `force: true` — `cancelled`, следующий отчёт агента по ней принимается, статус не меняется #### Scenario: Поздний отчёт по отменённому созданию - **WHEN** `ensure_issue {temp_key: new:7, …}` отменена с `force: true`, затем агент прислал `done` с `result.key = AURORA-1620` - **THEN** команда `cancelled`, в `result` — `AURORA-1620`; заметка `new:7` перенесена на `AURORA-1620` #### Scenario: Дубль темы в пакете - **WHEN** `POST /batches` с двумя `ensure_issue`, у обеих `summary = "Шахматка: комментарии"` - **THEN** 422 с темой «Шахматка: комментарии», пакет не создан ### Requirement: Автообновление зеркала Если `auto_refresh_minutes > 0`, агент на связи и очередь пуста дольше этого интервала, хаб SHALL поставить пакет «Автообновление» из `refresh {jql: base_jql}`. Очередь не пуста, если есть команды в `queued` или `claimed`. #### Scenario: Очередь занята - **WHEN** интервал прошёл, но в очереди есть `queued` команды - **THEN** автообновление не ставится до опустошения очереди #### Scenario: Есть выданная команда без отчёта - **WHEN** интервал прошёл, `queued` нет, одна команда в `claimed` - **THEN** автообновление не ставится; команда довыдаётся при следующем `claim`