## MODIFIED Requirements ### Requirement: Чтение состояния `refresh` SHALL выполняться запросом `search` (`jql`, `fields` = поля зеркала включая `issuelinks`, `comment`, `attachment` и спринт, `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` продолжается. Каждая задача в состоянии (с v14) SHALL нести `attachments` — все вложения задачи из поля `attachment` ответа `search` в порядке Jira, каждое `{id, filename, size, mime_type, author, created}`: `id` — строка; `filename` — имя как есть; `size` — целое (байт) или `null`; `mime_type` — `mimeType` Jira или `null`; `author` — как у комментария; `created` — время Jira как есть. Содержимое вложений при `refresh` MUST NOT скачиваться. Вложение без `id` агент SHALL отбросить с записью в лог (ключ задачи). Нет поля `attachment` в ответе (поле скрыто настройками Jira) — `attachments = []`. #### 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 = []` #### Scenario: Вложения в состоянии - **WHEN** у AURORA-1650 в Jira два вложения: «скрин 1.png» (`mimeType = image/png`, 240000 байт, автор `{name: "potapova", displayName: "Потапова Анна"}`) и «ОСВ 60.xlsx» - **THEN** в состоянии AURORA-1650 `attachments` из двух элементов в порядке Jira, у первого `filename = "скрин 1.png"`, `size = 240000`, `mime_type = "image/png"`, `author = "Потапова Анна"`; число вызовов `search` не изменилось, обращений к содержимому вложений нет ## ADDED Requirements ### Requirement: Скачивание вложения Агент v14 SHALL выполнять `fetch_attachment` по контракту `commands` («Скачивание вложения по запросу»). Метод `JiraClient` для содержимого SHALL отдавать байты ответа без разбора JSON, с тем же счётом вызовов, повтором 429/503 и учётом времени последнего вызова, что и прочие вызовы Jira. Отправка хабу — `HubClient` (`POST /agent/files`), работает и через общую папку. В журнал агента (`journal.jsonl`) и в лог содержимое файла MUST NOT попадать — только id, имя, размер и sha256. #### Scenario: Скачивание через общую папку - **WHEN** агент с `hub_url = folder:…` выполняет `fetch_attachment` вложения 3 МБ - **THEN** содержимое уходит хабу одним запросом `POST /agent/files` через папку (тело ≈ 4 МБ base64); отчёт `done` с `file` и `size`; в `journal.jsonl` нет содержимого файла