jira-agent/docs/superpowers/plans/2026-10-25-sp-estimation-agent.md
Andrey Epifancev 3350d0066a План: агент v16, оценка через доску (#53)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:40:40 +04:00

49 lines
4.3 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.

# Агент v16: оценка через доску Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** `ensure_fields` со `story_points` и `board_id` ставит оценку через `/rest/agile/1.0/issue/{key}/estimation?boardId=…`.
**Architecture:** в `Executor.do_ensure_fields` ветка оценки с доской отделяется от `PUT /issue`: сначала остальные
поля (как v15, `GET /issue` только если они есть), затем `GET`/`PUT` оценки доски. Без `board_id` — путь v15.
**Tech Stack:** Python 3.9 stdlib, unittest; фейк Jira — `tests/fake_jira.py`.
**Spec:** `sdlc-hub/openspec/changes/sp-estimation-board/specs/agent/spec.md`, `…/specs/commands/spec.md`; решения — `openspec/changes/agent-v16-sp-estimation/design.md`.
## Global Constraints
- `AGENT_VERSION = 16`; Python 3.9, только stdlib (`tests/test_py39.py`).
- Тело `PUT`: `{"value": <число или null>}`; путь `AGILE + "/issue/%s/estimation"` с параметром `boardId`.
- Сравнение — `_same_points`; плохое значение — `failed` «story_points — число ≥ 0 или null» до вызовов Jira.
## Review Focus
1. Команда только с оценкой — без `GET /issue` и `PUT /issue`; `jira_calls` 2 (запись) и 1 (без изменений).
2. Оценка и другие поля — `PUT /issue` без поля оценки, затем `PUT estimation`; `changed` — все поля.
3. Ошибка Jira на `PUT estimation` (400) — `failed`, остальные поля уже записаны.
4. `null` при пустой оценке — без записи; при `1.0` — `PUT {"value": null}`.
5. Без `board_id` — поведение v15 (существующие тесты `test_story_points_*` не меняются).
---
### Task 1: Оценка через estimation доски
**Files:**
- Modify: `tests/fake_jira.py` (маршрут `/rest/agile/1.0/issue/{key}/estimation`: `GET` → `{"fieldId": POINTS_FIELD, "value": <поле задачи>}`, `PUT` → пишет `value` в поле задачи, тело в `self.estimation_bodies`; доска не из `self.boards` → 400; задачи нет → 404; маршрут — до общего `/rest/agile/1.0/issue/([^/]+)$`)
- Modify: `src/agent.py` (`do_ensure_fields`, `AGENT_VERSION = 16`)
- Test: `tests/test_executor_fields.py` (раздел `# --- story_points через доску (#53)`)
- [ ] **Step 1: Тесты:**
- `test_points_by_board_set` — оценка `1.0`, `story_points=2, board_id=4216`: `result == {"changed": ["story_points"]}`, `jira_calls == 2`, `estimation_bodies == [{"value": 2}]`, `("PUT", "/rest/api/2/issue/AURORA-1704")` и `("GET", "/rest/api/2/issue/AURORA-1704")` нет в `requests`;
- `test_points_by_board_same` — оценка `2.0`, `story_points=2`: `changed == []`, `jira_calls == 1`, записей нет;
- `test_points_by_board_clear` — оценка `1.0`, `story_points=None` → тело `{"value": None}`; при пустой оценке — без записи;
- `test_points_by_board_with_fields` — `duedate` + `story_points`: `PUT /issue` без `customfield_10106`, потом `PUT estimation`; `changed == ["duedate", "story_points"]`;
- `test_points_by_board_jira_error` — доска 9999 (нет у фейка): `failed`, `duedate` уже записан;
- `test_points_by_board_no_field_lookup` — `fake.fields = []`: всё равно `done` (без `GET /field`);
- `test_points_by_board_bad_value` — `"3"` → `failed`, `requests` пуст.
- [ ] **Step 2:** `/usr/bin/python3 -m unittest tests.test_executor_fields` — FAIL.
- [ ] **Step 3:** `do_ensure_fields`: при `board_id` и `story_points` — путь доски (R-1…R-3 design), иначе v15; `AGENT_VERSION = 16`.
- [ ] **Step 4:** `/usr/bin/python3 -W error::ResourceWarning -m unittest discover -s tests -t .` — зелёный.
- [ ] **Step 5:** commit «Агент v16: оценка через estimation доски (#53)».