diff --git a/.github/workflows/process.yml b/.github/workflows/process.yml index 00525e7d..563aa9e3 100644 --- a/.github/workflows/process.yml +++ b/.github/workflows/process.yml @@ -45,7 +45,6 @@ jobs: env: GH_TOKEN: ${{ secrets.HP_PROCESS_TOKEN }} LABEL: ${{ github.event.label.name }} - AUTHOR: ${{ github.event.issue.user.login }} BLOCKED: ${{ contains(github.event.issue.labels.*.name, 'blocked') }} EXHAUSTED: ${{ contains(github.event.issue.labels.*.name, 'review-4') }} SMALL: ${{ contains(github.event.issue.labels.*.name, 'small') }} @@ -77,19 +76,39 @@ jobs: -q "[.comments[] | select(.body | test(\"Вердикт:\")) | select(.body | test(\"$marker\"))] | length") fi - # В процесс идут только issue, созданные владельцем: репозиторий - # публичный, чужие отчёты бывают невалидны и статусов не несут. + # Отказ обязан быть виден в issue, а не только в логе прогона. + # Ревьюшная метка обещает работу; если конвейер её не начал и промолчал, + # задача стоит в этом статусе бесконечно и никто об этом не узнаёт. + # Так и вышло на #123: чужой issue довели до S4-spec-review, guard + # отказался за 9 секунд, и в issue не было ни слова. + # + # Пишем только когда пытались запустить ревью, то есть stage опознан. + # Иначе комментарий уходил бы на каждую смену любой метки. + refuse() { + echo "$1" + gh issue comment "$NUM" --repo "${{ github.repository }}" --body \ + "Конвейер ревью не запущен: $2 + + Метка \`$LABEL\` обещает работу, которая не начнётся, поэтому статус лучше вернуть в предыдущий — иначе задача простоит здесь бесконечно. [Прогон](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})." + stage="" + } + + # Автор issue здесь не проверяется (решение владельца 2026-08-13). + # Проверка стоит на входе в процесс, а не на каждом шаге: как только + # задача получила статусную метку, она в работе, и кто её завёл — не + # имеет значения. Само присвоение метки и есть явное подтверждение + # владельца, причём проверенное платформой: метки может ставить только + # тот, у кого есть право записи в репозиторий. Прежняя проверка здесь + # дублировала эту гарантию и заставляла переоформлять чужие отчёты + # своими issue — чистая работа впустую, как на #123. if [ -z "$stage" ]; then : - elif [ "$AUTHOR" != "Matysh" ]; then - echo "issue от $AUTHOR, не от владельца — пропуск" - stage="" elif [ "$BLOCKED" = "true" ]; then - echo "стоит blocked — конвейер не запускается" - stage="" + refuse "стоит blocked — конвейер не запускается" \ + "на issue стоит \`blocked\` — задача ждёт внешнего решения. Снять метку, когда решение принято." elif [ "$EXHAUSTED" = "true" ]; then - echo "стоит review-4 — решение за владельцем" - stage="" + refuse "стоит review-4 — решение за владельцем" \ + "на issue стоит \`review-4\`: лимит циклов ревью исчерпан, дальше решает владелец — разделить задачу, отклонить или арбитраж (PROCESS.md §4)." elif [ "$done_cycles" -ge "$limit" ]; then echo "циклов этапа $stage пройдено $done_cycles из $limit — лимит исчерпан" gh issue edit "$NUM" --repo "${{ github.repository }}" --add-label review-4 diff --git a/AGENTS.md b/AGENTS.md index 5a422f52..9c0c5754 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,9 +41,17 @@ of a status and `rejected` on a closed issue. Exactly one `S*` label per open issue. [GitHub Projects (v2)](https://github.com/users/Matysh/projects/1) is a human-facing view synchronised from the labels, not the source of truth. -Only issues **created by the owner** enter the process. The repository is public; -outside reports may be malformed or invalid, carry no status labels, and are not -picked up until the owner converts them into his own issue. +An issue filed by an outsider is worked exactly like one of the owner's own, once +the owner has decided to take it. The check sits **at the entrance**, not on every +step: while an issue carries no status label it is outside the process and the +invariants do not apply to it; once a label is on, the task is in flight and **who +filed it stops mattering**. + +Applying that first label *is* the owner's explicit decision, and the platform +already guarantees it — only someone with write access can label. The earlier rule +made outside reports be refiled as the owner's own issues, which turned out to be +work for nothing: on #123 the spec was already written by the time the guard +refused. Specs, audits and ADRs may live under `docs/`, but must link to their issue and must not become a parallel task list. When repository documentation disagrees with diff --git a/PROCESS.md b/PROCESS.md index 940f5ff1..51c346b3 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -472,12 +472,20 @@ Project v2 остаётся человеческим представление Инварианты: **ровно одна `S*`-метка** на открытом issue; закрытый issue статусных меток не несёт; `blocked` не заменяет статус, а дополняет его. -**В процесс берутся только issue, созданные владельцем** (решение владельца -2026-08-13). Репозиторий публичный, задачи заводят и посторонние; такие issue -бывают плохо оформлены или невалидны, и статусных меток им не ставят — инварианты -на них не распространяются. Проверять `user.login`. Что делать с чужим issue: -прочитать, при необходимости переформулировать и завести **свой** со ссылкой на -исходный, либо оставить до решения владельца. Не размечать и не брать в работу. +**Чужой issue берётся в работу так же, как свой — после явного решения +владельца** (решение владельца 2026-08-13, уточнено в тот же день). Репозиторий +публичный, отчёты заводят и посторонние; проверка стоит **на входе**, а не на +каждом шаге. + +Входом служит присвоение первой статусной метки: пока меток нет, issue вне +процесса и инварианты на него не распространяются. Как только метка стоит, задача +в работе, и **кто её завёл, дальше не имеет значения** — статусы, ревью и лимиты +работают одинаково. + +Присвоение метки и есть то самое явное решение, причём проверенное платформой: +метки может ставить только тот, у кого есть право записи в репозиторий. Прежняя +редакция требовала переоформлять чужой отчёт своим issue со ссылкой на исходный; +это оказалось работой впустую — на #123 к моменту отказа ТЗ уже было написано. `S8-merged` появился позже остальных и закрывает разрыв, который раньше закрывался памятью человека: код принят, но бета ещё не вышла, и issue закрывать