* 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>
6.6 KiB
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). Docstringcheck_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 namepipeline_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).
- Добавлен helper
- ADR-028 (
docs/decisions/028-pr-67-project-map-contract.md) — фиксирует контракт project-map: README.md обязателен (mandatory, enforced), модульные файлы и frontmatterlast_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)+ monkeypatchPROJECT_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 номером (нужно удалить вручную).