diff --git a/docs/work-items/ORCH-098/13-test-report.md b/docs/work-items/ORCH-098/13-test-report.md index b0612ce..8570b32 100644 --- a/docs/work-items/ORCH-098/13-test-report.md +++ b/docs/work-items/ORCH-098/13-test-report.md @@ -1,5 +1,5 @@ --- -result: PASS +result: PASS # PASS | FAIL — машинный вердикт, UPPERCASE work_item: ORCH-098 stage: testing author_agent: tester @@ -14,59 +14,73 @@ work_item_id: ORCH-098 ## Окружение - Python: 3.12.13 -- pytest: 8.3.3 -- Worktree: `/repos/_wt/orchestrator/feature_ORCH-098-fnd` (ветка `feature/ORCH-098-fnd`) +- pytest: 8.3.3 (pytest-cov 5.0.0, anyio 4.13.0, asyncio 0.23.8) +- Worktree: `/repos/_wt/orchestrator/feature_ORCH-098-fnd/` (ветка `feature/ORCH-098-fnd`) - Дата: 2026-06-10 -- Review verdict (`12-review.md`): **APPROVED** ✅ + +## Предусловия +- Review-вердикт (`12-review.md`): **APPROVED** (блокеров нет, все findings P2/P3 advisory). ✅ +- Smoke API (read-only, prod 8500): + - `GET /health` → `{"status":"ok","service":"orchestrator"}` ✅ + - `GET /status` → `200`, активные задачи отдаются (ORCH-098 в стадии `testing`). ✅ + - `GET /queue` → `200`; присутствует блок **`serial_gate`** (ORCH-088) ✅ и **`auto_labels`** + (ORCH-089) ✅ в полезной нагрузке — смок-регресса нет. + - Примечание: прод-контейнер 8500 несёт ещё не задеплоенный код (без блока `lessons` в `/queue`) — + это ожидаемо (ORCH-098 не выкатан в прод), на смок-вердикт не влияет. ## Результаты — покрытие тест-плана (`04-test-plan.yaml`) -Каждый TC из тест-плана сопоставлен с конкретным тестом `tests/test_lessons.py` и с критерием -приёмки `03-acceptance-criteria.md`. +Прогон: `cd /repos/_wt/orchestrator/feature_ORCH-098-fnd && pytest tests/ -v --tb=short`. +Все TC из тест-плана исполнены и сопоставлены с критериями приёмки (`03-acceptance-criteria.md`). -| TC ID | Тип | Описание (кратко) | AC | Тест | Результат | -|-------|-----|-------------------|----|------|-----------| +| TC ID | Тип | Описание | AC | Тест (`tests/test_lessons.py`) | Результат | +|-------|-----|----------|----|--------------------------------|-----------| | TC-01 | unit | `init_db()` создаёт `lessons` идемпотентно, все поля BR-1 | AC-1 | `test_tc01_table_idempotent_and_fields` | PASS | -| TC-02 | unit | Нуллабельные колонки атрибуции; запись без них + update позже | AC-2 | `test_tc02_attribution_columns_nullable_and_settable` | PASS | -| TC-03 | unit | `record()` вставляет строку (auto/manual), возвращает id, стампит `created_at` | AC-3/AC-5 | `test_tc03_record_inserts_and_returns_id` | PASS | -| TC-04 | unit | never-raise: падающая БД → `None`/`[]`/`{}` без исключения | AC-6 | `test_tc04_never_raise_on_db_error` | PASS | -| TC-05 | unit | kill-switch `lessons_enabled=False` → record/get/update/snapshot инертны | AC-7 | `test_tc05_kill_switch_inert` | PASS | -| TC-06 | unit | `get_lessons` фильтрует type/status/repo/work_item + limit, `ORDER BY id DESC` | AC-4 | `test_tc06_filters_limit_order` | PASS | -| TC-07 | unit | `update_lesson` меняет status/attribution/target_*/related_task + `updated_at`; неизвестный id безопасен | AC-5 | `test_tc07_update_and_unknown_id` | PASS | -| TC-08 | integration | Автозапись gate-fail: откат на development → строка `type=gate_failure` с контекстом | AC-3 | `test_tc08_gate_failure_autorecord` | PASS | -| TC-09 | integration | Автозапись transient/HOLD; сбой записи не ломает горячий путь (never-raise) | AC-3/AC-6 | `test_tc09_transient_autorecord_and_never_raise` | PASS | -| TC-10 | integration | `GET /lessons` → 200 + фильтры; `GET /queue` блок `lessons`; чтение не мутирует | AC-4 | `test_tc10_get_endpoints` | PASS | -| TC-11 | integration | `POST /lessons` (manual+атрибуция), `POST /lessons/{id}` (update); flag=False → `{enabled:false}` | AC-5/AC-7 | `test_tc11_post_endpoints_and_killswitch` | PASS | -| TC-12 | unit | Инварианты конвейера: `STAGE_TRANSITIONS`/`QG_CHECKS`/machine-verdict неизменны | AC-8 | `test_tc12_pipeline_invariants_untouched` | PASS | +| TC-02 | unit | Нуллабельные колонки атрибуции `attribution/target_repo/target_domain`, update проставляет позже | AC-2 | `test_tc02_attribution_columns_nullable_and_settable` | PASS | +| TC-03 | unit | `record()` вставляет строку (source auto/manual), возвращает id, `created_at` заполнен | AC-3/AC-5 | `test_tc03_record_inserts_and_returns_id` | PASS | +| TC-04 | unit | never-raise при падающей БД: `record/get/update/snapshot` → `None/[]/{}` без исключения | AC-6 | `test_tc04_never_raise_on_db_error` | PASS | +| TC-05 | unit | kill-switch `lessons_enabled=False` — инертность (no-op, без БД) | AC-7 | `test_tc05_kill_switch_inert` | PASS | +| TC-06 | unit | `get_lessons` фильтрует type/status/repo/work_item, limit, `ORDER BY id DESC` | AC-4 | `test_tc06_filters_limit_order` | PASS | +| TC-07 | unit | `update_lesson` меняет status/attribution/target_*/related_task + `updated_at`; неизв. id безопасен | AC-5 | `test_tc07_update_and_unknown_id` | PASS | +| TC-07b | unit | (доп.) дедуп `source=auto` в окне; `source=manual` всегда проходит | AC-3/AC-5 | `test_tc07b_auto_dedup_and_manual_passthrough` | PASS | +| TC-08 | integration | Автозапись gate-fail: откат в `_handle_qg_failure_rollbacks` → строка `gate_failure` с контекстом | AC-3 | `test_tc08_gate_failure_autorecord` | PASS | +| TC-09 | integration | Автозапись transient/HOLD: транзиент-ветка пишет урок; сбой записи не ломает горячий путь | AC-3/AC-6 | `test_tc09_transient_autorecord_and_never_raise` | PASS | +| TC-10 | integration | `GET /lessons` → 200 с фильтрами; `GET /queue` несёт блок `lessons`; чтение не мутирует | AC-4 | `test_tc10_get_endpoints` | PASS | +| TC-11 | integration | `POST /lessons` (manual+атрибуция), `POST /lessons/{id}` обновляет; при выключенном флаге `{enabled:false}` | AC-5/AC-7 | `test_tc11_post_endpoints_and_killswitch` | PASS | +| TC-12 | unit | Инварианты конвейера не тронуты: `STAGE_TRANSITIONS`/`QG_CHECKS`/machine-verdict неизменны | AC-8 | `test_tc12_pipeline_invariants_untouched` | PASS | -**Дополнительно** (сверх тест-плана): `test_tc07b_auto_dedup_and_manual_passthrough` (дедуп -`source="auto"` в окне `lessons_dedup_window_s` + manual-passthrough, ADR-001 D4) — PASS. - -Покрытие: **все 12 TC тест-плана выполнены и PASS**; каждый сопоставлен с критерием приёмки -AC-1…AC-8 (AC-9 — верификация тестов/доков, подтверждена зелёным регрессом и review APPROVED). - -## Smoke API (read-only) -- `GET /health` → `{"status":"ok","service":"orchestrator"}` ✅ -- `GET /status` → 200, активные задачи отдаются (ORCH-098 task 86 на `testing`) ✅ -- `GET /queue` → 200; блок **`serial_gate`** присутствует (ORCH-088) ✅; блок `auto_labels` - присутствует ✅; блоки `coverage`/`stop`/`bug_fast_track` присутствуют ✅ -- Прим.: эндпоинт `GET /lessons` и блок `lessons` в `/queue` на прод-контейнере (8500) **отсутствуют - ожидаемо** — прод исполняет ещё не задеплоенный код; новая функциональность верифицирована в - worktree (TC-10/TC-11 зелёные). Это **не** регресс смока: обязательный блок `serial_gate` на месте. +**Итог покрытия:** 12/12 TC тест-плана исполнены и сопоставлены с AC-1…AC-9 → PASS. +AC-9 (полный регресс зелёный + новый `test_lessons.py`) подтверждён прогоном ниже. ## Вывод pytest -``` -$ cd /repos/_wt/orchestrator/feature_ORCH-098-fnd && pytest tests/ -v --tb=short -... -================== 1564 passed, 1 warning in 62.81s (0:01:02) ================== -$ pytest tests/test_lessons.py -v -======================== 13 passed, 1 warning in 1.56s ========================= +Полный регресс (`tests/`): +``` +================== 1630 passed, 1 warning in 71.78s (0:01:11) ================== +``` +(единственный warning — PydanticDeprecatedSince20 в `src/config.py`, не связан с ORCH-098, +предсуществующий.) + +Целевой модуль (`tests/test_lessons.py`): +``` +collected 13 items +tests/test_lessons.py::test_tc01_table_idempotent_and_fields PASSED [ 7%] +tests/test_lessons.py::test_tc02_attribution_columns_nullable_and_settable PASSED [ 15%] +tests/test_lessons.py::test_tc03_record_inserts_and_returns_id PASSED [ 23%] +tests/test_lessons.py::test_tc04_never_raise_on_db_error PASSED [ 30%] +tests/test_lessons.py::test_tc05_kill_switch_inert PASSED [ 38%] +tests/test_lessons.py::test_tc06_filters_limit_order PASSED [ 46%] +tests/test_lessons.py::test_tc07_update_and_unknown_id PASSED [ 53%] +tests/test_lessons.py::test_tc07b_auto_dedup_and_manual_passthrough PASSED [ 61%] +tests/test_lessons.py::test_tc08_gate_failure_autorecord PASSED [ 69%] +tests/test_lessons.py::test_tc09_transient_autorecord_and_never_raise PASSED [ 76%] +tests/test_lessons.py::test_tc10_get_endpoints PASSED [ 84%] +tests/test_lessons.py::test_tc11_post_endpoints_and_killswitch PASSED [ 92%] +tests/test_lessons.py::test_tc12_pipeline_invariants_untouched PASSED [100%] +======================== 13 passed, 1 warning in 1.55s ========================= ``` -(1 warning — устаревший Pydantic class-based `config` в `src/config.py`, не относится к ORCH-098.) ## Итог -**PASS** — полный регресс `tests/` зелёный (1564 passed), все 12 TC тест-плана выполнены и -сопоставлены с критериями приёмки, smoke read-only (`/health`, `/status`, `/queue` с обязательным -блоком `serial_gate`) в порядке. Review-вердикт APPROVED. Задача готова к переходу на -`deploy-staging`. +**PASS** — полный регресс зелёный (1630 passed), все 12 TC тест-плана исполнены и сопоставлены +с критериями приёмки, smoke API read-only (`/health`/`/status`/`/queue`) в норме (блоки +`serial_gate` и `auto_labels` присутствуют). Задача готова к переходу на `deploy-staging`.