Codexコミットレビューの1万行上限から自動生成データを外し、拍子シミュレーターの再生予約バグ4件を直す

開発mdx-playground

Codexコミットレビューの1万行上限から自動生成データを外し、拍子シミュレーターの再生予約バグ4件を直す

朝の /make-diary が9/27分の日記をコミットし終えたところで、引っかかっていたことを Claude Code に切り出した。 コミット時の Codex レビューには1万行の上限があり、自動生成データの差分がその行数を押し上げている。 生成データそのものをレビューの上限に数えても意味がない。 レビューすべきなのは、それを吐き出した生成スクリプトの変更のほうだ。 そう伝えて、上限の数え方を工夫しようと持ちかけた。

後半は、拍子シミュレーターの再生予約の不具合4件を直した。 その流れで回したデプロイでは、Claude Code がコミットメッセージに書いた判断の一つが、ビルドのログで覆った。

1万行上限から自動生成データを外す

新しい仕組みでは、linguist-generated を宣言したファイルと「自動生成」のヘッダーを持つファイルを、レビューからも行数の判定からも外す。 ヘッダーを書き込めない JSON、JSONL、抽出テキストは、mdx-playground の .gitattributes で宣言した(c6b642c9)。 対象は、メモリ価格の生スナップショット、evals の jsonl と sources、pelosi-watch の抽出テキストである。 evals の golden は人が選んだ例なので、宣言から外した。

ゲート本体を差し替える前に、Claude Code には今朝のコミット(17,976 行)をステージした状態を一時的な作業ツリーで再現させ、4つのパターンで動きを確かめさせた。 その途中で一つ見つかった。 自動生成データも含めて数える REVIEW_INCLUDE_GENERATED=1 を付けたときにも、画面には「自動生成データを除いた行数」と出ていた。 この文言を直してから残りのパターンを試し、4つとも想定どおり動いた。

今朝のコミットで測り直すと、上限に引っかかっていた 17,976 行の差分は、記事と state だけの 897 行になった。 生成スクリプトの変更は、これまでどおりレビューされる。 仕様書(codex-commit-review-gate.md)にも追記してもらった。

コミットとプッシュ

「全てコミットプッシュしといてください」と頼んだ。 ~/.claude 側には、今回と関係のない .last-complete-round が元からステージされていたので、Claude Code はそれを外してからコミットした。 コミット時の Codex レビューでは high の指摘が2回、計4件出た。 Claude Code が重要度を自分で判定し直し、4件とも直してから通している。 直した中には、角括弧を含むパスが差分に残らない件もあった。 ~/.claude と mdx-playground の両方を push して、この件は終わった。

Mac へのひとこと

続けて Mac にメッセージを送るよう頼んだが、同時に「push して Mac でクローンすれば分かるのでは」とも聞いた。 Claude Code は「push で足りる」と答え、メッセージは送らずにおいた。 それでも一言だけ送っておくことにした。

ところが、既定の LAN 直送が届かず、ブラウザ経由も送れなかった。 ブラウザでは、claude.ai が「再度サインインしてください」のダイアログを出して止まる。 SSH でつながっているはずだと伝えたが、Mac の LAN アドレスへの SSH もタイムアウトした。 LAN 直送が届かなかったのは、Mac の IP アドレスの末尾が .102 から .104 に変わっていたからだった。 送信ヘルパーの既定は古いアドレスのままだった。 Mac のホスト名から今のアドレスを引き直すと、受信サーバーはそこで普通に動いていた。 最後は LAN 直送で、Mac の tmux セッションの入力欄まで本文が届いた。

同じ朝には、Bash ツールがどのシェルで動くかも3回確かめている。 Windows では3回とも bash 5.2.37 が返った。 Mac 側の話は Mac の Claude Code で Bash ツールが zsh として動く問題の記事 にまとめた。

拍子シミュレーターの再生予約を直す

こちらの材料は、別のセッションに渡すつもりで用意していた issue とレビュー結果だった。 それを貼り付けて、不具合4件の修正を Claude Code に任せた。

#場面直し方
1再生中の拍子切り替え旧拍子の予約を捨て、現在時刻の 0.05 秒後から新しい拍子の1拍目を鳴らす
2停止や切り替えのあとの残響クリック音を再生単位の GainNode に集め、止めるたびに切り離す
36/8、9/8、12/8 の裏拍付点4分を1拍にし、裏拍オンでは8分音符の3分割を鳴らす
4タブに戻ったとき大きく遅れた拍は鳴らさず、拍番号と小節数だけ進める

予約の計算は app/utils/rhythmSchedule.ts に純粋関数として切り出し、Vitest で検証する形にした(c34d0f04)。 ページ側は、音を扱う区間を Python で丸ごと置き換えてもらった。

テストが落ちた2か所

テストを書かせると、2か所で落ちた。 1つめは関数のほうの誤りだった。 遅れを取り戻した直後の拍がちょうど小節の頭に当たると、飛ばした小節数(barsSkipped)を二重に数えていた。 数える範囲を半開区間に直し、テストも足した。

2つめはテストの期待値のほうが誤っていた。 先読みの窓を 2.55 秒にしていたため、2.5 秒の拍もその窓に入ってしまう。 窓を 2.0 秒に直すと、15件すべて通った。

音量0で予約を数える

表示の確認に入ると、最初は Chrome DevTools MCP がつながらなかった。 Chrome は起動していた(34プロセス)のに、DevToolsActivePort が見つからない。 調べ直すとファイルはできていて、もう一度つなぐと接続できた。

作業中の自分の邪魔にならないよう、Claude Code は音量スライダーを0にしてから計測用のフックを仕込んだ。 周波数も記録させ、強拍と裏拍を見分けられるようにしている。 40 BPM の 4/4 では拍が 1.5 秒間隔で予約され、620Hz の裏拍がその中間の 0.75 秒に入っていた。 そこから 6/8 に切り替え、表示にもエラーにも問題がないことを確かめた。 6/8 のカウンターは「1 拍目(8分の 1〜3つ目)」のように出る。

ただ、全体の Vitest を流すと2件落ちた。 パンくずと OG メタのテストである。 さっきのスクリーンショットでも、パンくずに「rhythm-simulator」という生のスラッグが出ていたので、その件の可能性があった。 この2件はあとで直すことになる。 ここでは拍子シミュレーターの修正と、.gitignore に __pycache__/ を足す変更(ec3d1ab8)を別々にコミットした。

_redirects の判断が覆る

dev サーバーを止めてコミットと push をするよう頼んだ。 作業ツリーには、別セッションが残した伏線回収漫画ページの変更もあった。 これも中身ごとに分けてコミットしてもらった。

その中に public/_redirects の差分があった。 このファイルは、自分の設定した許可ルールで読み取りが禁止されている。 Claude Code は中身を読まずに、誰がこのファイルを書き換えるのかを調べ、scripts/generate-redirects.mjs が生成していると突き止めた。 さらに、package.json にこのスクリプトを呼ぶ行が1つしかないことを根拠に、「ビルド時に再生成されない」と判断した。 その判断は、コミット(e0c42721)のメッセージにも書かれた。

/deploy は 09:09 に始まった。 プリレンダーは 7057 ルートで約399秒かかり、そのあとの postgenerate で generate-redirects が走った。 ログを見た Claude Code が書き出し先を確かめると、このスクリプトは postgenerate のたびに記事一覧から _redirects を作り直し、public/ と dist/ の両方へ書き出していた。 さっきの判断は間違いだった。 残っていた差分は、9/27 のデプロイで再生成されたものが、コミットされずに残っていただけと考えられる。

本番のヘルスチェックは 09:24:12 に通り、伏線回収漫画ページも本番で表示を確かめた。

積み残し4件

「セッションの積み残しはないですか」と聞くと、頼んだ作業に積み残しはないという答えのあとに、気になる点が4件挙がった。 「全部直して」と返した。

  • パンくずの現在地が生のスラッグだった /rhythm-simulator などの3ページに、ラベルを登録した
  • embed/ の Player Card 試作は X が iframe で読む埋め込み専用ページなので、OG メタのテスト対象から外した(d4ccc670)
  • 7/8 と 11/8 も8分音符を1マスとする拍子にまとめ、裏拍に16分音符を入れないようにした(aa710523)。7/8 は裏拍オフで 2+2+3 の長さの違う3拍、オンで8分音符7つになる
  • _redirects は、リポジトリにすでにある writeIfChanged の仕組みに合わせた。生成時刻の行を除いて比べ、同じなら public/ 側を書き換えない(24ffbfba)。配信される dist/ 側は従来どおり毎回書き出す

_redirects では、ヘッダーコメントの置換だけが効いておらず、Edit で直した。 直したあとは public/_redirects が書き換わらず、差分も出なかった。

7/8 の確認では、また計測が空振りした。 60 BPM で裏拍のオフとオンを鳴らしたのに、予約が1件も記録されない。 BPM が 96 のままだったので、dev の初回表示でハイドレーションが済む前にクリックしていたと分かった。 準備ができてから、同じ計測をやり直させた。

全体のテストは 21021 件がすべて通り、前回落ちた2件も解消した。 デプロイは後でいいと伝えて、このセッションを終えた。 最後の3コミット(aa710523、d4ccc670、24ffbfba)は、この時点では本番に出ていない。

学び

  • 生成データは行数の上限に数えず、生成スクリプトの変更をレビューする。ヘッダーを書けない生成物は .gitattributes の linguist-generated で宣言できる
  • スクリプトを呼ぶ行が package.json に1つしかないことは、ビルドで走らない根拠にならなかった。postgenerate の中から呼ばれていた
  • dev の初回表示でハイドレーション前にクリックすると、計測は何も拾わない。空振りしたら、まず画面の状態(今回は BPM の初期値)を見る
#Codex#コミットレビュー#gitattributes#Web Audio#Vitest#Nuxt