Тест границы test_core_has_no_module_terms; ARCHITECTURE/CLAUDE/README; дельта-спека о хуках before_result/abort_result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
62 lines
5.7 KiB
Markdown
62 lines
5.7 KiB
Markdown
## ADDED Requirements
|
||
|
||
### Requirement: Агенты модулей
|
||
У каждого подключённого модуля, объявляющего типы команд, SHALL быть свой агент; имя агента — имя модуля (`jira` —
|
||
jira-agent, `wiki` — eva-agent). Агент SHALL определяться по токену: `setting.tokens = {client, agents: {<модуль>:
|
||
<токен>}}`, недостающий токен агента хаб создаёт при старте. Хаб SHALL для каждого агента отдельно:
|
||
- выдавать в `claim` только команды типов его модуля, с одной командой в полёте на агента (агенты работают
|
||
параллельно);
|
||
- хранить строку `agent_status` (ключ — имя агента);
|
||
- держать опубликованный релиз `release/<модуль>/` и состояние самообновления;
|
||
- отдавать в `GET /agent/settings` ключи ядра и ключи для агента только своего модуля;
|
||
- пускать на маршруты модуля со scope `agent` только агента этого модуля (токен другого агента — 401).
|
||
|
||
Миграция v7 SHALL сохранить прежний агентский токен как токен агента `jira`, перенести строку `agent_status` в агента
|
||
`jira` и прежнюю публикацию `release/agent.py` в `release/jira/`. jira-agent v14 SHALL работать без обновления.
|
||
|
||
#### Scenario: jira-agent после выкатки
|
||
- **WHEN** хаб v6 с агентским токеном T и публикацией v14 обновлён до v7, jira-agent v14 шлёт `claim` с токеном T
|
||
- **THEN** 200; ответ содержит `agent_release {version: 14, …}`; `GET /agent` показывает агента `jira` с версией 14
|
||
|
||
#### Scenario: Агенты не берут чужие команды
|
||
- **WHEN** в очереди пакет 1 с `ensure_issue` и пакет 2 с `wiki_sync`, оба `queued`; агент `wiki` шлёт `claim`
|
||
- **THEN** выдан `wiki_sync`; следующий `claim` агента `jira` получает `ensure_issue`, хотя `wiki_sync` ещё `claimed`
|
||
|
||
#### Scenario: Чужой маршрут агента
|
||
- **WHEN** токеном агента `wiki` вызван `POST /agent/state`
|
||
- **THEN** 401, зеркало не меняется
|
||
|
||
#### Scenario: Настройки только своего модуля
|
||
- **WHEN** токеном агента `wiki` вызван `GET /agent/settings`
|
||
- **THEN** в ответе есть `wiki_pacing` и `settings_version`, ключей jira (`project_key`, `transitions_map`) нет
|
||
|
||
### Requirement: Поля проекта от модулей
|
||
Проект ядра SHALL состоять из `label`, `name`, `created_at`; остальные поля проекта SHALL объявлять модули: имя, тип,
|
||
проверку, изменяемость после создания, подпись и подсказку. Модуль SHALL сам хранить свои поля и отдавать их значения
|
||
(включая вычисляемые) для списка проектов. При старте хаб SHALL отвергать два модуля с одним именем поля или поле
|
||
модуля с именем поля ядра — ошибка старта с именем поля и модулей. В ядре SHALL NOT оставаться знания о полях модулей
|
||
(доска, число задач, корень вики).
|
||
|
||
#### Scenario: Конфликт полей
|
||
- **WHEN** два модуля объявляют поле проекта `root`
|
||
- **THEN** хаб не стартует, ошибка называет поле и оба модуля
|
||
|
||
#### Scenario: Поля jira прежние
|
||
- **WHEN** после миграции v7 вызван `GET /projects`
|
||
- **THEN** у `AWPCA` `board_id = 4216`, `board_type = scrum`, `issues_count` — как до миграции
|
||
|
||
### Requirement: Подготовка отчёта команды модулем
|
||
Контракт `CommandHooks` SHALL содержать два необязательных хука. `before_result(conn, cmd, status, result, files_dir)`
|
||
SHALL вызываться ядром при отчёте по выданной команде до транзакции отчёта, чтобы модуль готовил тяжёлую работу (перевод,
|
||
запись файлов) вне блокировки базы; `ValueError` из него SHALL отдаваться как ошибка сервера, а не как неверный статус
|
||
отчёта. `abort_result(conn, cmd)` SHALL вызываться, когда отчёт не дошёл до `after_result` (ранний выход, исключение), и
|
||
снимать подготовку `before_result`. Модуль без этих хуков SHALL работать как прежде.
|
||
|
||
#### Scenario: Подготовка до транзакции
|
||
- **WHEN** агент шлёт отчёт `done` по команде типа модуля с `before_result`
|
||
- **THEN** `before_result` вызван до `BEGIN IMMEDIATE`, после фиксации транзакции — `after_result`
|
||
|
||
#### Scenario: Отчёт прерван
|
||
- **WHEN** `before_result` выполнен, а транзакция отчёта завершилась исключением
|
||
- **THEN** вызван `abort_result`, подготовка снята, команда остаётся выданной
|