* 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>
5.1 KiB
ADR-028: Project map contract (mandatory README.md, aspirational modules)
Статус
Accepted (2026-07-25)
Контекст
Контракт docs/project-map/ в репо slaid098/opencode-config размазан по 3
файлам с внутренними несоответствиями:
.opencode/agents/docs-reviewer.md:158-159,191— обязывает docs-reviewer обновлять карту при структурных изменениях и предлагает один commit message..opencode/skills/get-project-map/SKILL.md:25-27— описывает структуру карты (README.md + модульные файлы per module) и frontmatterlast_updated..opencode/agents/reviewer.md:199-205— требует от code-reviewer проверять актуальность карты и предлагает другой commit message для той же операции (несоответствие с docs-reviewer.md).
Фактическое состояние карты: только README.md (~140 строк, ASCII-дерево
структуры репо) без frontmatter и без модульных файлов. Полный контракт
(модульные файлы per module) никогда не соблюдался — aspirational документ,
не enforcement.
pipeline-status.py:check_docs (DOCS phase) валидировал handoff (4 секции),
ADR (filename pattern) и docs-reviewer comment (heading ## Docs Review Summary), но не валидировал docs/project-map/. Это позволяло PR проходить
DOCS-фазу даже при «тихом провале» docs-reviewer (забыл обновить карту при
структурных изменениях) — детерминированный guard отсутствовал. Зафиксировано
в memory technical/pipeline-status-no-project-map-check.md.
Решение
Минимальный guard в pipeline-status.py — новая функция check_project_map()
проверяет существование docs/project-map/README.md (через
PROJECT_MAP_DIR.exists() + README.md.exists()). Встроена в check_docs
между check_adr и _check_docs_reviewer_comment (short-circuit на
NOT_DONE). Mandatory для pipeline-driven репо: docs-reviewer автосоздаёт
initial README.md при отсутствии каталога (docs-reviewer.md:82-84), поэтому
guard не блокирует первый PR и не требует ручной bootstrap-операции.
Контракт ослаблен под фактическое состояние:
- README.md обязателен — единственное, что проверяется детерминированно. Возвращает DONE с размером файла в detail, либо NOT_DONE с указанием что docs-reviewer должен создать (с ссылками на строки docs-reviewer.md).
- Модульные файлы per module и frontmatter
last_updated— aspirational, НЕ enforced. Полный контракт остаётся вget-project-map/SKILL.mdкак рекомендация для docs-reviewer, но не блокирует пайплайн.
Возвращает только DONE/NOT_DONE (без AMBIGUOUS) — проверка файловой системы детерминирована, нет внешних API вызовов.
Альтернативы
-
Полный контракт (модульные файлы per module) — отклонено: потребовало бы создания ~12 новых файлов (по одному на модуль) для существующего репо, блокируя пайплайн до их создания. Фактическое состояние никогда не соответствовало этому контракту — enforcement сломал бы все открытые PR.
-
Опциональность через env-flag
OPENCODE_REQUIRE_PROJECT_MAP— отклонено: docs-reviewer уже автосоздаёт initial README.md при отсутствии каталога (docs-reviewer.md:82-84), feature-flag избыточен — guard никогда не блокирует корректно настроенный pipeline-driven репо. Env-flag добавил бы конфигурационную поверхность без выгоды. -
Diff-based проверка (карта обновлена в PR через
gh pr view --json files) — отклонено: сложнее в реализации (парсинг diff, фильтр по путям), не гарантирует валидность содержимого (файл может быть изменён, но остаться пустым/устаревшим). Существование README.md — более сильный guard (файл присутствует), diff-based — слабее (файл изменён, но может быть невалиден).