Files
orchestrator/docs/work-items/ORCH-099/03-acceptance-criteria.md

128 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
work_item: ORCH-099
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-10
model_used: claude-opus-4-8
---
# 03 — Критерии приёмки (Acceptance Criteria): ORCH-099 — FND/F1a: лёгкий `/metrics` в орке
Work Item: **ORCH-099** · Repo: **orchestrator** · Стадия: analysis
Формат: каждый критерий имеет **PASS** (что должно быть истинно для приёмки) и **FAIL**
(что считается провалом). Reviewer/tester проверяет их буквально по файлам репозитория и по ответу
эндпоинта.
---
## AC-1 — Эндпоинт `/metrics` отдаёт четыре раздела сырья
**Условие:** `GET /metrics` возвращает `200` и JSON с разделами `stages`, `queue`, `agents`, `cost`
(плюс конверт `schema_version` / `generated_at`), с полями из TRZ §3.
- **PASS:** ответ — валидный JSON-объект; присутствуют ключи `schema_version`, `generated_at`,
`stages` (список; элемент содержит `work_item`, `stage`, `age_in_stage_s`, `repo`), `queue`
(содержит `counts`, `breaker`, `max_concurrency`, сырьё ретраев), `agents` (список; элемент
содержит `agent`, `run_id`, `pid`, `runtime_s` и поле сырья CPU-liveness), `cost` (содержит
`aggregate` с суммами `cost_usd`/`input_tokens`/`output_tokens`/`cache_read_tokens`/
`cache_creation_tokens`).
- **FAIL:** отсутствует любой из четырёх разделов; в `agents` нет `pid`/`runtime_s`; в `stages` нет
«как давно в стадии»; в `cost` нет агрегата токенов/стоимости; ответ не JSON или статус ≠ 200.
---
## AC-2 — Аддитивность: `/health`, `/status`, `/queue` не сломаны
**Условие:** существующие эндпоинты сохраняют прежний контракт.
- **PASS:** `GET /health``{"status":"ok", ...}`; `GET /status``{"active_tasks":[...]}`;
`GET /queue` отдаёт прежний набор ключей; существующие тесты эндпоинтов (`tests/test_queue_endpoint.py`
и пр.) зелёные без модификации их ожиданий.
- **FAIL:** изменён/удалён любой существующий ключ ответа `/health`/`/status`/`/queue`; пришлось
править существующие тесты под новый контракт; регресс в этих эндпоинтах.
---
## AC-3 — Лёгкость и быстрая выборка
**Условие:** эндпоинт лёгкий — только быстрые локальные SQL + чтение in-memory снапшотов, без
тяжёлых вычислений и сетевых вызовов.
- **PASS:** в коде `src/metrics.py` нет сетевых вызовов (HTTP/Plane/Gitea/Anthropic), нет запуска
подпроцессов кроме безопасного чтения `/proc/<pid>/stat`, нет сканирования git/файлового дерева;
данные берутся из существующих helper'ов БД и `worker`-снапшота; на типовом объёме ответ
формируется без заметной задержки.
- **FAIL:** эндпоинт делает сетевой запрос, запускает агента/тяжёлый процесс, сканирует worktree/git
или выполняет дорогие агрегаты, заметно тормозящие ответ.
---
## AC-4 — Never-raise (ошибка поля → `null`, эндпоинт не падает)
**Условие:** любая ошибка сбора отдельного поля/раздела не роняет эндпоинт.
- **PASS:** при недоступном источнике (например, `worker` не инициализирован, `pid` уже мёртв,
`/proc/<pid>` отсутствует, пустые таблицы) соответствующее поле получает `null`/безопасный дефолт,
а `GET /metrics` всё равно возвращает `200` и валидный JSON; есть тест, симулирующий сбой раздела
и проверяющий 200 + `null` в этом поле.
- **FAIL:** при любом из перечисленных условий эндпоинт возвращает `500` / бросает исключение /
возвращает невалидный JSON.
---
## AC-5 — Read-only (ничего не меняет; гейты/схема не тронуты)
**Условие:** эндпоинт и модуль строго read-only; конвейерные инварианты целы.
- **PASS:** `src/metrics.py` и обработчик `/metrics` не выполняют `INSERT`/`UPDATE`/`DELETE`/`CREATE`/
`ALTER`, не запускают/останавливают процессы, не рестартят, не мутируют состояние демонов;
`STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, machine-verdict ключи и схема БД (`tasks`/`jobs`/
`agent_runs` и пр.) — без изменений в диффе; повторный вызов `/metrics` не меняет состояние БД
(тест: снимок БД до/после идентичен).
- **FAIL:** дифф трогает `STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/схему/machine-verdict; модуль
выполняет любую запись/мутацию; вызов эндпоинта меняет состояние.
---
## AC-6 — agent-liveness содержит сырьё для alive-детекта
**Условие:** по каждому running-job отдаётся идентификация процесса и сырьё для CPU-детекта
sidecar'ом.
- **PASS:** для running-job ответ содержит `agent`, `run_id`, `pid`, `runtime_s` и поле сырья
CPU-liveness (например `cpu_ticks` из `/proc/<pid>/stat` + базис тиков `clk_tck`, либо
эквивалент по решению ADR), позволяющее внешнему наблюдателю посчитать CPU-дельту между опросами;
при `pid is None`/мёртвом процессе CPU-поле = `null` (см. AC-4), прочие поля целы.
- **FAIL:** liveness-раздел не позволяет sidecar'у отличить «жив» от «завис» (нет ни CPU-сырья, ни
pid+runtime); отсутствуют `run_id`/`pid`; обращение к мёртвому pid роняет эндпоинт.
---
## AC-7 — Контракт задокументирован (для sidecar F1b) + CHANGELOG
**Условие:** формат `/metrics` зафиксирован как контракт и отражён в журнале изменений.
- **PASS:** в `docs/architecture/README.md` описан формат ответа `/metrics` (разделы, поля,
`schema_version`) как стабильный контракт для sidecar (F1b); в `CHANGELOG.md` есть запись
`## [Unreleased]` с пометкой `ORCH-099`.
- **FAIL:** формат не задокументирован или описан только в коде; нет записи в `CHANGELOG.md`;
документация противоречит фактическому ответу эндпоинта.
---
## AC-8 — pytest зелёный
**Условие:** новый тест-набор и полный регресс проходят.
- **PASS:** `pytest tests/ -q` зелёный; присутствует `tests/test_metrics.py`, покрывающий структуру
ответа (AC-1), never-raise (AC-4), read-only (AC-5), liveness-сырьё (AC-6) и аддитивность (AC-2).
- **FAIL:** любой тест красный; новые тесты отсутствуют или не покрывают перечисленные критерии.
---
## Сводная матрица AC ↔ FR/BR
| AC | Покрывает |
|----|-----------|
| AC-1 | BR-1/BR-2/BR-3/BR-5 / FR-1…FR-5 |
| AC-2 | BR-6 / FR-4 |
| AC-3 | NFR-3 / FR-6 |
| AC-4 | NFR-2 / FR-6 |
| AC-5 | NFR-1/NFR-4/NFR-5 / FR-5 |
| AC-6 | BR-4 / FR-3 |
| AC-7 | BR-7 / FR-5 |
| AC-8 | NFR-3 (валидация) / все FR |