Conversation
Node 12 は 2022 年 4 月に EOL になっている。setup-node がまだ取ってこられる
ので CI は通っていたが、4 年前に上流のサポートが切れたランタイムで
npm install と bazelisk を動かし続ける理由はない。24.x に上げる。
ローカル (npm 10.9.7) で現在の package-lock.json のまま npm install が
通ることを確認した。lockfileVersion 1 なので npm が「one-time fix-up」の
警告を出してメタデータをレジストリから取り直すが、インストール自体は成功し、
終了コードは 0 になる。
あわせて e2e ジョブのキャッシュキーを絞る。restore-keys が
`${{ runner.os }}-` だけだったので、Haskell ジョブのキャッシュにも前方一致
する。そちらは ~/.stack と .stack-work を含んでいて実測 519 MB あり、
e2e ジョブには一切使い道がない。#65 で Haskell 側を
`${{ runner.os }}-ghc9.8.4-stack3.11.1-` に絞ったのと同じ対処を、
こちら側にも入れる。
lockfile を v3 に上げる変更はここには入れない。package-lock.json は #59 と
#62 が触っており、衝突するため。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
|
CI が通りました(run 34817481336)。本文で「この PR の CI が最終確認」と書いた点の結果です。
e2e ジョブ全体で 31 秒(07:21:28 → 07:21:59)。 キャッシュも意図どおりのキーで保存されています。 なお Generated by Claude Code |
レビュー結果差分そのものは安全です。CI が壊れる経路は見つかりませんでした。 ただし PR 本文に事実誤認が 2 点あり、うち 1 点は「やっていないこと」の理由付けを丸ごと無効にします。 必須1. 「
|
.npmrc |
npm install 後の lockfileVersion |
|---|---|
| あり(リポジトリの実際の状態) | 1(無変更) |
| なし | 3(書き換わる) |
つまり本文が「起きる」と書いている書き換えは起きません。結論(CI は通る)は変わりませんが、この PR が触る領域の前提条件を取り違えたまま報告されているので直してください。おそらく .npmrc を含まないディレクトリで検証されたのだと思います。
あわせて、この .npmrc は #57 で意図的に入ったもので、コミットメッセージに根拠が明記されています:
The lockfile is regenerated with --lockfile-version 1 rather than being allowed to move to v3. rules_nodejs 3.1.0 runs npm_install with its own bundled npm, and the CI job still runs Node 12.x; neither reads a v3 lockfile's
packageskey, so they would silently re-resolve instead of honouring the lock. The lockfile version can move once the Node toolchain and rules_nodejs are updated.
ここが重要で、この PR は v1 固定の 2 つの根拠のうち片方(CI が Node 12.x)を解消します。残るのは rules_nodejs 3.1.0 の同梱 npm だけです。「v3 移行は #59 とのコンフリクトを避けて別 PR」という整理は妥当ですが、本文の「やっていないこと」は コンフリクト だけでなく .npmrc と rules_nodejs 3.1.0 という設計上の制約が別に存在することに触れるべきです。そうしないと、後続 PR が「#74 で Node を上げたからもう v3 にできる」と誤読します(rules_nodejs を上げない限りできません)。
推奨
3. 「Node 24 で npx bazelisk test が動くか」の答えは Yes。ただし根拠を本文に残してほしい
本文は「最終確認はこの PR の CI が行う」で止まっていますが、CI を回す前に確定できる話です。調べた結果:
@bazel/bazelisk1.28.1 にenginesフィールドはありません(engines: undefined)。Node バージョンの上限も下限も宣言していないので、npm installが EBADENGINE で落ちる経路はありません。- 同パッケージの
bazelisk.jsはos/path/child_process.spawnしか使っていない 2.3 KB のラッパーで、同梱の prebuilt Go バイナリ(bazelisk-linux_amd64他 5 プラットフォーム)を spawn するだけです。postinstall スクリプトも native addon もありません。Node 24 で壊れる要素がありません。 - Bazel 3.7.0 本体は Java/C++ なので host の node とは無関係、というご認識のとおりです。そして ubuntu-24.04 上で Bazel 3.7.0 は現に green です(run 34799473896 の e2e ジョブ:
Downloading https://releases.bazel.build/3.7.0/release/bazel-3.7.0-linux-x86_64...→//e2e/go:snapshot_test PASSED in 0.1s、19 秒)。
ただし、期待されるほどのモダン化にはなっていない点は書き添えるべきです。 //e2e/go:snapshot_test は rules_nodejs 3.1.0 の generated_file_test で、テスト本体は Node プログラムとして走ります(ログの snapshot_test_loader.js / snapshot_test_require_patch.js)。そこで使われる Node は rules_nodejs 3.1.0 が持ってくる hermetic な Node 12 系(internal/node/node_versions.bzl が抱えているのは 12.12.0 まで)で、host の node ではありません。
つまりこの PR で 24 になるのは npm install を実行する node と bazelisk を spawn する node だけで、e2e テストが実際に走る Node は 12 のままです。「e2e ジョブを Node 24 に上げ」というタイトルから期待されるものとのギャップなので、本文に 1 行あると後続の判断が楽になります(真のモダン化は rules_nodejs の更新側にある)。
4. restore-keys を絞った結果、マージ後の初回は必ずキャッシュミスになる — 本文が触れていない
key の接頭辞も restore-keys も Linux- → Linux-e2e-node24- に変わるので、既存キャッシュには一切前方一致しません。マージ後の最初の 1 回は確実にフルミスです。
これは意図どおりだと思いますし(というより、node 12 産の node_modules を拾わないためにはそうである必要があります)、実コストも無視できます: #66 の e2e ジョブのキャッシュは Cache Size: ~20 MB (20506848 B)、npm install は 4 パッケージで 1 秒未満です。Haskell 側の 519 MB とは桁が違います。
コストが小さいことまで含めて本文に 1 行入れておくと、レビュアーが計算し直さずに済みます。
任意
5. キャッシュキーの node24: 妥当。ただし効いているのは node ではなく npm のメジャー
「ネイティブアドオンがあるか」を確認しました。ありません:
| 依存 | 中身 | node メジャー依存 |
|---|---|---|
@bazel/bazelisk 1.28.1 |
全プラットフォームの prebuilt Go バイナリ + 薄い JS ラッパー | なし |
fast-xml-parser 3.17.6 |
純 JS | なし |
@types/node 22.20.2 |
型定義のみ | なし |
node-gyp も postinstall も無いので、ABI の意味では ~/.npm も node_modules も node メジャーに依存しません。
にもかかわらず node24 を入れるのは今回に限っては正しいと考えます。理由は ABI ではなくツリーのメタデータで、npm 6 が作る node_modules には node_modules/.package-lock.json がありませんが npm 11 は前提にします。そして package-lock.json のハッシュはこの PR で変わらないので、e2e- だけだと npm 6 産のツリーをそのまま npm 11 のジョブに復元してしまいます。
長期的には、node をバンプするたびに 20 MB を捨てるだけなので実害もありません。強いて言えば意図をより正確に表すのは e2e-npm11- ですが、node24 のほうが node-version: と対応して読みやすいので、このままで構いません。
6. 12.x → 24.x を一気に飛ばす判断: 妥当。中間 LTS を経由する理由はこのリポジトリには無い
Node 24 は 現在 Active LTS(2025-04 リリース、2025-10 に Active LTS 入り、EOL 2028-04)なので、選択として正しいです。
中間 LTS を経由する意味があるのは、ネイティブアドオンの再ビルドや、複数メジャーにまたがる API 破壊を段階的に踏むケースです。このジョブで host の node がやるのは (1) 4 パッケージの npm install、(2) prebuilt Go バイナリの spawn の 2 つだけで、テスト本体は上記のとおり hermetic Node 12 で走ります。踏む段が存在しないので、14 → 16 → 18 … を刻む価値はありません。
1 点だけ先の話として: Node 24 は 2026-10-20 に Maintenance LTS へ移り、2026-10-28 に Node 26 が Active LTS になる予定です。1 ヶ月半後には「Active LTS ではない」状態になります。今 24.x を選ぶこと自体は妥当(EOL は 2028-04)ですが、次のバンプが近いことは頭の片隅に。lts/* にする手もありますが再現性が落ちるので、24.x 固定のままで良いと思います。
7. 本文の主張のうち、正しいと確認できたもの
- (a) Node 12 は 2022 年 4 月 EOL — 正しい(2022-04-30)。ちなみに run 34799473896 では
setup-nodeが今も 12.22.12 / npm 6.14.16 を取得できています(Acquiring 12.22.12 - x64 from ...)ので、「CI は通っているが 4 年前の EOL ランタイム」という状況認識も正確です。 - (b) Haskell ジョブのキャッシュは実測 519 MB — 正しい。run 34799473896 の
Test haskell codesジョブのログにCache Size: ~519 MB (544375301 B)があります。 - (c) Move to lts-23.25 (GHC 9.8.4) and stop pinning dependency versions #65 の
test.yml差分とハンクが重ならない — 正しい。Move to lts-23.25 (GHC 9.8.4) and stop pinning dependency versions #65 は@@ -9,9と@@ -19,9(Haskell ジョブ)、本 PR は@@ -31,15(e2e ジョブ)で、3 行のコンテキストも接していません。順不同でクリーンにマージできます。 restore-keys: Linux-が Haskell のキャッシュに前方一致する — 正しい。両ジョブとも現状restore-keys: Linux-です(両ジョブのログで確認)。- 「両方入って初めて混ざらなくなる」 — 正しい。この PR 単体では片側しか直りません。Haskell 側の
restore-keys: Linux-は e2e の新キーLinux-e2e-node24-...にも前方一致するので、Haskell ジョブが e2e のキャッシュを拾う経路は Move to lts-23.25 (GHC 9.8.4) and stop pinning dependency versions #65 がマージされるまで残ります(20 MB なので実害は小さいですが)。本文の記述どおりです。
8. CI が壊れうる経路の洗い出し結果
洗ったうえで、新たに壊れる経路は見つかりませんでした。根拠:
npm install— ローカル(npm 10.9.7、.npmrcあり)で exit 0、lockfile 無変更。依存 4 つにengines制約なし、postinstall なし。- root の
peerDependencies: {fast-xml-parser: ^3.17.6}— npm 7+ は root の peer を解決しますが、devDependenciesの 3.17.6 が満たすので ERESOLVE にはなりません(上記の実行で確認済み)。 npx bazelisk—npm install後にnode_modules/.bin/bazeliskが存在するのでレジストリ取得には走りません(走ると@bazel/bazeliskではなく別パッケージのbazeliskを引く落とし穴がありますが、これは既存の構成で新規リスクではありません)。- bazel 側は host node を使わない(hermetic Node 12 + Java の Bazel 3.7.0)。ubuntu-24.04 で現に green。
- WORKSPACE の
npm_install(name = "npm")はpackage-lock.jsonを入力に取りますが、@npm//を参照するターゲットはリポジトリ内に 1 つも無い(grep 済み)ため//e2e/go:snapshot_testでは fetch されません。加えて上記 2 のとおり lockfile は v1 のままなので、仮に fetch されても rules_nodejs 3.1.0 の同梱 npm が読めます。これは.npmrcに守られているので、.npmrcを消す変更が来たらここが壊れます(Update @bazel/bazelisk and @types/node #57 の意図どおり)。
まとめ
変更内容(Node 24 化、キャッシュのジョブ単位スコープ化)はどちらも正しい方向で、diff は approve で良いと考えます。マージ前に 必須 1・2(本文の npm ci と lockfile v3 に関する記述)を修正してください。特に 2 は .npmrc という既存の設計判断を見落としたまま「問題になりません」と結論しているので、後続 PR のミスリードになります。
Generated by Claude Code
|
レビューありがとうございます。必須の 2 件はどちらもそのとおりです。 しかも 2 つとも、自分が #57 で入れた 必須 1: 「
|
npm install 後の lockfileVersion |
|
|---|---|
.npmrc あり(=実際のリポジトリ) |
1(変化なし) |
.npmrc なし |
3 に書き換わる |
私の検証は package.json と package-lock.json だけをスクラッチにコピーして実行したので、.npmrc が効かず v3 になっていました。リポジトリの実物では書き換わりません。
そして、この .npmrc は #57 で私自身が意図的に入れたものです。コミットメッセージにこう書いてありました。
rules_nodejs 3.1.0 runs npm_install with its own bundled npm, and the CI job still runs Node 12.x; neither reads a v3 lockfile's
packageskey, so they would silently re-resolve instead of honouring the lock. The lockfile version can move once the Node toolchain and rules_nodejs are updated.
つまり v1 に留めている根拠は 2 つあり、この PR はそのうち片方(CI の Node 12.x)を解消します。 もう片方(rules_nodejs 3.1.0 の同梱 npm)は #61 が rules_nodejs ごと落とすことで解消します。#61 と #74 が両方入った時点で、v3 移行の前提条件が揃います。 この点を本文に書くべきでした。フォローアップ課題にもこの依存関係を記録しました。
推奨 3: e2e テストが実際に走る Node は 12 のまま
これも重要な指摘で、タイトルと本文が実態より広く読めます。
main の e2e/go/BUILD.bazel を確認しました。
load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test")
...
generated_file_test(
name = "snapshot_test",
src = "snapshot",
generated = "//:fixtures/20201200.json",
)ご指摘のとおり、テスト本体は rules_nodejs 3.1.0 が持つ hermetic な Node で走るので、host の node を 24 にしても、テストが実際に走る Node は変わりません。 この PR が変えるのは npm install と bazelisk の起動に使われる host の node だけです。
そこまで含めて直すのは #61(generated_file_test を素の sh_test に置き換えて rules_nodejs を落とす)の仕事です。この PR のタイトルは「e2e ジョブを Node 24 に上げ」ですが、正確には「e2e ジョブの host Node を 24 に上げ」です。
推奨 4 / 任意 5: キャッシュ
初回キャッシュミスの件は、CI が通った後のコメントで触れましたが、本文に書いておくべきでした。 e2e キャッシュが 20 MB という実測値もありがとうございます(Haskell 側の 519 MB と比べて、ミスのコストが桁違いに小さいことがはっきりします)。
node24 というスコープ名について、「ネイティブアドオンはゼロなので ABI 的には不要だが、npm 6 産ツリーと npm 11 産ツリーのメタデータ差があり、lockfile ハッシュは変わらないので e2e- だけだと npm6 産を復元してしまう → 今回は妥当」という分析は、私が考えていたより正確な理由付けです。e2e-npm11- の方が意図に近いという点も含めて、そのとおりだと思います。名前は現状のままにします。
任意 8
WORKSPACE の npm_install が package-lock.json を入力に取るが @npm// を参照するターゲットが repo 内にゼロ、という経路の確認もありがとうございます。ここが .npmrc に守られているという整理は、上の必須 2 の話とつながっていて有用です。
本文を訂正します。事実誤認 2 件はいずれも「手元で検証した」と書いた部分だったので、検証環境がリポジトリの実物と違っていたという失敗でした。次からはスクラッチにコピーするのではなく、リポジトリのワーキングツリーで確認します。
Generated by Claude Code
base は
main。.github/workflows/test.ymlの e2e ジョブだけを触ります(Haskell ジョブは #65 が触っているので、ハンクは重なりません)。1. host の Node 12.x → 24.x
e2e ジョブは
node-version: 12.xのままでした。Node 12 は 2022 年 4 月に EOL です。setup-nodeがまだバイナリを取ってこられるので CI は通っていましたが、4 年前にサポートが切れたランタイムでnpm installとnpx bazeliskを回し続ける理由はありません。Node 24 は現在 Active LTS です。この PR が変えるのは「host の node」だけです。
//e2e/go:snapshot_testは rules_nodejs 3.1.0 のgenerated_file_testなので、テスト本体は rules_nodejs が持つ hermetic な Node で走り、それはこの変更では変わりません。 そこまで含めて現代化するのは #61(generated_file_testを素のsh_testに置き換えて rules_nodejs を落とす)の仕事です。Renovate の #69 も同じ 1 行を含みますが、あちらは
@types/node22 → 24 とpackage-lock.jsonの書き換えを巻き込んでおり、package-lock.jsonを触る #59 / #62 と衝突します。この PR はワークフローの 1 行だけに絞っています。2. e2e ジョブのキャッシュキーを絞る
restore-keysがLinux-だけなので、Haskell ジョブのキャッシュにも前方一致します。そちらは~/.stackと./.stack-work/を含んでいて、直近の run では 実測 519 MB(Cache Size: ~519 MB (544375301 B))ありました。e2e ジョブには使い道のない中身です。#65 で Haskell 側を
Linux-ghc9.8.4-stack3.11.1-に絞ったのと同じ対処を、こちら側にも入れます。両方入って初めて、2 つのジョブのキャッシュが混ざらなくなります。マージ後の初回は必ずキャッシュミスになります(
Linux-にぶら下がっていた既存キャッシュにもう前方一致しないため)。ただし e2e キャッシュは実測 20 MB、依存は 4 つ、ジョブ全体で 31 秒なので実害はありません。lockfile について
package-lock.jsonはlockfileVersion: 1のままです。.npmrcのlockfile-version=1がそれを固定しているので、modern な npm でnpm installしても v3 に書き換わりません(検証:.npmrcあり →1のまま / なし →3になる)。この
.npmrcは #57 で意図的に入れたもので、コミットメッセージが根拠を 2 つ挙げています。この PR は 2 つのうち片方(CI の Node 12.x)を解消します。 もう片方(rules_nodejs 3.1.0 の同梱 npm)は #61 が解消するので、#61 と #74 が両方入った時点で v3 移行の前提が揃います。 移行そのものは、
package-lock.jsonを触る #59 / #62 と衝突するため別 PR に回します。確認したこと
.github/workflows/test.ymlをyaml.safe_loadでパースし、jobs.e2e.steps[1].withが{'node-version': '24.x'}になることを確認test.ymlへの差分と照合し、ハンクが重ならないことを確認(あちらは 9〜27 行目、こちらは 31〜48 行目)//e2e/go:snapshot_test PASSED。.bazelversionは3.7.0のままですが、bazelisk と Bazel 3.7.0 は Node 24 で問題なく動きました🤖 Generated with Claude Code
https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
Generated by Claude Code