fix: вердикт broken-repo-paths не зависит от личных настроек git; пробелы в TODO() #30
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/deterministic-verdict-todo-spaces"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Закрывает #27 — два независимых пункта, оба пришли из тела #11.
1. Гейт, который у двух людей отвечает по-разному
no-broken-repo-pathsспрашиваетgit check-ignore, а тот учитывает глобальныйcore.excludesFile. Значит путь, добавленный в личный игнор-файл, переводил хук с FAIL на pass — не оставляя следа ни в диффе, ни в конфиге репозитория. У разработчика зелено, в CI красно, и разница не видна нигде.Замерил на временном репозитории: с подсунутым глобальным
excludesFileбитый путь переставал быть нарушением. Теперь git вызывается сGIT_CONFIG_GLOBALиGIT_CONFIG_SYSTEMв/dev/null— и вcheck-ignore, и вrev-parse(глобальныйcore.worktreeсдвинул бы корень резолва, а от него зависит, какой путь считается существующим)..git/info/excludeтак не отключается — git читает его всегда, опции для этого нет. Записал в README как оставшееся ограничение, с честной оговоркой: файл локален для клона и, в отличие от глобального конфига, не приезжает вместе с настройками пользователя на другую машину.2.
TODO (#456)принимался,TODO( #456 )— нетАсимметрия, которая нигде не описана: пробел перед скобкой и вокруг запятой regex допускал, а сразу после открывающей скобки и перед закрывающей — нет. Разработчик, поставивший пробел внутри скобок, получал FAIL на формате, который выглядит легальным.
Выбрал «разрешить везде»: правило про формат ссылки, а не про пунктуацию вокруг неё. Паттерн синхронизирован в обоих местах — pygrep-хук
todo-needs-issueи исключениеTODO_REвno-issue-refs-in-comments. Два хука обязаны говорить об одном формате одно и то же, иначеTODO( #456 )проходит у одного и падает у другого.Что осталось запрещённым — без изменений:
TODOбез ссылки и префиксная формаTODO(ns/proj#N).Проверка
broken_paths_ignores_global_excludesподнимает git с подсунутымexcludesFile, который «прощает» битый путь: вердикт обязан не измениться. Мутация «убрать отключение конфига» роняет кейс.todo_needs_issue_inner_spaces_cleanиissue_refs_todo_spaces_clean— обе формы у обоих хуков. Мутация «вернуть запрет пробелов внутри скобок» роняет первый.Версия
0.21.0→0.22.0. На тот же номер претендует #29 — тот, что уйдёт вторым, станет0.23.0. Забавно, что именно #29 и заводит CI-гейт, который такие коллизии впредь ловит автоматически.543f1114d99b7e3f39dd9b7e3f39dd3c3292ba03Ревью (субагент, свежий контекст): блокер подтверждён и исправлен — вместе с ним ушли ещё две неточности, которые я в первой редакции написал уверенно и неверно.
B1 — снос конфига забирал
safe.directory. Проверил: он читается только из protected-конфига, так чтоGIT_CONFIG_GLOBAL=/dev/null+GIT_CONFIG_SYSTEM=/dev/nullвыкидывает и то, что кладёт тудаactions/checkout. В контейнере с UID-mismatch каждый вызов git отвечал бы 128, а хук трактует ненулевой код как «путь не игнорируется» — то есть я обменял бы одну недетерминированность на волну ложных FAIL'ов, причём молча.Заменено на
git -c core.excludesFile=/dev/null. Проверил, что это строго лучше: перебивает все уровни, включая локальный.git/config(который снос конфига не трогал вовсе — нит 1 закрыт заодно), иsafe.directoryостаётся на месте.Две мои формулировки оказались неверными, обе сняты:
-cуrev-parseзащищает от глобальногоcore.worktree» — проверил,core.worktreeиз глобального конфига наrev-parse --show-toplevelне влияет. Флаги оставлены на всех вызовах ради единообразия, но обоснование теперь честное: «сегодня ручка влияет только наcheck-ignore, флаги едины, чтобы следующая команда не осталась без них».diff.external» — да, гасило, но моя замена на-c diff.external=ломает git: он пытается выполнить пустую команду и падает. Правильный инструмент —--no-ext-diffу самой командыdiff, добавлен.Ниты:
core.excludesFile. Мутации «убрать-cу check-ignore» и «убратьcore.excludesFileиз списка» роняют по два кейса.run_case_outс пином пути в выводе (трейсбек давал тот же exit=1) и&&вместо;между setup и запуском.no-issue-refs-in-commentsв манифесте теперь говорит про пробелы: весь смысл правки в том, что два хука обязаны говорить об одном формате одно и то же.TODO( # 456 )остаётся нарушением,# 456— не ссылка. Мутация «разрешить пробел внутри ссылки» роняет новый кейс.TODO(arg, #42, ...), который regex отвергает сv0.11.0; это ровно тот дефект, на который жалуется issue, — переписано.-c: флаг поддерживается всеми живыми версиями git, no-op'а из-за старого git больше нет.Про кейс на
--no-ext-diffотдельно. Первые две редакции были вакуумными: при сломанном diff нарушения не появляются, а исчезают, поэтому кейс с ожиданием 0 проходил в обе стороны. Правильный кейс ожидает 1 на branch-долге: регрессия здесь — пропажа вердикта, а не его появление. Мутация ловится только в такой постановке.V1 — ветка отребейзена и force-запушена, версия
0.23.0, гейт из #29 на ней зелёный. Тегv0.23.0поставлю сразу после мержа.