feat(pipeline-oracle): issue-number input, bootstrap NEXT, issues dashboard #74

Closed
opened 2026-08-16 18:05:07 +03:00 by slaid098 · 0 comments
Owner

Контекст

Оракул .opencode/scripts/pipeline-status.py строго PR-центричен: принимает только номер PR. На номере issue он падает PR #N не существует (exit 1) — это ломает bootstrap пайплайна: пайплайн стартует с номера issue, а PR ещё не создан. Маппинга issue→PR нет ни в одном компоненте системы.

Сопутствующие дефекты оракула (зафиксированы аудитом):

  • NEXT_ACTIONS используют плейсхолдер N = номер PR, тогда как в run-pipeline SKILL.md N = номер issue — агенты путают номера.
  • NEXT для фазы CI ссылается на приватную функцию _forgejo_run_view() (агент не может её вызвать) и не указывает subagent_type+template, в отличие от NEXT остальных фаз.
  • Фазы ISSUE/IMPLEMENT могут быть ❌ только при уже существующем PR с битым body, но NEXT предлагает template=A (флоу «с нуля») — риск создания дубль-PR.
  • Оракул эмитит snake_case имена инструментов (call merge_pr tool, pipeline_status проверит CI), тогда как инструменты kebab-case (рецидив после ADR-034).
  • Таймауты рассинхронизированы: description tool'а «5 min», скрипт CI_WAIT_TIMEOUT=420с (7 мин), TS-обёртка 480000мс (8 мин) с текстом ошибки «timed out (60s)».
  • Режим без аргументов (таблица открытых PR) существует в скрипте, но недосягаем через tool (pr_number обязателен в схеме TS-обёртки).
  • Docstring'и фаз используют устаревшую 7-фазную нумерацию («Phase 5: REVIEW», «Phase 6: MERGE», «Phase 7: MEMORY» при реальных 4/5/6).

Задача

  1. Вход оракула — любой номер (issue или PR), детерминированная резолюция:
    • GET /pulls/{N} → 200: текущее поведение без изменений (PR-путь).
    • 404 → GET /issues/{N}:
      • issue существует → поиск среди ОТКРЫТЫХ PR, чьи body содержат Closes|Fixes|Resolves #N:
        • ровно 1 → продолжить по найденному PR, в выводе пометка issue #N → PR #M;
        • 0 → вывести фазы (ISSUE ❌, IMPLEMENT ❌, остальные ❌) и NEXT: dispatch subagent (subagent_type=general, template=A) for issue #N, exit 0 (bootstrap, НЕ ошибка);
        • больше 1 → AMBIGUOUS: <список кандидатов-PR>;
      • номера нет ни среди PR, ни среди issues → stderr Не существует ни PR, ни issue с номером N, exit 1.
  2. Закрытые/слитые PR в резолюции НЕ участвуют — только state=open.
  3. Переписать NEXT_ACTIONS с явными плейсхолдерами типа номера: issue #N для bootstrap ISSUE/IMPLEMENT (когда PR нет), PR #N для всех остальных фаз.
  4. ISSUE-фаза при существующем PR без Closes: NEXT = инструкция дописать Closes #<issue> в body существующего PR (не template=A). Если вход был PR-номером и issue неизвестен — текст без конкретного issue-номера.
  5. CI-NEXT: добавить subagent_type=general, template=D; инструкция получать логи через curl к Forgejo API (/actions/runs/{id}/jobs + /actions/jobs/{id}/logs); убрать упоминание _forgejo_run_view().
  6. snake_case → kebab-case во всех строках, которые читает агент (NEXT и ошибки): merge-pr, pipeline-status и т.д. Обновить тесты, закрепляющие snake-строки.
  7. Таймауты к единообразию: скрипт 420с = 7 мин; wrapper 480000мс = 8 мин запас; тексты описаний привести к фактическим («up to 7 min polling», wrapper error без «60s»). Поправить description tool'а.
  8. .opencode/tools/pipeline-status.ts: сделать pr_number опциональным; вызов без аргумента → дашборд открытых ISSUES репо (номер, title, номер связанного открытого PR или «—»). Существующая таблица открытых PR заменяется этим дашбордом.
  9. Docstring'и проверок фаз: перенумеровать на реальные 1..6.

Контракты

  • PR-вход: поведение фаз и формат вывода как раньше (единственные изменения — kebab-case в строках NEXT/ошибок и явные плейсхолдеры типа номера).
  • Bootstrap-вывод при issue-входе без PR: exit 0 и строка NEXT: dispatch subagent (subagent_type=general, template=A) for issue #N.
  • Дашборд no-arg: стабильный parseable формат (одна строка на issue: #N <title> — PR #M | —).

Инварианты

  • Скрипт остаётся read-only: ни одной мутации Forgejo/git.
  • Порядок и имена фаз (ISSUE=1..MEMORY=6) и иконки ✅/❌/⚠️ не меняются.
  • Обязательность FORGEJO_URL/FORGEJO_TOKEN с явной ошибкой без env — как сейчас.

Граничные случаи

  • Несколько открытых PR закрывают один issue → AMBIGUOUS со списком.
  • Issue существует, а PR только закрытый/слитый → bootstrap NEXT (как при полном отсутствии PR); допустима пометка в выводе о существовании закрытого PR.
  • Нечисловой вход → существующая ошибка «Некорректный номер» без изменений.
  • Один открытый PR упоминает Closes на несколько issues → резолюция идёт от входного номера, конфликта нет.

Влияние на связанные компоненты

  • run-pipeline SKILL.md синхронизируется отдельным issue (зависит от новых NEXT-строк этого issue).
  • .opencode/tools/pipeline-status.ts — сигнатура и description.
  • tests/test_pipeline_status*.py — новые тесты + правка snake-case фикстур.
  • reviewer.md / memory-syncer.md читают вывод оракула — kebab-строки им совместимы.

Вне scope

  • Правки skill'ов run-pipeline / issue / bug-discovery и агентов — отдельные issues.
  • Проверка качества issue (8 SDD-секций в body) в оракуле — сознательно не делаем: валидация уже в create-issue, код не дублируем.

Критерии приемки

  • pytest tests/test_pipeline_status*.py зелёный, включая новые тесты всех веток резолюции: PR-вход; issue→1 PR; issue→0 PR (bootstrap, exit 0); issue→2+ PR (AMBIGUOUS); номер-призрак (exit 1, явный текст); issue с только закрытым PR (bootstrap).
  • В строках NEXT/ошибок нет snake_case имён инструментов (grep-проверка: merge_pr, pipeline_status отсутствуют в эмитимом выводе).
  • Тексты таймаутов согласованы: нет «5 min» и «60s» там, где фактически 7/8 минут.
  • Docstring'и фаз перенумерованы 1..6.
  • Вызов tool'а без pr_number возвращает дашборд открытых issues.
## Контекст Оракул `.opencode/scripts/pipeline-status.py` строго PR-центричен: принимает только номер PR. На номере issue он падает `PR #N не существует` (exit 1) — это ломает bootstrap пайплайна: пайплайн стартует с номера issue, а PR ещё не создан. Маппинга issue→PR нет ни в одном компоненте системы. Сопутствующие дефекты оракула (зафиксированы аудитом): - `NEXT_ACTIONS` используют плейсхолдер `N` = номер PR, тогда как в run-pipeline SKILL.md `N` = номер issue — агенты путают номера. - NEXT для фазы CI ссылается на приватную функцию `_forgejo_run_view()` (агент не может её вызвать) и не указывает `subagent_type`+`template`, в отличие от NEXT остальных фаз. - Фазы ISSUE/IMPLEMENT могут быть ❌ только при уже существующем PR с битым body, но NEXT предлагает `template=A` (флоу «с нуля») — риск создания дубль-PR. - Оракул эмитит snake_case имена инструментов (`call merge_pr tool`, `pipeline_status проверит CI`), тогда как инструменты kebab-case (рецидив после ADR-034). - Таймауты рассинхронизированы: description tool'а «5 min», скрипт `CI_WAIT_TIMEOUT=420`с (7 мин), TS-обёртка `480000`мс (8 мин) с текстом ошибки «timed out (60s)». - Режим без аргументов (таблица открытых PR) существует в скрипте, но недосягаем через tool (`pr_number` обязателен в схеме TS-обёртки). - Docstring'и фаз используют устаревшую 7-фазную нумерацию («Phase 5: REVIEW», «Phase 6: MERGE», «Phase 7: MEMORY» при реальных 4/5/6). ## Задача 1. Вход оракула — любой номер (issue или PR), детерминированная резолюция: - `GET /pulls/{N}` → 200: текущее поведение без изменений (PR-путь). - 404 → `GET /issues/{N}`: - issue существует → поиск среди ОТКРЫТЫХ PR, чьи body содержат `Closes|Fixes|Resolves #N`: - ровно 1 → продолжить по найденному PR, в выводе пометка `issue #N → PR #M`; - 0 → вывести фазы (ISSUE ❌, IMPLEMENT ❌, остальные ❌) и `NEXT: dispatch subagent (subagent_type=general, template=A) for issue #N`, exit 0 (bootstrap, НЕ ошибка); - больше 1 → `AMBIGUOUS: <список кандидатов-PR>`; - номера нет ни среди PR, ни среди issues → stderr `Не существует ни PR, ни issue с номером N`, exit 1. 2. Закрытые/слитые PR в резолюции НЕ участвуют — только state=open. 3. Переписать `NEXT_ACTIONS` с явными плейсхолдерами типа номера: `issue #N` для bootstrap ISSUE/IMPLEMENT (когда PR нет), `PR #N` для всех остальных фаз. 4. ISSUE-фаза при существующем PR без `Closes`: NEXT = инструкция дописать `Closes #<issue>` в body существующего PR (не template=A). Если вход был PR-номером и issue неизвестен — текст без конкретного issue-номера. 5. CI-NEXT: добавить `subagent_type=general, template=D`; инструкция получать логи через curl к Forgejo API (`/actions/runs/{id}/jobs` + `/actions/jobs/{id}/logs`); убрать упоминание `_forgejo_run_view()`. 6. snake_case → kebab-case во всех строках, которые читает агент (NEXT и ошибки): `merge-pr`, `pipeline-status` и т.д. Обновить тесты, закрепляющие snake-строки. 7. Таймауты к единообразию: скрипт 420с = 7 мин; wrapper 480000мс = 8 мин запас; тексты описаний привести к фактическим («up to 7 min polling», wrapper error без «60s»). Поправить description tool'а. 8. `.opencode/tools/pipeline-status.ts`: сделать `pr_number` опциональным; вызов без аргумента → дашборд открытых ISSUES репо (номер, title, номер связанного открытого PR или «—»). Существующая таблица открытых PR заменяется этим дашбордом. 9. Docstring'и проверок фаз: перенумеровать на реальные 1..6. ## Контракты - PR-вход: поведение фаз и формат вывода как раньше (единственные изменения — kebab-case в строках NEXT/ошибок и явные плейсхолдеры типа номера). - Bootstrap-вывод при issue-входе без PR: exit 0 и строка `NEXT: dispatch subagent (subagent_type=general, template=A) for issue #N`. - Дашборд no-arg: стабильный parseable формат (одна строка на issue: `#N <title> — PR #M | —`). ## Инварианты - Скрипт остаётся read-only: ни одной мутации Forgejo/git. - Порядок и имена фаз (ISSUE=1..MEMORY=6) и иконки ✅/❌/⚠️ не меняются. - Обязательность `FORGEJO_URL`/`FORGEJO_TOKEN` с явной ошибкой без env — как сейчас. ## Граничные случаи - Несколько открытых PR закрывают один issue → AMBIGUOUS со списком. - Issue существует, а PR только закрытый/слитый → bootstrap NEXT (как при полном отсутствии PR); допустима пометка в выводе о существовании закрытого PR. - Нечисловой вход → существующая ошибка «Некорректный номер» без изменений. - Один открытый PR упоминает `Closes` на несколько issues → резолюция идёт от входного номера, конфликта нет. ## Влияние на связанные компоненты - run-pipeline SKILL.md синхронизируется отдельным issue (зависит от новых NEXT-строк этого issue). - `.opencode/tools/pipeline-status.ts` — сигнатура и description. - `tests/test_pipeline_status*.py` — новые тесты + правка snake-case фикстур. - reviewer.md / memory-syncer.md читают вывод оракула — kebab-строки им совместимы. ## Вне scope - Правки skill'ов run-pipeline / issue / bug-discovery и агентов — отдельные issues. - Проверка качества issue (8 SDD-секций в body) в оракуле — сознательно не делаем: валидация уже в create-issue, код не дублируем. ## Критерии приемки - `pytest tests/test_pipeline_status*.py` зелёный, включая новые тесты всех веток резолюции: PR-вход; issue→1 PR; issue→0 PR (bootstrap, exit 0); issue→2+ PR (AMBIGUOUS); номер-призрак (exit 1, явный текст); issue с только закрытым PR (bootstrap). - В строках NEXT/ошибок нет snake_case имён инструментов (grep-проверка: `merge_pr`, `pipeline_status` отсутствуют в эмитимом выводе). - Тексты таймаутов согласованы: нет «5 min» и «60s» там, где фактически 7/8 минут. - Docstring'и фаз перенумерованы 1..6. - Вызов tool'а без `pr_number` возвращает дашборд открытых issues.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
slaid098/opencode-config#74
No description provided.