diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..153d5e4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,21 @@ +# 決定論ビルドの入力とシェルスクリプトは LF 固定、コミット済みネイティブバイナリは +# 一切変換させない。CRLF で checkout されると `GOTOOLCHAIN=go1.26.5\r` になり +# go が `invalid GOTOOLCHAIN` で即死する(build.sh は Git Bash / WSL も対象)。 + +.go-version text eol=lf + +# build.sh と OS 分岐 dispatcher は sh が解釈するため LF 必須。 +*.sh text eol=lf +*.ps1 text eol=lf +ast-grep/bin/ast-grep text eol=lf +github/bin/github text eol=lf +go-lsp/bin/go-lsp text eol=lf +retro-status/bin/retro-status text eol=lf +settings-advisor/bin/settings-advisor text eol=lf +worktree-manager/bin/worktree-manager text eol=lf +agy-plugin-kit/validator/bin/validator text eol=lf + +# bit-identical な stale 検出ゲートの前提。改行変換もテキスト diff もさせない。 +*-linux-amd64 binary +*-darwin-arm64 binary +*.exe binary diff --git a/.github/workflows/build-verify.yml b/.github/workflows/build-verify.yml index dad5d0f..4fdf1a4 100644 --- a/.github/workflows/build-verify.yml +++ b/.github/workflows/build-verify.yml @@ -16,6 +16,7 @@ on: - 'worktree-manager/**' - 'build.sh' - 'build.ps1' + - '.go-version' - '.github/workflows/build-verify.yml' push: branches: [master] @@ -29,13 +30,13 @@ on: - 'worktree-manager/**' - 'build.sh' - 'build.ps1' + - '.go-version' - '.github/workflows/build-verify.yml' -# 決定論ビルドは Go ツールチェーンのバージョンまで一致が必要。 -# 上げる時はこことローカル環境を揃えて全バイナリを再ビルドすること。 +# 決定論ビルドは Go ツールチェーンのパッチ版まで一致が必要。版の定義は +# リポジトリルートの .go-version 1箇所だけ(build.sh / build.ps1 も同じファイルを読む)。 +# 上げる時は .go-version を書き換え、全バイナリを再ビルドしてコミットすること。 # ビルドフラグ自体は build.sh に集約している(重複定義を避けるため)。 -env: - GO_VERSION: '1.26.5' jobs: github: @@ -47,7 +48,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version - run: go vet ./... - run: go test ./... - name: govulncheck @@ -83,7 +84,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version - run: go vet ./... - run: go test ./... - name: govulncheck @@ -119,7 +120,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version - run: go vet ./... - run: go test ./... - name: govulncheck @@ -155,7 +156,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version - run: go vet ./... - run: go test ./... - name: govulncheck @@ -191,7 +192,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version - run: go vet ./... - run: go test ./... - name: govulncheck @@ -227,7 +228,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version - run: go vet ./... - run: go test ./... - name: govulncheck @@ -263,7 +264,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version - run: go vet ./... - run: go test ./... - name: govulncheck diff --git a/.go-version b/.go-version new file mode 100644 index 0000000..8fe00a5 --- /dev/null +++ b/.go-version @@ -0,0 +1 @@ +1.26.5 diff --git a/AGENTS.md b/AGENTS.md index 773ec7a..95d9425 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -79,7 +79,7 @@ Go ソースを変更したら、リポジトリルートで対象を決定論 ./build.sh ``` -Windows PowerShell では同じ target を `./build.ps1` に渡します。決定論ビルドは `go 1.26.5` を前提とします。ローカル Go バージョンが異なる場合、コミット済みバイナリとの差分を正しい更新とみなさず、使用できなかったことを報告してください。 +Windows PowerShell では同じ target を `./build.ps1` に渡します。決定論ビルドが前提とする Go のパッチ版は `.go-version` に定義され、`build.sh`/`build.ps1` が `GOTOOLCHAIN` で強制します(未取得なら Go が自動ダウンロード)。素の `go build` で焼いたバイナリはローカル Go 版によって別物になるため、必ずビルドスクリプト経由で再ビルドしてください。 ## Verification and Review diff --git a/CLAUDE.md b/CLAUDE.md index 4752e44..3b2faf5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,14 +21,14 @@ Go プラグインは **`src/`(ソース)+ `bin/`(配布物)** に分 cd github/src && go vet ./... && go test ./... cd agy-plugin-kit/validator/src && go vet ./... && go test ./... # 他プラグイン(ast-grep / retro-status / settings-advisor / go-lsp)も同じ流儀(/src で go vet ./... && go test ./...) -# バイナリ再ビルド(go 1.26.5。Windows は ./build.ps1) +# バイナリ再ビルド(Go 版は .go-version に固定。build.sh が GOTOOLCHAIN で強制するため事前準備不要。Windows は ./build.ps1) ./build.sh # 全プラグイン ./build.sh github # github だけ ./build.sh validator # validator だけ # 他ターゲット: ast-grep | retro-status | settings-advisor | go-lsp ``` -**ソース変更時は必ず `./build.sh` で再ビルドしてコミット**(`agy plugin install` はビルドせず git 追跡バイナリをコピーするだけ)。決定論フラグは `build.sh` に集約され、Go 1.26.5 固定で bit-identical になる。CI の stale 検出ゲート(`.github/workflows/build-verify.yml`)がこれを前提にする。 +**ソース変更時は必ず `./build.sh` で再ビルドしてコミット**(`agy plugin install` はビルドせず git 追跡バイナリをコピーするだけ)。決定論フラグは `build.sh` に、Go のパッチ版は `.go-version` に集約され(`build.sh`/`build.ps1`/CI が同じファイルを読む)、bit-identical になる。CI の stale 検出ゲート(`.github/workflows/build-verify.yml`)がこれを前提にする。 ## 実機検証(tmux + agy) diff --git a/LESSONS.md b/LESSONS.md index d0736cf..6d8cf6a 100644 --- a/LESSONS.md +++ b/LESSONS.md @@ -1,5 +1,11 @@ # LESSONS(実装知見ログ) +## 2026-09-12: Go ツールチェーン版を `.go-version` に集約し `GOTOOLCHAIN` で強制する + +- 却下した案: (a) 従来どおり「go 1.26.5 前提」をコメント・README に書くだけで運用する。(b) 固定自体をやめ、stale ゲートを bit-identical 比較からソースハッシュ照合へ変更する。 +- 決め手: (a) は実測で破綻していた。go.mod の `go 1.26.5` は**下限**でしかなく `GOTOOLCHAIN` の既定は `auto` のため、ローカル go1.27.1 で `./build.sh` を回すと 18 バイナリが「正常な再ビルド出力と見分けのつかない差分」として生成された(PR #20 の Codex P1 指摘の原因でもある)。`export GOTOOLCHAIN=go$(cat .go-version)` 追加後は、環境変数を渡さずに全ビルドしても差分 0。(b) は成果物そのものを検証しなくなり、ハッシュの手書き換えや別アーキ・破損バイナリが素通りする。 +- 覆す条件: stale ゲートを bit-identical 比較以外(CI 側でビルドしてコミットする方式など)に変えた場合。その時は版一致が不要になるため固定も外せる。 + ## 2026-09-12: settings-advisor のパス判定を root 相対の「パス成分」へ統一(PR #20 レビュー対応) - 却下した案: Codex の指摘どおり CI 検知(`.circleci` 等の部分文字列一致)と本番設定検知(絶対パスのディレクトリ名走査)を**別々に**直す案。前者に区切り境界チェックを足し、後者だけ root 相対化する。 diff --git a/agy-plugin-kit/README_ja.md b/agy-plugin-kit/README_ja.md index 83ff4fe..f1f568e 100644 --- a/agy-plugin-kit/README_ja.md +++ b/agy-plugin-kit/README_ja.md @@ -37,7 +37,7 @@ agy(Antigravity CLI)プラグインを**正しく・速く量産する**た agy plugin install https://github.com/kwrkb/agy-plugins/agy-plugin-kit ``` -`validator/bin/` のネイティブバイナリ(`validator-linux-amd64` / `validator-darwin-arm64` / `validator.exe`)は `validator/src/main.go` から `go build` した成果物を**全 OS 分とも同梱**(コミット済み)。再ビルドはリポジトリルートのビルドスクリプトを使います(**Go 1.26.5**。決定論フラグはスクリプトに集約。CI の検証ゲート `.github/workflows/build-verify.yml` がこの結果との bit-identical 一致を要求し、Go のバージョンがずれると fail します)。 +`validator/bin/` のネイティブバイナリ(`validator-linux-amd64` / `validator-darwin-arm64` / `validator.exe`)は `validator/src/main.go` から `go build` した成果物を**全 OS 分とも同梱**(コミット済み)。再ビルドはリポジトリルートのビルドスクリプトを使います(Go のパッチ版は `.go-version` に固定され、スクリプトが `GOTOOLCHAIN` で強制します。決定論フラグもスクリプトに集約。CI の検証ゲート `.github/workflows/build-verify.yml` がこの結果との bit-identical 一致を要求します)。 ```bash ./build.sh validator # validator のネイティブバイナリ(linux-amd64/darwin-arm64/windows)を再ビルド。Windows は ./build.ps1 validator diff --git a/build.ps1 b/build.ps1 index 01888e1..807ba10 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,6 +1,6 @@ #!/usr/bin/env pwsh # build.sh の Windows(PowerShell) 版。決定論フラグ・対象は build.sh と完全に揃える。 -# 同一 Go バージョン(1.26.5) + 同一フラグ + CGO 無効のため、build.sh と bit-identical な +# 同一 Go バージョン + 同一フラグ + CGO 無効のため、build.sh と bit-identical な # バイナリを生成する(CI の検証ゲートはどちらでビルドしても通る)。 # # 使い方: @@ -8,29 +8,39 @@ # ./build.ps1 github # github プラグインのみ # ./build.ps1 validator # agy-plugin-kit の validator のみ # -# 注意: 決定論ビルドは Go ツールチェーンのバージョン一致が前提(現状 go 1.26.5)。 +# 注意: 決定論ビルドは Go ツールチェーンのパッチ版まで一致が前提。版は .go-version が +# 唯一の定義箇所(build.sh・CI も同じファイルを読む)。 param([string]$Target = 'all') $ErrorActionPreference = 'Stop' # 決定論フラグ(build.sh の FLAGS と一致させること) $Flags = @('-trimpath', '-buildvcs=false', '-ldflags=-buildid=') +# Go ツールチェーン固定版(build.sh の GOTOOLCHAIN と同じ .go-version を読む)。 +$GoToolchain = 'go' + (Get-Content (Join-Path $PSScriptRoot '.go-version') -Raw).Trim() + # Build # /src/ のソースから、ネイティブバイナリを /bin/ に生成する。 # -linux-amd64 -darwin-arm64 .exe # 拡張子なしの (OS 分岐 dispatcher)は build.sh / build.ps1 では触らない # (git 追跡のテキストスクリプト)。Windows の agy は .exe を直接起動する。 function Build([string]$dir, [string]$base) { - $ver = (go version) -split ' ' | Select-Object -Index 2 - Write-Host "==> building $base (linux-amd64, darwin-arm64, windows) from $dir/src/ [$ver]" - Push-Location "$dir/src" # $env: はプロセス環境を書き換えるため、対話セッションで ./build.ps1 を # 実行すると呼び出し元シェルを汚染する。退避し finally で必ず復元する # (build.sh はコマンド単位 env + subshell なので汚染しない。それと挙動を揃える)。 + # GOTOOLCHAIN も同じ扱い(build.sh 側は export だが、あちらは子プロセスで完結する)。 $oldCgo = $env:CGO_ENABLED $oldArch = $env:GOARCH $oldOs = $env:GOOS + $oldToolchain = $env:GOTOOLCHAIN + $pushed = $false try { + # 固定は go version の表示より先に行う。表示された版が「固定が効いた証拠」になる。 + $env:GOTOOLCHAIN = $GoToolchain + $ver = (go version) -split ' ' | Select-Object -Index 2 + Write-Host "==> building $base (linux-amd64, darwin-arm64, windows) from $dir/src/ [$ver]" + Push-Location "$dir/src" + $pushed = $true $env:CGO_ENABLED = '0' $env:GOARCH = 'amd64' $env:GOOS = 'linux' @@ -49,7 +59,8 @@ function Build([string]$dir, [string]$base) { $env:CGO_ENABLED = $oldCgo $env:GOARCH = $oldArch $env:GOOS = $oldOs - Pop-Location + $env:GOTOOLCHAIN = $oldToolchain + if ($pushed) { Pop-Location } } } diff --git a/build.sh b/build.sh index 49a3478..7ee50ec 100755 --- a/build.sh +++ b/build.sh @@ -8,14 +8,28 @@ # ./build.sh github # github プラグインのみ # ./build.sh validator # agy-plugin-kit の validator のみ # -# 注意: 決定論ビルドは Go ツールチェーンのバージョン一致が前提(現状 go 1.26.5)。 -# バージョンを上げる時は全バイナリを再ビルドしてコミットすること。 +# 注意: 決定論ビルドは Go ツールチェーンのパッチ版まで一致が前提。版は .go-version が +# 唯一の定義箇所で、CI(setup-go の go-version-file)もこのファイルを読む。 +# バージョンを上げる時は .go-version を書き換え、全バイナリを再ビルドしてコミットすること。 # Windows ネイティブで実行する場合は WSL または git-bash を使う。 set -eu +# スクリプトの位置をリポジトリルートとして扱う(呼び出し元 CWD に依存しない) +cd "$(dirname "$0")" + # 決定論フラグ(CI ゲートと一致させる唯一の定義箇所) FLAGS="-trimpath -buildvcs=false -ldflags=-buildid=" +# Go ツールチェーンを .go-version に固定する。GOTOOLCHAIN の既定は auto で、 +# go.mod の `go` ディレクティブは下限でしかないため、ローカルに新しい Go があると +# 黙ってそちらが使われ、正常な再ビルド出力と見分けのつかない差分が出る(stale ゲートが落ちる)。 +# 指定版が無ければ Go が自動ダウンロードするので、開発者側の事前準備は不要。 +# Git Bash + core.autocrlf=true では .go-version が CRLF で checkout されうる。 +# CR が残ると go は `invalid GOTOOLCHAIN "go1.26.5\r"` で即死するため空白類を除去する +# (.gitattributes で LF 固定もしているが、既存クローンを救うため読み取り側でも守る)。 +GOTOOLCHAIN="go$(tr -d "[:space:]" < .go-version)" +export GOTOOLCHAIN + # build # /src/ のソースから、ネイティブバイナリを /bin/ に生成する。 # -linux-amd64 -darwin-arm64 .exe @@ -34,9 +48,6 @@ build() { ) } -# スクリプトの位置をリポジトリルートとして扱う(呼び出し元 CWD に依存しない) -cd "$(dirname "$0")" - target="${1:-all}" case "$target" in github) build github github ;; diff --git a/github/README_ja.md b/github/README_ja.md index 4c0f371..07a4166 100644 --- a/github/README_ja.md +++ b/github/README_ja.md @@ -54,7 +54,7 @@ agy plugin install https://github.com/kwrkb/agy-plugins/github ### バイナリの再ビルド -リポジトリルートのビルドスクリプトを使います(**Go 1.26.5**。決定論フラグはスクリプトに集約。CI の検証ゲート `.github/workflows/build-verify.yml` がこの結果との bit-identical 一致を要求し、Go のバージョンがずれると fail します)。 +リポジトリルートのビルドスクリプトを使います(Go のパッチ版は `.go-version` に固定され、スクリプトが `GOTOOLCHAIN` で強制します。決定論フラグもスクリプトに集約。CI の検証ゲート `.github/workflows/build-verify.yml` がこの結果との bit-identical 一致を要求します)。 ```bash ./build.sh github # github のネイティブバイナリ(linux-amd64/darwin-arm64/windows)を再ビルド。Windows は ./build.ps1 github @@ -62,5 +62,5 @@ agy plugin install https://github.com/kwrkb/agy-plugins/github ``` > **ビルドする OS によってスクリプトを使い分ける**: macOS / Linux は `./build.sh`、Windows は `./build.ps1`。 -> どちらも `CGO_ENABLED=0` のクロスコンパイルで **3 OS 分のネイティブを 1 台で一括生成**し、Go 1.26.5 固定なら +> どちらも `CGO_ENABLED=0` のクロスコンパイルで **3 OS 分のネイティブを 1 台で一括生成**し、`.go-version` のツールチェーン固定により > ホスト OS に依らず bit-identical(各 OS で実機ビルドする必要はない)。