opencode-config/docs/handoff/pr-67-check-project-map.md
Sergey f06d36140b
feat(pipeline): add check_project_map to DOCS phase (#67)
* feat(pipeline): add check_project_map to DOCS phase

* test(pipeline): add check_project_map unit tests + update check_docs tests

* docs(adr): add ADR-028 project map contract

* docs(project-map): mention check_project_map guard in Update Protocol

* docs(handoff): add PR handoff for check_project_map

* docs(handoff): set PR number 67

* docs(review): fix PR#66 to PR#67 typo in project map and handoff

* fix(ci): ruff lint errors in pipeline-status and project map test

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-07-26 00:07:13 +03:00

95 lines
No EOL
6.6 KiB
Markdown
Raw Permalink 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.

---
pr: 67
title: feat(pipeline): add check_project_map to DOCS phase
---
## Что сделано
- **`.opencode/scripts/pipeline-status.py`** — 3 точечные правки:
- Константа `PROJECT_MAP_DIR = REPO_ROOT / "docs" / "project-map"` (после
`ADR_DIR`, строка 54).
- Функция `check_project_map()` (после `check_adr`) — проверяет
`PROJECT_MAP_DIR.exists()` + `README.md.exists()`, возвращает
DONE/NOT_DONE (без AMBIGUOUS, чисто файловая система). Шаблон по образцу
`check_adr`.
- В `check_docs` вставлен вызов между `check_adr` и
`_check_docs_reviewer_comment` (short-circuit на NOT_DONE). Docstring
`check_docs` обновлён (теперь 5 детерминированных проверок).
- **`tests/test_pipeline_status_project_map.py`** — новый файл, 3 unit-теста
(по образцу `test_pipeline_status_adr.py`):
- `test_project_map_exists` — README.md есть → DONE, "README.md" в detail.
- `test_project_map_dir_missing` — директория отсутствует → NOT_DONE,
"директория" в detail.
- `test_project_map_readme_missing` — директория есть, README.md нет →
NOT_DONE, "README.md не найден" в detail.
Загрузка скрипта под уникальным module name `pipeline_status_project_map`
(не коллидирует с `pipeline_status` из других тестов).
- **`tests/test_pipeline_status.py`** — критическая правка существующих
тестов:
- Добавлен helper `make_project_map(tmp_path)` рядом с `make_handoff`
создаёт `tmp_path/project-map/README.md`.
- Во все 10 `test_check_docs_*` тестов добавлен
`monkeypatch.setattr(ps, "PROJECT_MAP_DIR", make_project_map(tmp_path))`.
Без этого новая под-проверка возвращала NOT_DONE и ломала assertions
(7 тестов с валидным ADR доходили до check_project_map).
- **ADR-028** (`docs/decisions/028-pr-67-project-map-contract.md`) —
фиксирует контракт project-map: README.md обязателен (mandatory, enforced),
модульные файлы и frontmatter `last_updated` — aspirational (не enforced).
Альтернативы: полный контракт (отклонено — блокирует пайплайн, ~12 файлов),
env-flag (отклонено — docs-reviewer автосоздаёт), diff-based (отклонено —
сложнее, не гарантирует валидность).
- **`docs/project-map/README.md`** — секция Update Protocol дополнена строкой
про новый guard; tree обновлён (новый тест-файл + тег PR#67 на
pipeline-status.py).
## Почему
Детерминированный guard для project-map отсутствовал —
`pipeline-status.py:check_docs` проверял handoff, ADR и docs-reviewer
comment, но не валидировал `docs/project-map/`. Это позволяло PR проходить
DOCS-фазу даже при «тихом провале» docs-reviewer (забыл обновить карту при
структурных изменениях). Memory `technical/pipeline-status-no-project-map-check.md`
зафиксировала эту дыру.
Контракт карты был размазан по 3 файлам (`docs-reviewer.md`,
`get-project-map/SKILL.md`, `reviewer.md`) с несоответствиями (2 разных commit
message для одной операции). Фактическое состояние — только README.md без
frontmatter и модульных файлов. ADR-028 ослабляет контракт под фактическое
состояние (README.md mandatory, модульные файлы aspirational) и фиксирует
единый source of truth. Полный контракт остаётся в `get-project-map/SKILL.md`
как рекомендация.
Локальная верификация: 404 теста прошли, coverage 89.19% ≥ 80%
(pipeline-status.py покрыт на 88%).
## Pending
- После merge: фаза MEMORY — обновить memory
`technical/pipeline-status-no-project-map-check.md` секцией Closure (guard
добавлен в PR#67, контракт зафиксирован в ADR-028).
- ADR filename переименован с placeholder `<PR-NUMBER>` на `028-pr-67-project-map-contract.md`
после create_pr (коммит `docs(handoff): set PR number`).
## Watch out
- **10 существующих тестов правлены** — `test_check_docs_*` в
`test_pipeline_status.py` теперь требуют `make_project_map(tmp_path)` +
monkeypatch `PROJECT_MAP_DIR`. Если добавить новый `test_check_docs_*` без
этого — упадёт на NOT_DONE от `check_project_map`. Паттерн: копируй строку
`monkeypatch.setattr(ps, "PROJECT_MAP_DIR", make_project_map(tmp_path))` из
соседнего теста.
- **Уникальный module name в новом тесте** — `pipeline_status_project_map`
(не `pipeline_status`). Если использовать `pipeline_status`, произойдёт
коллизия с `test_pipeline_status.py`/`test_pipeline_status_adr.py` которые
грузят скрипт под тем же именем — `sys.modules` уже занят, тесты
конфликтуют. Шаблон: новый test-файл для под-проверки → уникальный module
name.
- **Контракт ослаблен намеренно** — ADR-028 явно фиксирует что модульные
файлы и frontmatter `last_updated` НЕ enforced. Если будущий PR захочет
ужесточить контракт (полный enforcement) — это будет breaking change,
требующий создания ~12 файлов для существующего репо. См. альтернативу в
ADR-028.
- **scaffold-handoff.sh нумерация** — скрипт считает `ls docs/decisions |
grep -E '^[0-9]{3}-' | wc -l + 1`. Если ADR-028 уже существует, следующий
вызов даст 029. При создании ADR вручную + через scaffold в одном PR —
scaffold создаст дубликат с +1 номером (нужно удалить вручную).