51 lines
4.6 KiB
Markdown
51 lines
4.6 KiB
Markdown
## MODIFIED Requirements
|
||
|
||
### Requirement: Схема базы хаба
|
||
База хаба SHALL быть одним файлом SQLite (WAL) с таблицами `issue`, `issue_link`, `issue_note`, `batch`, `command`,
|
||
`sync_run`, `agent_status`, `setting`. Схема SHALL создаваться и мигрироваться самим хабом при старте по номеру версии
|
||
в `setting.schema_version` (текущая — 2). Миграция существующей базы SHALL выполняться в одной транзакции; перед ней
|
||
хаб SHALL скопировать файл базы в `backups/<дата-время>-schema-v<старая>.sqlite` рядом с базой. Денежных и дробных
|
||
полей нет; даты — ISO-8601 строки в UTC, кроме `duedate` и плановых дат (даты без времени).
|
||
|
||
#### Scenario: Первый запуск
|
||
- **WHEN** хаб стартует с несуществующим файлом базы
|
||
- **THEN** файл создаётся, таблицы и индексы на месте, `setting.schema_version` = текущая
|
||
|
||
#### Scenario: Миграция базы v1
|
||
- **WHEN** хаб стартует с базой `schema_version = 1`, в которой есть задачи, заметки и команда в `claimed`
|
||
- **THEN** в `backups/` копия базы v1; добавлена `command.deliveries` (у `claimed` — 1, у остальных — 0); данные на месте;
|
||
`schema_version = 2`
|
||
|
||
### Requirement: Служебные заметки
|
||
Таблица `issue_note` SHALL хранить поля, которых нет в Jira: `key` (PK; ключ Jira или временный `new:<n>`),
|
||
`fact_status`, `work_kind`, `done_text`, `rest_text`, `owner_note`, `updated_at`, `updated_by`. Обновление зеркала
|
||
MUST NOT менять `issue_note`. При завершении `ensure_issue` с временным ключом хаб SHALL переименовать строку заметок
|
||
на настоящий ключ — в том числе по позднему отчёту `done` с ключом о команде, отменённой до отчёта.
|
||
|
||
#### Scenario: Заметка переживает refresh
|
||
- **WHEN** у задачи есть `issue_note.fact_status = "В работе"` и приходит полное обновление зеркала
|
||
- **THEN** `fact_status` не изменился
|
||
|
||
### Requirement: Пакеты и команды
|
||
Таблица `batch` SHALL хранить `id`, `title`, `author`, `created_at`, `cancelled_at`, `estimate_seconds`.
|
||
Таблица `command` SHALL хранить `id`, `batch_id`, `seq`, `type`, `params` (JSON), `status`
|
||
(`queued | claimed | done | failed | skipped | cancelled | confirmed_by_state`), `claimed_at` (время последней выдачи),
|
||
`deliveries` (сколько раз команда выдана агенту), `finished_at`, `result` (JSON), `error`, `jira_calls`, `rate_limited`
|
||
(число 429/503), `pause_seconds` (выданная пауза), `depends_on` (id команды, чей результат подставляется). Статус пакета
|
||
SHALL вычисляться из команд, не храниться.
|
||
|
||
#### Scenario: Статус пакета
|
||
- **WHEN** в пакете 3 команды: `done`, `claimed`, `queued`
|
||
- **THEN** статус пакета «выполняется»; когда все в терминальных статусах — «завершён», с числом `failed`/`skipped`
|
||
|
||
### Requirement: Журнал синхронизаций и статус агента
|
||
Таблица `sync_run` SHALL хранить каждую загрузку состояния: `started_at`, `finished_at`, `kind` (`keys | jql`), `query`,
|
||
`issues_count`, `links_count`, `jira_calls`, `rate_limited`, `command_id`. Таблица `agent_status` (одна строка) SHALL
|
||
хранить `last_seen_at`, `agent_version`, `settings_version`, `current_command_id`, `last_jira_call_at`. Через API и MCP
|
||
`agent_status` SHALL отдаваться с признаком `online` (истина, если `last_seen_at` моложе 5 минут) и списком
|
||
`redelivered` — команд в `claimed`, выданных больше одного раза (`id`, `type`, `claimed_at`, `deliveries`).
|
||
|
||
#### Scenario: Агент давно не выходил на связь
|
||
- **WHEN** `last_seen_at` старше 5 минут
|
||
- **THEN** `agent_status` через API и MCP отдаётся с `online = false`
|