opencode-config/docs/handoff/pr-46-review-posting-tools.md
Sergey 1acac5229f
feat(tools): deterministic review posting tools (post-review, post-docs-review) (#46)
* feat(tools): add post-review and post-docs-review tools

* refactor(agents): use post-review/post-docs-review tools in reviewer and docs-reviewer

* feat(permissions): add post_review and post_docs_review to agent.tools map

* test(tools): add tests for post-review and post-docs-review tools

* docs(handoff): add handoff ADR and project-map for review posting tools

* docs(handoff): set PR number

* docs: fix PR#45→PR#46 refs in project map

---------

Co-authored-by: opencode-agent <agent@slaid098.dev>
2026-07-24 18:26:48 +03:00

7.8 KiB
Raw Permalink Blame History

pr_number title
46 Deterministic review posting tools (post-review, post-docs-review)

PR: Deterministic review posting tools (post-review, post-docs-review)

Что сделано

  • .opencode/tools/post-review.ts — TS tool wrapper (3 args: pr_number, verdict enum, body). Генерирует comment ## Code Review Summary\n\n${body}\n\n### Verdict: ${verdict}. Вызывает gh pr comment N --body <comment> --repo slaid098/opencode-config через spawnSync. Verdict enum: APPROVE, REQUEST_CHANGES, NEEDS_DISCUSSION. Паттерн merge-pr.ts (spawnSync, cwd: context.worktree).
  • .opencode/tools/post-docs-review.ts — TS tool wrapper (3 args: pr_number, verdict enum, body). Генерирует comment ## Docs Review Summary\n\n${body}\n\n### Verdict: ${verdict}. Вызывает gh pr comment N --body <comment> --repo slaid098/opencode-config через spawnSync. Verdict enum: APPROVE, FIXED, NO_CHANGES.
  • .opencode/agents/reviewer.md — секция "Output Format" переписана: gh pr commentpost_review({ pr_number, verdict, body }). Tool auto-generates heading + verdict line, body — содержимое между ними. 3 сценария (APPROVE/REQUEST_CHANGES/NEEDS_DISCUSSION). Frontmatter description + Rules 7/8 обновлены.
  • .opencode/agents/docs-reviewer.md — секция "PR Comment (mandatory)" переписана: gh pr commentpost_docs_review({ pr_number, verdict, body }). Frontmatter description обновлён.
  • .opencode/opencode.jsonagent.tools map расширен: post_review + post_docs_review добавлены для 4 агентов (general/reviewer/docs-reviewer/memory-syncer). reviewer: post_review=true, post_docs_review=false; docs-reviewer: post_review=false, post_docs_review=true; general+memory-syncer: оба false.
  • tests/_ts_loader.mjs — zodShim расширен методом enum: () => chain() (для tool.schema.enum(VERDICTS)). stripTs расширен: strip as const assertions + strip type <Name> = ... type alias declarations (TS-only синтаксис, используется в новых tools).
  • tests/test_post_review_tool.ts — 7 TS тестов (документационные): valid APPROVE/REQUEST_CHANGES/NEEDS_DISCUSSION, invalid verdict, heading, verdict line, spawnSync args.
  • tests/test_post_docs_review_tool.ts — 7 TS тестов: valid APPROVE/FIXED/NO_CHANGES, invalid verdict, heading, verdict line, spawnSync args.
  • tests/test_post_review_tool.py — 12 Python тестов через _ts_loader.mjs (exec_stub_json): load, 3 valid verdicts, invalid verdict (permissive — zod validates, not execute), heading, 3 verdict lines, spawnSync args, cwd propagation, gh failure.
  • tests/test_post_docs_review_tool.py — 12 Python тестов: load, 3 valid verdicts, invalid verdict, heading, 3 verdict lines, spawnSync args, cwd propagation, gh failure.
  • docs/project-map/README.md — обновлён: новые tools (post-review.ts, post-docs-review.ts), новые тесты, обновлённые описания agents (reviewer/docs-reviewer используют post_review/post_docs_review tools).
  • ADR-019 + этот handoff

Почему

Reviewer и docs-reviewer постят комментарии через raw gh pr comment с ручным форматированием heading + verdict. pipeline-status.py парсит эти комментарии regex'ами (REVIEW_VERDICT_RE = re.compile(r"## Code Review Summary.*?###\s*Verdict:\s*(\w+)"), DOCS_REVIEW_RE = re.compile(r"Docs Review")). Риски:

  1. Reviewer случайно использует wrong heading → pipeline NOT_DONE (блокировка)
  2. Verdict опечатан (например APROVE вместо APPROVE) → regex не матчит → NOT_DONE
  3. Нет mutual exclusion между review и docs-review комментариями
  4. DOCS_REVIEW_RE — substring match, теоретический false positive если любой комментарий упомянет "Docs Review"

Решение: детерминированные TS tools, которые гарантируют heading + verdict формат через type system (zod enum). Tool принимает body БЕЗ heading — heading auto-generated. Это устраняет root cause ошибок форматирования: агент не может опечататься в heading или verdict, т.к. они генерируются кодом, не промптом.

Паттерн merge-pr.ts (PR#30, ADR-010): thin TS wrapper → spawnSync → context.worktree как cwd. Tools auto-discovered через @opencode-ai/plugin. agent.tools map в opencode.json контролирует role-based access (reviewer → post_review, docs-reviewer → post_docs_review, general+memory-syncer → none).

Pending

  • Skills/AGENTS.md правила форматов reviews теперь дублируются (agents текст + tools код). Future PR может заменить agents rules на "use post_review/post_docs_review tools" references.
  • gh pr comment* permission в reviewer.md/docs-reviewer.md frontmatter оставлен — tools вызывают spawnSync напрямую (не через bash permission layer). Если захотеть запретить raw gh pr comment (принудить к tool) — добавить deny правило. Сейчас оба пути работают.
  • pipeline-status.py regex'ы НЕ изменены (tools совместимы с существующим парсингом — генерируют ровно тот формат, который regex ожидает).

Watch out

  • _ts_loader.mjs zodShim НЕ валидирует enum (chainable builder без checks) — enum validation происходит в opencode runtime (zod), НЕ внутри execute(). Тест test_invalid_verdict_not_validated_by_execute документирует: execute() permissive, guard в zod schema. Это intentional — не дублировать валидацию в execute().
  • _ts_loader.mjs stripTs расширен для as const и type <Name> = ... — TS-only синтаксис, которого не было в предыдущих tools (commit/create-pr/create-issue/merge-pr не используют type aliases). Если будущие tools добавят другие TS-only конструкции (interface, generic, etc.) — stripTs нужно будет расширить дальше.
  • post-review.ts / post-docs-review.ts хардкодят --repo slaid098/opencode-config (как merge-pr.ts хардкодил --squash --delete-branch). Для других репо tools нужно параметризовать или создать копии. Альтернатива (через git remote) — out of scope этого PR (см. ADR-007 для паттерна параметризации).
  • gh pr comment* в allow-list reviewer.md/docs-reviewer.md остался — tools используют spawnSync (не bash permission layer), так что raw gh pr comment всё ещё доступен агенту. Это intentional для обратной совместимости (fallback). Запретить raw можно отдельным PR если захотеть strict tool-only.
  • ADR number = sequential (019), НЕ PR number. Эволюция известного паттерна (PR#26 docs-reviewer typo — записал PR number как ADR number).
  • TS-тесты (test_*.ts) — документационные, CI гоняет Python-версии через _ts_loader.mjs (bun нет на runner).
  • 347 тестов всего (323 существующих + 24 новых), все green. ruff check passes.