Дельты commands, hub-api, mcp, data-model, agent: issue_type bug с настройкой
issue_types.bug, хранилище файлов хаба (POST /files, GET /agent/files/{sha256}),
команда ensure_attachment, path в MCP batch_create, агент v11; заодно R-1
(#46) и M-1/M-2 из aep/jira-agent#30.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
7.8 KiB
Markdown
86 lines
7.8 KiB
Markdown
## MODIFIED Requirements
|
||
|
||
### Requirement: Чтение состояния
|
||
`refresh` SHALL выполняться запросом `search` (`jql`, `fields` = поля зеркала включая `issuelinks`, `comment` и спринт,
|
||
`maxResults = 100`, постранично) и отправляться хабу пачками по 100 задач со связями; ключи из `issuelinks`, которых нет
|
||
в выборке и в зеркале хаба (хаб сообщает список известных), агент SHALL дочитать одним `search` по `key in (...)`
|
||
и отправить с признаком `neighbor`. Ошибка хаба при запросе известных ключей или отправке пачки SHALL попадать в
|
||
`error` с префиксом «хаб: »; недоступность хаба и его 5xx повторяются, как обрыв связи, с источником «хаб».
|
||
Каждая задача в состоянии (с v10) SHALL нести `comments` — все комментарии задачи в порядке Jira, каждый
|
||
`{id, author, created, updated, body}`: `id` — строка; `author` — отображаемое имя автора, иначе его логин, иначе `null`;
|
||
`created`, `updated` — время Jira как есть; `body` — текст как есть (пустой — `""`). Если `search` отдал у задачи меньше
|
||
комментариев, чем `comment.total`, агент SHALL дочитать комментарии этой задачи через `GET /issue/{key}/comment`
|
||
постранично (`maxResults = 100`) и передать полный список. Комментарий без `id` или с пустым `id` агент SHALL отбросить
|
||
с записью в лог (ключ задачи), остальные передать. Если дочитывание комментариев задачи вернуло 403 или 404, агент SHALL
|
||
передать задачу без поля `comments` (хаб оставит прежние комментарии) с записью в лог; `refresh` продолжается.
|
||
|
||
#### Scenario: Полная синхронизация
|
||
- **WHEN** `refresh {jql: "project = AURORA AND labels = AWPCA"}` при 180 задачах
|
||
- **THEN** 2 вызова `search` + 1 на соседей; `sync_run.issues_count = 180 + соседи`
|
||
|
||
#### Scenario: Хаб не ответил при отправке состояния
|
||
- **WHEN** `refresh` через папку, реле не ответило на отправку пачки ни в одной из 4 попыток
|
||
- **THEN** отчёт `failed` с ошибкой «результат неизвестен (обрыв связи с хабом), повтор безопасен: хаб: не ответил через
|
||
папку …»; в логе повторов — «обрыв связи с хабом»
|
||
|
||
#### Scenario: Комментарии в состоянии
|
||
- **WHEN** у AURORA-1620 в Jira два комментария, автор первого — `{name: "petrov", displayName: "Петров Пётр"}`, у автора
|
||
второго нет `displayName`, его `name` — `ivanov`
|
||
- **THEN** в состоянии AURORA-1620 `comments` из двух элементов в порядке Jira, `author` — «Петров Пётр» и «ivanov»; число
|
||
вызовов `search` не изменилось
|
||
|
||
#### Scenario: Неполный список комментариев
|
||
- **WHEN** `search` вернул у AURORA-1620 20 комментариев при `comment.total = 130`
|
||
- **THEN** агент дочитал комментарии двумя вызовами `GET /issue/AURORA-1620/comment`; в состоянии 130 комментариев
|
||
|
||
#### Scenario: Комментарий без id
|
||
- **WHEN** у задачи два комментария, у второго `id = null`
|
||
- **THEN** в состоянии один комментарий; в логе строка с ключом задачи; пачка принята хабом
|
||
|
||
#### Scenario: Нет доступа к комментариям
|
||
- **WHEN** `GET /issue/AURORA-1620/comment` при дочитывании вернул 403
|
||
- **THEN** AURORA-1620 в состоянии без поля `comments`; остальные задачи пачки с комментариями; `refresh` — `done`
|
||
|
||
#### Scenario: Задача без комментариев
|
||
- **WHEN** у задачи в Jira нет комментариев
|
||
- **THEN** в её состоянии `comments = []`
|
||
|
||
## ADDED Requirements
|
||
|
||
### Requirement: Тип задачи и вложения
|
||
Агент (с v11) SHALL брать тип для `ensure_issue` из `issue_types.<issue_type>`: `{id}`, если `id` задан, иначе `{name}`;
|
||
нет записи или в ней нет ни `id`, ни `name` — ошибка конфигурации «нет настройки issue_types.<issue_type>», `failed`
|
||
без вызова Jira.
|
||
|
||
`ensure_attachment {key, file, filename, size}` (`size` дописан хабом при выдаче) агент SHALL выполнять так:
|
||
0. `size = null` — `failed` «файл удалён с хаба, загрузите заново» без вызова Jira.
|
||
1. `GET /rest/api/2/issue/{key}?fields=attachment`; вложение с тем же `filename` и тем же `size` есть — `done` с его
|
||
`attachment_id`, файл у хаба не запрашивается.
|
||
2. Файл — `GET /agent/files/{file}`; sha256 и длина декодированного `content` SHALL совпасть с `file` и `size`, иначе —
|
||
временный сбой (повтор, как обрыв связи с хабом); 404 — `failed` «файл удалён с хаба, загрузите заново».
|
||
3. `POST /rest/api/2/issue/{key}/attachments`, `multipart/form-data` с одной частью `file`, имя файла — `filename` в UTF-8
|
||
(`filename="…"` и `filename*=UTF-8''…`), заголовок `X-Atlassian-Token: no-check`; результат `attachment_id` из ответа.
|
||
Ответ Jira 4xx (в том числе 413) — `failed` с кодом и текстом Jira.
|
||
Содержимое файла MUST NOT попадать в журнал и лог (только `file`, `filename`, размер). `AGENT_VERSION` SHALL быть 11.
|
||
|
||
#### Scenario: Ошибка по имени типа
|
||
- **WHEN** `ensure_issue {issue_type: bug, …}`, `issue_types.bug = {name: "Ошибка"}`
|
||
- **THEN** в `POST /issue` `issuetype = {name: "Ошибка"}`
|
||
|
||
#### Scenario: Нет настройки типа
|
||
- **WHEN** `ensure_issue {issue_type: bug, …}`, в `issue_types` нет `bug`
|
||
- **THEN** `failed` «нет настройки issue_types.bug», вызовов Jira нет
|
||
|
||
#### Scenario: Загрузка вложения с кириллическим именем
|
||
- **WHEN** `ensure_attachment {key: X, file: <sha>, filename: "ОСВ сч. 60 за 2 кв. 2026.xlsx"}`, у X вложений нет
|
||
- **THEN** один `GET /issue/X`, один `GET /agent/files/<sha>`, один `POST /issue/X/attachments`; в Jira вложение с этим
|
||
именем и размером файла; отчёт `done` с `attachment_id`
|
||
|
||
#### Scenario: Файл повреждён в пути
|
||
- **WHEN** sha256 полученного `content` не равен `file`
|
||
- **THEN** вложение в Jira не загружается; команда повторяется как при обрыве связи с хабом
|
||
|
||
#### Scenario: Старый агент
|
||
- **WHEN** агент v10 получил `ensure_attachment`
|
||
- **THEN** `failed` «неизвестный тип команды», агент работает дальше (поведение v10, без изменений)
|