fix: modified の書き換えが #998 で止まらなかった本当の原因を直す - #1009
Merged
Merged
Conversation
#998 made the main branch available so isDifferentFromMain() could compare against it, and the fetch does work — the workflow log shows "* [new branch] main -> main". Timestamps kept churning anyway, because there is a second cause underneath. The ten writes in this file are `void fs.outputJson(...)`: fire-and-forget promises that nothing awaits. main() then calls core(), convert(), packages(), scripts() and list() synchronously, so list() reaches `git hash-object v3/core.json` while that write is still pending. A probe confirms it directly — at the top of list(), fs.existsSync(V3_CORE_JSON) is false on a clean checkout. isDifferentFromMain() reads that as "exists on main, missing in the workspace", takes its deleted-on-workspace branch, and reports every file as changed. Before #998 the same runs ended up at "now" by a different route: with no main branch, getListJsonFromMain() returned null and the fallback stamped everything with new Date(). Two independent causes, one symptom, which is why fixing the first one alone changed nothing visible. Node drains the event loop before exit, so the files themselves are always written correctly and the published data has never been wrong — only the ordering within a run was. Making the writes synchronous removes the race without changing what is produced: 100 of 100 files still validate, and every generated file is byte-identical to the copy currently on main. Verified on a fresh shallow clone made the way the runner makes it, which is what the earlier check got wrong: it reused a workspace where a previous run had already left v3/ in place, so it exercised the second run rather than the first, and every CI run is a first run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
先に結論
#998 では止まりませんでした。 マージ後のリリース 5 本を確認すると、
modified50 件は依然として毎回リリース時刻に書き換わっています。原因が 2 つあり、#998 はそのうち 1 つしか直していませんでした。 私の前回の検証が不十分だったためです(下の「検証の誤り」を参照)。
#998 自体は効いています
ワークフローのログで
mainの取得は成功しています。つまり
getListJsonFromMain()とgit ls-tree -r mainは動くようになりました。その下にもう 1 つ原因がありました。本当の原因: 生成の書き込みが待たれていない
util/release.tsの書き込みは 10 箇所すべてがvoid fs.outputJson(...)— Promise を投げっぱなしにしていて、誰も await しません。main()は同期的に呼ぶだけなので、list()がv3/core.jsonをハッシュしようとする時点で、その書き込みがまだ完了していません。 probe を仕込んで直接確認しました。isDifferentFromMain()はこれを「main には在るのに作業ツリーに無い」と読み、削除された = 変更ありの枝に入ります。結果、全件が「変更あり」になります。2 つの原因が同じ症状を出していた
getListJsonFromMain()isDifferentFromMain()mainが無く null → 既定値でnew Date()falsetrue経路が違うだけで結果が同じだったため、1 つ目を直しても表からは何も変わりませんでした。
修正
void fs.outputJson(をfs.outputJsonSync(に置き換えます(10 箇所)。main()を同期のまま保てて、レースが消えます。生成するファイルは 100 個程度なので同期 I/O のコストは問題になりません。公開データは壊れていません
Node はイベントループが空になるまでプロセスを終えないので、ファイル自体は最終的に必ず正しく書かれます。壊れていたのは 1 回の実行の中の順序だけです。
検証(まっさらな shallow clone、CI と同一条件)
--depth=1 --branch sourceでクローンし、mainを取得し、v3/がSPECIFICATION.mdだけの状態から 1 回だけ実行しました。main)core.modified2026-08-23T20:14:43.955Z2026-08-23T13:20:49.752Z2026-08-23T13:20:49.752Zconvert.modified13:20:49.756Zpackages[]48 件13:20台生成物そのものも変わっていないことを確認しました。
core.json/convert.json/scripts.json: 公開中とバイト一致packages/*.json96 件すべてが公開中とバイト一致検証の誤り(前回)
#998 で「1 回目と 2 回目が同じ値になった」と報告しましたが、あの作業ツリーには前の実行で作った
v3/が既に残っていました。ファイルが存在する状態を測っていたので、実質 2 回目以降の挙動しか見ていませんでした。CI の実行は毎回が 1 回目です。 今回はクローンからやり直して 1 回目を測っています。
この後
マージ後の最初のリリースでは、
main上の内容と生成物が一致するファイルのmodifiedが2026-08-23T13:20:49台のまま固定されるはずです。それが確認できれば止まったと言えます。既に公開されてしまった値そのものは直りません(#998 に書いたとおりです)。