Files
transcriber/docs/adr/ADR-2026-08-12-version-read-from-repo-not-from-tool.md
T
av 09228f23d8 Go обновлён до 1.26, а расхождение версий теперь роняет гейт
- шаг go-version в task gate сверяет объявленную версию в go.mod, Dockerfile,
  CLAUDE.md и README.md; судит по репозиторию, go не зовёт, docker и сети не
  требует
- заведена capability toolchain: до сих пор спеки нормировали только поведение
  сервиса, теперь и инструмент сборки. Причина и цена — в двух ADR
- закрыт дефект 2026-08-12: образ на golang:1.24-alpine разошёлся с go.mod и
  перестал собираться, а восемь шагов гейта и шесть проходов ревью были зелёными
2026-08-12 10:57:50 +03:00

5.1 KiB
Raw Blame History

ADR-2026-08-12. Объявленную версию Go шаг гейта читает из репозитория, а не спрашивает у инструмента

Решение

Шаг сверки версий добывает числа чтением файлов и не зовёт go ни в каком виде — ни go mod edit -json, ни go list -m, ни go env. Директива toolchain в go.mod при этом запрещена: её наличие роняет шаг.

Дословно из источника:

Способ это не самый удобный: разбор директивы через go mod edit -json короче и надёжнее регулярного выражения. Он же и опасный: вызов go тянет за собой GOTOOLCHAIN, $PATH и установленный тулчейн, а при непустом GOTOOLCHAIN go вправе полезть в сеть за нужной версией — то есть требование «без сети» перестало бы выполняться. Хуже того, исход шага стал бы зависеть от машины, а не от коммита.

Почему

Причина не в аккуратности, а в том, что ровно этой подменой и держался дефект, ради которого шаг заведён. 2026-08-12 требование модуля уехало на 1.25, сборочный образ остался на 1.24, образ перестал собираться — и восемь шагов гейта с шестью проходами ревью показали зелёное, потому что go build ./... шёл на хостовом Go. Проверка судила по тому, что стоит на машине, вместо того что записано в коммите. Шаг, зовущий go, воспроизвёл бы ту же подмену внутри себя: зелёный там, где стоит нужная версия, и другой ответ на другой машине.

Отсюда же запрет toolchain. Директива — штатный механизм Go и очевидное решение задачи расхождения: она заставила бы Go скачать нужную версию самому, и сверять стало бы нечего. Отвергнута намеренно:

Директива toolchain заставила бы Go скачивать нужный тулчейн сам, и расхождение с образом перестало бы ломать сборку. Но она же превращает сборку образа в сетевую операцию, а сборочный слой качает тулчейн при каждой сборке. Дороже и менее предсказуемо, чем строка сравнения.

Вдобавок она вводит пятое место, называющее версию, — то, которого закрытый перечень из четырёх мест не знает: при toolchain go1.27.0 четыре объявленных числа сойдутся, а собирать будет пятое.

Последствия

  • + исход шага есть функция коммита. Проверено прогоном: с PATH, где нет go, шаг даёт тот же код выхода и тот же вывод.
  • + требование «без сети» выполняется по построению, а не обещанием: под strace шаг не делает ни одного сетевого вызова.
  • + пятое место закрыто: toolchain в go.mod роняет шаг с названной причиной.
  • разбор держится на регулярных выражениях sed/awk вместо готового разбора, который дал бы сам go. Это дороже в сопровождении и хрупче: правка образца ломает смежный случай беззвучно.
  • запрет toolchain придётся снять или пересмотреть, если зависимость однажды потребует версию выше той, что стоит у нас. Тогда эта запись пересматривается, а не обходится.
  • проверять сам скрипт нечем: shellcheck в гейт не заведён, тестов у него нет. Из девятнадцати сценариев нормы машина гоняет один — тот, где всё сошлось. Остаток объявлен и уехал отдельной задачей.