9.9 KiB
MODIFIED Requirements
Requirement: Маршруты интерфейсов
Хаб SHALL предоставлять интерфейсам (MCP, позже просмотрщик) следующие маршруты под клиентским токеном:
GET /issuesс фильтрамиsprint,assignee,work_kind,fact_status,status,label,epic,neighbor,q(подстрока темы),limit/offset— строки зеркала (все поляissue) сfact_statusиwork_kindиз заметок; сокращение до карточки — дело интерфейса.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— отменяетqueuedкоманды пакета; ответ — вид пакета с полемstill_claimed: список{id, type}команд пакета вclaimed(они будут выполнены агентом; остановить — отмена команды сforce).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; ответ — все настройки после записи, как уGET /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 с темой «Шахматка: комментарии», пакет не создан
Scenario: Тема не строка
- WHEN
POST /batchesсensure_issue {temp_key: new:1, summary: 42, …} - THEN 422 с указанием параметра
summary, пакет не создан
Scenario: Отмена пакета с командой у агента
- WHEN в пакете 9 команда 30
claimed, команды 31 и 32queued;POST /batches/9/cancel - THEN 31 и 32
cancelled; в ответеstill_claimed = [{id: 30, type: …}]; 30 остаётсяclaimed
Scenario: Ответ на запись настроек
- WHEN
PUT /settings {relay_dir: "/Volumes/externalSSD/utm/rshb/jira-bridge"} - THEN 200; ответ содержит
relay_dirс записанным значением, новуюsettings_versionи остальные настройки; токенов в ответе нет
Requirement: Публикация версии агента
jira-hub agent publish PATH SHALL публиковать файл агента: текст в UTF-8 не больше 1 МБ, ровно одна строка
AGENT_VERSION = <целое>, версия больше опубликованной. Файл SHALL записываться в <JIRA_HUB_HOME>/release/agent.py
(каталог 0700), затем manifest.json {version, sha256, size, published_at}; оба — через временный файл с fsync и
переименование, манифест последним. Прежний agent.py на время публикации SHALL переименовываться в agent.py.prev
и удаляться после записи манифеста; если запись нового файла или манифеста не удалась (OSError), хаб SHALL вернуть
agent.py.prev на место agent.py, удалить временные файлы и завершить команду сообщением «не удалось записать
публикацию: <ошибка>» и кодом 1 — опубликованной остаётся прежняя версия. Команда SHALL работать без запущенного
serve и печатать «опубликована v, sha256 <первые 12 символов>…, байт»; при ошибке — сообщение и код 1,
опубликованное не меняется. Хаб SHALL читать манифест при каждом claim, GET /agent/release и GET /agent; манифест
годен, только если это объект, version — целое число (не логическое) не меньше 1, sha256 — строка из 64 символов
[0-9a-f]; негодный или нечитаемый манифест означает «публикации нет» и предупреждение в лог — одно на каждый новый
текст ошибки. Файл agent.py, не декодируемый как UTF-8 при совпавшем sha256, означает «публикации нет»
(GET /agent/release — 404 no_release). GET /agent SHALL дополняться полями release ({version, sha256, published_at} или null), update_state, launcher_version, agent_reported (был ли claim с момента запуска хаба)
и update_hint: «агент запущен без run.py — обновится только вручную» (опубликована версия выше версии агента, агент
онлайн, agent_reported = true, launcher_version = null), «откат с v на v: » (rolled_back),
«v отвергнута: » (rejected), иначе null.
Scenario: Публикация новой версии
- WHEN опубликована v5,
jira-hub agent publish jira-agent/src/agent.pyсAGENT_VERSION = 6 - THEN в
release/— новыйagent.pyи манифест сversion = 6,agent.py.prevнет; вывод «опубликована v6, sha256 …»; код 0
Scenario: Версия не выше опубликованной
- WHEN опубликована v6, публикуется файл с
AGENT_VERSION = 6 - THEN «опубликована v6, новая должна быть больше», код 1;
release/не изменён
Scenario: Нет строки версии
- WHEN публикуется файл без строки
AGENT_VERSION = <целое>или с двумя такими строками - THEN сообщение об ошибке, код 1;
release/не изменён
Scenario: Диск полон при записи манифеста
- WHEN опубликована v8, публикуется v9, запись
manifest.jsonзавершиласьOSError - THEN «не удалось записать публикацию: …», код 1, без трейсбека;
agent.pyи манифест — прежние v8,GET /agent/releaseотдаёт v8; временных файлов иagent.py.prevвrelease/нет
Scenario: Негодный манифест
- WHEN в
manifest.jsonversion = 6.9(илиtrue, илиsha256короче 64 символов), хаб получает 100claim - THEN в
claimagent_release = null,GET /agent/release— 404; в логе одно предупреждение о манифесте
Scenario: Агент без запускателя
- WHEN опубликована v6, агент v5 онлайн, в последнем
claimlauncher_version = null - THEN
GET /agent→agent_reported = true,update_hint= «агент запущен без run.py — обновится только вручную»
Scenario: Хаб перезапущен, агент ещё не выходил на связь
- WHEN опубликована v10, агент v9 под запускателем, хаб перезапущен,
claimпосле запуска ещё не было - THEN
GET /agent→agent_reported = false,launcher_version = null,update_hint = null; после первогоclaim—agent_reported = true,launcher_versionизclaim