feat(ci): упавший прогон называет тесты в самом PR - #1383
Merged
Conversation
Логи джоба и артефакты прогона живут в скоупе `actions`, на который прокси облачной сессии отвечает 403. То есть junit-отчёт отвечает «какой тест упал» только владельцу, у которого есть веб-интерфейс, а тому, кто чинит из облака, достаётся одна строка — `Process completed with exit code 1`. Цена измерена сегодня: причину красных macOS-джобов пришлось искать тремя полными прогонами набора локально, подбирая условия. Открытый канал ровно один — комментарий PR. Отдельный джоб `report-failures` (не шаг в матрице: девять джобов гонялись бы за одним комментарием) разбирает отчёты всех комбинаций и держит в PR ОДНУ сводку, обновляемую по скрытому маркеру. Границы, без которых это стало бы шумом: только на `pull_request` и только при падении `test`; поимённо названы первые 25 упавших, остальные — числом (молчаливая обрезка читалась бы как «это всё»); красный прогон без единого упавшего теста получает отдельную формулировку — он означает смерть до тела тестов. Closes #1382 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com>
ArtVsMark
enabled auto-merge (squash)
August 27, 2026 11:34
ArtVsMark
added a commit
that referenced
this pull request
Aug 27, 2026
`.gitignore` игнорировал `.claude/*` целиком — исключение стояло только на `settings.json`. Настройки честно объявляли `SessionStart`, а файла хука в репозитории не было: он существовал в рабочей копии того окна, где его написали. В чистом клоне и в CI механизма не существовало вовсе, то есть второй рубеж не действовал ни у кого, кроме одного окна. Поймано прогоном на всех девяти комбинациях матрицы: тест звал хук по пути и получал код 2 — «файла нет». Диагноз пришёл сводкой упавших тестов прямо в PR, той самой, что появилась в #1383: логи Actions облачной сессии по-прежнему недоступны, а имя теста было названо через минуту после прогона. Класс закрыт проверкой: `check_rules_digest.py` теперь смотрит не только, что хук объявлен в настройках, но и что файл лежит в репозитории; отдельный тест спрашивает git, отслеживается ли он. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com>
ArtVsMark
added a commit
that referenced
this pull request
Aug 27, 2026
* feat(rules): второй рубеж — правила читаются окном на старте Первый рубеж — механизм: гейт краснеет, и правило действует независимо от памяти окна. Но механизмом покрыто 35 правил из 101 действующих; остальные держатся тем, что окно про них знает, — а знать оно может лишь то, что прочитало. `CLAUDE.md` формулирует немногие, указатель перечисляет заголовки и следы, а сами утверждения живут в каталоге, куда в работе никто не заходит. Дайджест закрывает зазор: утверждение каждого правила одной строкой, `docs/agent/rules/DIGEST.md`. Хук `SessionStart` кладёт его в стартовый контекст — то есть правила оказываются прочитанными раньше, чем окно успеет что-нибудь нарушить. Порядок групп не алфавитный: сначала то, что не поймает машина, потому что правило с гейтом окну помнить не обязательно; у группы с гейтом утверждения нет вовсе — место в стартовом контексте не бесконечно. Ответ каталогу заодно стал полным: нерассмотренных было 43 (30 записей плюс 13 правил без записи вовсе), стало ноль. Разбор шёл по фактам, а не по памяти: каждый ответ проверен grep'ом по предмету, отсюда и рост гейтов с 9 до 35 — не новые механизмы, а увиденные наконец старые. «Ничем не обеспечено» — 60, и это очередь на автоматизацию. Указатель правил впервые за месяц пересобрался: он считал своими следы, ведущие в каталог (правила 049, 140, 142 родились там и держатся его файлами), падал на «след ведёт в никуда» и потому застрял на числах месячной давности — 89 правил и 9 гейтов. Владельца следа теперь задаёт абзац, а не файл целиком. Механизмы: `check_rules_digest.py` (на каждый PR, без сети — дайджест не разошёлся с `.rules/bindings.json`, хук объявлен) и `generate_rules_digest.py --check` в ночном обходе, где есть клон каталога. Часть #1384 — второй рубеж и полнота ответа; покрытие механизмами непокрытых правил идёт отдельно. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com> * fix(rules): хуки харнесса живут в репозитории, а не в рабочей копии `.gitignore` игнорировал `.claude/*` целиком — исключение стояло только на `settings.json`. Настройки честно объявляли `SessionStart`, а файла хука в репозитории не было: он существовал в рабочей копии того окна, где его написали. В чистом клоне и в CI механизма не существовало вовсе, то есть второй рубеж не действовал ни у кого, кроме одного окна. Поймано прогоном на всех девяти комбинациях матрицы: тест звал хук по пути и получал код 2 — «файла нет». Диагноз пришёл сводкой упавших тестов прямо в PR, той самой, что появилась в #1383: логи Actions облачной сессии по-прежнему недоступны, а имя теста было названо через минуту после прогона. Класс закрыт проверкой: `check_rules_digest.py` теперь смотрит не только, что хук объявлен в настройках, но и что файл лежит в репозитории; отдельный тест спрашивает git, отслеживается ли он. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com> * fix(rules): стартовый хук печатает в любой консоли Дайджест русский, а на Windows-раннере кодовая страница западноевропейская — кириллицы в ней нет вовсе. `print` падал `UnicodeEncodeError`, хук возвращал код 1, то есть старт сессии ронялся бы из-за кодировки вывода. На macOS и Linux этого не видно: там UTF-8 по умолчанию. Приём тот же, что у гейтов проекта (#1108): `reconfigure` обоих потоков в UTF-8 раньше первой печати, собственной копией — хук обязан работать там, где пакет не установлен. Тест воспроизводит дефект `PYTHONIOENCODING=cp1252`, а не `cp1251`: в русской консоли кириллица как раз кодируется, и cp1251 показал бы зелёное там, где Windows красная. Проверено полу-откатом: без `_force_utf8_stdio` тест краснеет. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Логи джоба и артефакты прогона живут в скоупе
actions, на который проксиоблачной сессии отвечает 403. То есть junit-отчёт отвечает «какой тест упал»
только владельцу, у которого есть веб-интерфейс, а тому, кто чинит из
облака, достаётся одна строка —
Process completed with exit code 1. Ценаизмерена сегодня: причину красных macOS-джобов пришлось искать тремя полными
прогонами набора локально, подбирая условия.
Открытый канал ровно один — комментарий PR. Отдельный джоб
report-failures(не шаг в матрице: девять джобов гонялись бы за одним комментарием)
разбирает отчёты всех комбинаций и держит в PR ОДНУ сводку, обновляемую по
скрытому маркеру.
Границы, без которых это стало бы шумом: только на
pull_requestи толькопри падении
test; поимённо названы первые 25 упавших, остальные — числом(молчаливая обрезка читалась бы как «это всё»); красный прогон без единого
упавшего теста получает отдельную формулировку — он означает смерть до тела
тестов.
Closes #1382
Работа сделана вместе: @ArtVsMark — постановка, решения и приёмка; Claude Code — реализация.