- шаг 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 и перестал собираться, а восемь шагов гейта и шесть проходов ревью были зелёными
5.1 KiB
ADR-2026-08-12. Объявленную версию Go шаг гейта читает из репозитория, а не спрашивает у инструмента
- Дата: 2026-08-12
- Источник: openspec/changes/archive/2026-08-12-go-1-26-upgrade/design.md, раздел
Decisions, Решения 1 и 6
Решение
Шаг сверки версий добывает числа чтением файлов и не зовёт go ни в каком
виде — ни go mod edit -json, ни go list -m, ни go env. Директива
toolchain в go.mod при этом запрещена: её наличие роняет шаг.
Дословно из источника:
Способ это не самый удобный: разбор директивы через
go mod edit -jsonкороче и надёжнее регулярного выражения. Он же и опасный: вызовgoтянет за собойGOTOOLCHAIN,$PATHи установленный тулчейн, а при непустомGOTOOLCHAINgoвправе полезть в сеть за нужной версией — то есть требование «без сети» перестало бы выполняться. Хуже того, исход шага стал бы зависеть от машины, а не от коммита.
Почему
Причина не в аккуратности, а в том, что ровно этой подменой и держался дефект,
ради которого шаг заведён. 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в гейт не заведён, тестов у него нет. Из девятнадцати сценариев нормы машина гоняет один — тот, где всё сошлось. Остаток объявлен и уехал отдельной задачей.