---
pr: 49
title: remove invalid doom_loop frontmatter field + simplify reviewer setup
---

# PR #49: remove invalid doom_loop frontmatter field + simplify reviewer setup

## Что сделано
- `.opencode/agents/reviewer.md:6` — удалён top-level `doom_loop: deny` (ВНЕ блока `permission:`). Невалидное поле — не в схеме `AgentV2.Info` opencode, форвардилось провайдеру как model param → `AI_APICallError: Extra inputs are not permitted` на строгих провайдерах (umans-ai-coding-plan).
- `.opencode/agents/docs-reviewer.md:6` — удалён top-level `doom_loop: deny` (тот же fix).
- `.opencode/agents/memory-syncer.md:6` — удалён top-level `doom_loop: deny` (тот же fix).
- `permission.doom_loop: deny` ВНУТРИ блока `permission:` — сохранён во всех 3 файлах (валидный permission guard, не тронут).
- `steps: 100` — не изменён во всех 3 файлах.
- `reviewer.md` Setup шаг 5 — упрощён: убрана inline-ссылка на ADR-019 и детальное объяснение запрета `gh pr checks` / `python3 pipeline-status.py`. Заменено на лаконичную инструкцию с `pipeline_status` tool + `gh run list` fallback + явным "Do NOT". Это устраняет self-referential trigger (модель зацикливалась на верификации ADR-019 ссылки — 75 повторений `git show f06c9f2 | grep ADR-019` за 6 минут, doom loop отменён на step 88).
- `reviewer.md` — добавлена секция `## Investigation Budget` после Setup: максимум ~15 steps для investigation, после чего обязательный `post_review` даже при неполном review. Предотвращает бесконечные investigation loops.
- `tests/test_agent_frontmatter.py` — 6 новых тестов: frontmatter НЕ содержит top-level `doom_loop` (parsed + raw check), `permission.doom_loop: deny` присутствует во всех 3 файлах, `steps: 100` присутствует, frontmatter parseable. Парсинг ручной (pyyaml не в зависимостях), по паттерну `check-permissions.py` (split по `---`, отслеживание отступов).
- ADR-020 + этот handoff

## Почему
При review PR #46 (reviewer ревьюил свой собственный .md файл) reviewer agent ушёл в doom loop — 75 повторений `git show f06c9f2 | grep ADR-019` за 6 минут, отменён пользователем на step 88. Investigation выявило 2 проблемы:

1. **`doom_loop: deny` как top-level frontmatter поле** — НЕ в схеме `AgentV2.Info` opencode, форвардится провайдеру как model param → `AI_APICallError` на строгих провайдерах. Валидно только внутри блока `permission:`. Подтверждено логом `opencode.log:91717`. Top-level поле — копия permission guard, ошибочно продублированная на верхний уровень (вероятно при миграции config/ → .opencode/ в PR#23).

2. **Self-referential trigger** — Setup шаг 5 в reviewer.md содержал inline-ссылку на ADR-019 и детальное объяснение запрета. Модель зациклилась на верификации этой ссылки (читает reviewer.md → видит ADR-019 → идёт проверять ссылку → повторяет). Это "крючок", за который модель зацепилась в doom loop.

Решение: удалить невалидное top-level поле (fix root cause #1) + упростить Setup шаг 5 (убрать self-referential hook, fix root cause #2) + добавить Investigation Budget секцию (structural guard против doom loops — явный step limit).

## Pending
— (нет)

## Watch out
- **Top-level `doom_loop` удалён, НЕ `permission.doom_loop`** — `doom_loop: deny` внутри блока `permission:` (отступ 2 пробела, строки 8/8/8) — ОСТАВЛЕН во всех 3 файлах. Это валидный permission guard. Удалён только top-level `doom_loop: deny` (indent 0, строка 6). Тесты `test_permission_doom_loop_present` + `test_no_top_level_doom_loop` явно различают эти два поля.
- **Global config (OLD repo) НЕ обновлён** — bind-mounted `/root/.config/opencode/agents/*.md` (из `/root/workspace/opencode/config/agents/`) всё ещё содержит top-level `doom_loop` (commit 38c5a34 фиксил только NEW repo `.opencode/agents/`). Если strict provider используется в репо БЕЗ project-local agents → falls back to global → bug resurfaces. Это known issue (см. memory: technical/opencode-agent-loading-precedence.md), вне scope этого PR.
- **Investigation Budget — soft guard** — секция в промпте reviewer.md, не type system. Модель может игнорировать ~15 step limit (как игнорирует другие промпт-правила). Но explicit limit лучше implicit — даёт модели чёткий сигнал "остановись и вызови post_review". Hard guard = steps: 100 (frontmatter) — на нём модель упрётся в лимит в любом случае.
- **Setup шаг 5 упрощён, НЕ удалён** — `gh pr checks` (403) и `python3 pipeline-status.py` (denied) запреты сохранены в лаконичной форме ("Do NOT use ..."). Запреты функциональны (permission rules в frontmatter + DANGEROUS_PATTERNS в check-permissions.py), inline-ссылка на ADR-019 — единственное убранное (она была self-referential hook, не функциональным guard).
- ADR number = sequential (020), НЕ PR number (эволюция известного паттерна PR#26 docs-reviewer typo).