Andrey Epifancev ca231ba2ae docs(openspec): архив agent-self-update (#22)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:58:46 +04:00

8.3 KiB
Raw Blame History

MODIFIED Requirements

Requirement: Маршруты агента

Хаб SHALL предоставлять агенту следующие маршруты (все под агентским токеном):

  • POST /agent/claim {agent_version, settings_version, last_jira_call_at, update_state, launcher_version} — долгий запрос до 30 с; ответ {command: {id, type, params, pause_seconds}, settings_version, agent_release} или {command: null, settings_version, agent_release}, где agent_release — {version, sha256} опубликованной версии агента или null; обновляет agent_status (last_jira_call_at = null не затирает прежнее значение). update_state (объект или null, error хранится до 500 символов) и launcher_version (целое или null) необязательны; хаб SHALL хранить последние значения в памяти процесса, значения неверного типа игнорировать, не отвергая claim. Если есть команда в 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 или failed без результата (результат записывается, статус не меняется, заметка new:N переносится на ключ). Отчёт по команде в queued SHALL отвергаться 409 not_claimed. error хаб SHALL обрезать до 1500 символов.
  • POST /agent/state {command_id, issues: [...], links: [...], neighbor_keys: [...], page, last_page} — загрузка состояния пачками; neighbor_keys — ключи вне базовой JQL, дочитанные по связям; хаб обновляет зеркало и sync_run. Каждая пачка применяется независимо; page и last_page необязательны и хабом не используются.
  • GET /agent/known-keys — ключи зеркала (для определения соседей).
  • GET /agent/release — опубликованная версия агента {version, sha256, content} (content — текст agent.py); нет публикации или файл не сходится с манифестом по sha256 — 404 no_release.

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 not_claimed, команда осталась queued

Scenario: Длинная ошибка

  • WHEN агент прислал failed с error длиной 5000 символов
  • THEN в command.error первые 1500 символов

Scenario: Поздний отчёт после предела выдач

  • WHEN ensure_issue {temp_key: new:8, …} переведена хабом в failed «агент не отчитался после 3 выдач», затем агент прислал done с result.key = AURORA-1630
  • THEN команда failed, в result — AURORA-1630; заметка new:8 перенесена на AURORA-1630

Scenario: Публикация в ответе claim

  • WHEN опубликована v6, агент v5 отправил claim, команд нет
  • THEN ответ {command: null, settings_version, agent_release: {version: 6, sha256: …}}

Scenario: Состояние обновления от агента

  • WHEN агент прислал в claim update_state = {state: rolled_back, from_version: 6, to_version: 7, error: "код 1 через 3 с"} и launcher_version = 1
  • THEN GET /agent отдаёт это update_state, launcher_version = 1 и update_hint «откат с v7 на v6: код 1 через 3 с»

Scenario: Скачивание версии

  • WHEN агентским токеном GET /agent/release, опубликована v6
  • THEN 200 {version: 6, sha256, content}, sha256 от content в UTF-8 равен sha256; клиентским токеном — 401; без публикации — 404 no_release

ADDED Requirements

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}; оба — через временный файл и переименование, манифест последним. Команда SHALL работать без запущенного serve и печатать «опубликована v, sha256 <первые 12 символов>…, байт»; при ошибке — сообщение и код 1, опубликованное не меняется. Хаб SHALL читать манифест при каждом claim, GET /agent/release и GET /agent; битый манифест означает «публикации нет» (предупреждение в лог). GET /agent SHALL дополняться полями release ({version, sha256, published_at} или null), update_state, launcher_version и update_hint: «агент запущен без run.py — обновится только вручную» (опубликована версия выше версии агента, агент онлайн, 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; вывод «опубликована v6, sha256 …»; код 0

Scenario: Версия не выше опубликованной

  • WHEN опубликована v6, публикуется файл с AGENT_VERSION = 6
  • THEN «опубликована v6, новая должна быть больше», код 1; release/ не изменён

Scenario: Нет строки версии

  • WHEN публикуется файл без строки AGENT_VERSION = <целое> или с двумя такими строками
  • THEN сообщение об ошибке, код 1; release/ не изменён

Scenario: Агент без запускателя

  • WHEN опубликована v6, агент v5 онлайн, в последнем claim launcher_version = null
  • THEN GET /agent → update_hint = «агент запущен без run.py — обновится только вручную»