fix(pipeline-status): ignore issue refs inside code spans in PR body #93

Closed
opened 2026-08-16 20:57:27 +03:00 by slaid098 · 0 comments
Owner

Контекст

PR #92 (test: regression guard для дубликатов Closes) упал в ложный AMBIGUOUS: оракул распознал цитаты тестовых данных в body PR — `Closes #45 Closes #45`, `Closes #45 Fixes #47` — как реальные Closes-связи к issue #45/#47. Реальные привязки были только к #86 (автогенерированный Closes #86). Итог: «несколько issue в body» → AMBIGUOUS → батч остановлен, PR ожидает правки body вручную.

Корень: regex резолюции issue в pipeline-status.py матчит #N по всему телу PR без учёта markdown-контекста. Агенты часто цитируют примеры body-строк в описании PR — это класс ложных срабатываний.

Задача

Научить оракул игнорировать упоминания #N внутри code-спанов (backtick-спаны `...`, многострочные блоки ```) и блочных цитат (>) при резолюции issue по PR body. Реальный Closes #N вне этих конструкций матчится как раньше.

Альтернатива (НЕ предпочтительная): экранирование в create-pr — хрупко, не защищает от правок body вручную. Выбран путь оракула.

Контракты

  • Closes #N / Fixes #N / Resolves #N вне code-спанов и цитат → резолюция как раньше (ISSUE DONE).
  • Упоминания #N внутри backtick-спанов, многострочных code-блоков и строк > → не влияют на резолюцию.
  • AMBIGUOUS «несколько issue в body» сохраняется для реальных нескольких привязок.

Инварианты

  • Поведение оракула для тестов из #86 (дубликат одного номера → DONE, разные номера без спанов → AMBIGUOUS) не меняется.
  • Формат вывода фазы ISSUE и NEXT-строк не меняется.

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

  • Однострочный спан: body содержит `Closes #45` в примере → не матч.
  • Многострочный блок: \nCloses #45\n → не матч.
  • Цитата: > Closes #45 → не матч.
  • Незакрытый backtick — трактовать как текст (спан не начинается).
  • Реальный Closes #45 в обычном тексте рядом с цитатой → матч.
  • Упоминание без ключевого слова (см. #45) — вне scope (и так не матчится).

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

  • pipeline-status.py (функция резолюции issue) + tests/test_pipeline_status.py.
  • Оба файла также меняет #86 (PR #92) — исполнять ПОСЛЕ мержа #86 (конфликт по файлу тестов).
  • TS-обёртка pipeline-status.ts не меняется (контракт NEXT/verdict тот же).

Вне scope

  • Правка body уже существующих PR (чинится вручную при необходимости).
  • Аналогичный парсинг title PR (оракул его не использует).
  • Валидация markdown-разметки в целом.

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

  • Тест: body с `Closes #45` в backtick-спане + Closes #86 в тексте → ISSUE DONE (#86), не AMBIGUOUS.
  • Тест: многострочный code-блок и цитата с Closes #N → не влияют.
  • Существующие тесты резолюции (#86, #46/45/47 кейсы) зелёные.
  • pytest и CI зелёные.
## Контекст PR #92 (test: regression guard для дубликатов Closes) упал в ложный AMBIGUOUS: оракул распознал цитаты тестовых данных в body PR — `` `Closes #45 Closes #45` ``, `` `Closes #45 Fixes #47` `` — как реальные Closes-связи к issue #45/#47. Реальные привязки были только к #86 (автогенерированный `Closes #86`). Итог: «несколько issue в body» → AMBIGUOUS → батч остановлен, PR ожидает правки body вручную. Корень: regex резолюции issue в `pipeline-status.py` матчит `#N` по всему телу PR без учёта markdown-контекста. Агенты часто цитируют примеры body-строк в описании PR — это класс ложных срабатываний. ## Задача Научить оракул игнорировать упоминания `#N` внутри code-спанов (backtick-спаны `` `...` ``, многострочные блоки ```) и блочных цитат (`>`) при резолюции issue по PR body. Реальный `Closes #N` вне этих конструкций матчится как раньше. Альтернатива (НЕ предпочтительная): экранирование в `create-pr` — хрупко, не защищает от правок body вручную. Выбран путь оракула. ## Контракты - `Closes #N` / `Fixes #N` / `Resolves #N` вне code-спанов и цитат → резолюция как раньше (ISSUE DONE). - Упоминания `#N` внутри backtick-спанов, многострочных code-блоков и строк `>` → не влияют на резолюцию. - AMBIGUOUS «несколько issue в body» сохраняется для реальных нескольких привязок. ## Инварианты - Поведение оракула для тестов из #86 (дубликат одного номера → DONE, разные номера без спанов → AMBIGUOUS) не меняется. - Формат вывода фазы ISSUE и NEXT-строк не меняется. ## Граничные случаи - Однострочный спан: `` body содержит `Closes #45` в примере `` → не матч. - Многострочный блок: ```\nCloses #45\n``` → не матч. - Цитата: `> Closes #45` → не матч. - Незакрытый backtick — трактовать как текст (спан не начинается). - Реальный `Closes #45` в обычном тексте рядом с цитатой → матч. - Упоминание без ключевого слова (`см. #45`) — вне scope (и так не матчится). ## Влияние на связанные компоненты - `pipeline-status.py` (функция резолюции issue) + `tests/test_pipeline_status.py`. - Оба файла также меняет #86 (PR #92) — исполнять ПОСЛЕ мержа #86 (конфликт по файлу тестов). - TS-обёртка `pipeline-status.ts` не меняется (контракт NEXT/verdict тот же). ## Вне scope - Правка body уже существующих PR (чинится вручную при необходимости). - Аналогичный парсинг title PR (оракул его не использует). - Валидация markdown-разметки в целом. ## Критерии приемки - Тест: body с `` `Closes #45` `` в backtick-спане + `Closes #86` в тексте → ISSUE DONE (#86), не AMBIGUOUS. - Тест: многострочный code-блок и цитата с `Closes #N` → не влияют. - Существующие тесты резолюции (#86, #46/45/47 кейсы) зелёные. - pytest и CI зелёные.
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#93
No description provided.