## 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.`: `{id}`, если `id` задан, иначе `{name}`; нет записи или в ней нет ни `id`, ни `name` — ошибка конфигурации «нет настройки issue_types.», `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: , filename: "ОСВ сч. 60 за 2 кв. 2026.xlsx"}`, у X вложений нет - **THEN** один `GET /issue/X`, один `GET /agent/files/`, один `POST /issue/X/attachments`; в Jira вложение с этим именем и размером файла; отчёт `done` с `attachment_id` #### Scenario: Файл повреждён в пути - **WHEN** sha256 полученного `content` не равен `file` - **THEN** вложение в Jira не загружается; команда повторяется как при обрыве связи с хабом #### Scenario: Старый агент - **WHEN** агент v10 получил `ensure_attachment` - **THEN** `failed` «неизвестный тип команды», агент работает дальше (поведение v10, без изменений)