Node.jsスクリプトをRust化すべき基準|V8起動税78ms撤廃と43倍高速化の実証録
AI エディタ(Antigravity / VS Code)と連携する自作スクリプトが増えてくると、「検索や監査の一部を Rust にしたら爆速になったけれど、残りの Node.js スクリプトも全部 Rust 化した方がいいのだろうか?」と迷う場面が出てきます。当サイト(公開 568 記事・2,361 会話スレッド運用)でも、残っていた全 18 本のスクリプトを 1 本ずつミリ秒単位で実測し、どこに本当のボトルネックが潜んでいるのかを徹底解剖しました。
結論からお伝えすると、すべての Node.js スクリプトを闇雲に Rust 化する必要はありません。劇的な効果が出るのは 「毎ターン起動される短命 CLI・エディタ Hooks・数百ファイルの並列解析・巨大 SQLite の差分同期」の 4 領域 であり、逆に外部 API の通信待ち・画像変換(sharp)・常駐サーバーは Node.js のまま残すのが最も賢い選択です。本記事では、この基準に沿って優先度の高い 7 つの基盤処理を 外部クレート依存ゼロの Pure Rust 2 バイナリ(gemini-gate と kb-search) へ完全統合し、毎ターンの Hooks 遅延を最大 15.8 倍速(94.1ms → 5.9ms)、会話 DB の差分同期を 43.0 倍速(1,063.3ms → 24.7ms) へ引き上げた一次実測データと設計ノウハウを公開します。
-
SQLite全文検索にGPUは逆効果?Rust×AVX2と短語FTS5で48ms化した検証録 : 本記事の前編にあたる検証録です。CPU 内蔵 AVX2 命令と 1〜2 文字専用
short_fts索引で検索クエリ自体を高速化した仕組みを解説しています。 -
旧システムのAI移行はなぜ失敗する?1,141行の憲法とSQLite・Rust検問の12段階実証録 : 今回統合先の 1 つとなった Pure Rust 憲法監査ゲート(
gemini-gate)の設計思想と、AI の手戻りを機械検問で防ぐ仕組みをまとめています。 -
AIルール設計の壁突破|GEMINI.mdの24KB切り捨てと3層自動分割の実装録 : 今回 Rust バイナリへ統合して SHA-256 完全一致を証明した、25 本のルール自動分割エンジンの背景解説です。
-
AIエディタの会話ログでRAMDiskが満杯?直近3日保持とSSD自動退避で空き容量を2倍にした構築録 : 5 分周期の自動バックアップと連携して動く完了済み会話アーカイブ処理の 4 重保護ロジックを詳しく紹介しています。
-
AI エディタの Hooks やローカル自動化ツールを Node.js で組んでおり、「1 回あたり 0.1〜1 秒の微妙な引っかかり」 を解消したい方
-
「どの処理を Rust に移植すれば投資対効果が高く、逆にどの処理は Node.js のまま触らなくてよいのか」 の明確な判断基準を知りたい方
-
外部パッケージ(
crates.ioやnpm)の依存地獄を増やさず、OS 標準の SQLite ライブラリと単体コンパイラだけで保守性の高い高速 CLI を作る方法 に興味がある方
結論:Rust化すべき処理と残すべき処理の境界線
「Rust は速い」と聞くと、つい手元のスクリプトを端から端まで書き直したくなります。しかし実際に当サイトの scripts/ 配下にある全スクリプトの実行時間と内訳を計測してみると、「Rust 化すると 5〜40 倍速くなる処理」と「苦労して Rust 化しても 1% も速くならない処理」が真っ二つに分かれる ことがわかりました。
まずは実測にもとづく仕分け基準を一覧表で整理します。
| 処理カテゴリー | 当サイトでの具体例 | Rust化の判定 | 理由と損益分岐点 |
|---|---|---|---|
| ① 毎ターン走るエディタ Hooks | kb_hook_bridge.mjs(編集検知・連鎖ガイド) | ◎ 最優先 | AI の思考前後やファイル保存のたびに何十回も起動するため、V8 起動税の削減効果 が最も大きい領域です |
| ② 高頻度の短命 CLI サブコマンド | kb_query.mjs の未移植 8 コマンド(card / impact 等) | ◎ 最優先 | 処理本体が 10ms でも Node.js 起動に約 78ms かかると、体感速度が 4〜5 倍遅くなります |
| ③ 巨大 SQLite 同期・並列テキスト解剖 | sync_knowledge_db.mjs(572 記事+2,361 会話同期) | ◎ 最優先 | シングルスレッドの JS ループを 12 スレッド並列+FFI 直結 に変えることで桁違いの差が出ます |
| ④ 全記事スキャン・定型構造操作 | 監査マップ生成・見出し行番号抽出・太字スペース整形 | ○ 中優先 | 既存の監査バイナリに相乗り統合すれば、568 記事走査や文字境界判定が数ミリ秒〜0.2 秒で終わります |
| ⑤ 定期 LaunchAgent のファイル退避 | archive_cold_brain.mjs(RAMDisk 会話整理) | ○ 中優先 | インプロセスで SQLite パス同期まで完結でき、バックグラウンド常駐ジョブの負荷が最小化します |
| ⑥ 外部 Web API の通信待ち処理 | Search Console API 取得・Gemini API 日報生成 | × 不要 | 実行時間の 99% 以上がネットワーク応答待ち(数秒〜数十秒) のため、言語を変えても速くなりません |
| ⑦ 内部がすでに C/C++ ネイティブの処理 | sharp による WebP 画像変換・EXIF 回転補正 | × 不要 | Node.js は薄い窓口にすぎず、実際の画素計算はすでに C++ 製 libvips が SIMD 並列で実行しています |
| ⑧ 起動しっぱなしの常駐サーバー | Convo Mail ローカル閲覧サーバー・Astro 開発サーバー | × 不要 | 起動が 1 回きりなので V8 起動税が問題にならず、JIT 最適化が効いた後は数ミリ秒で応答します |
なるほどなぁ!「何でもかんでも Rust に書き換えりゃええ」っちゅう話じゃないんじゃな。通信待ちが 10 秒かかる処理を Rust にしても、9.95 秒になるだけじゃったら苦労の割に合わんわい。
まさにそこが一番大切な見極めポイントなんです!逆に言えば、「1 回の作業中に何十回も立ち上がってはすぐ終了する短命プロセス」 や 「何百本ものテキストと巨大 SQLite を毎回なめる処理」 に絞って Rust 化すれば、最小の手間で開発環境全体の引っかかりを根こそぎ消すことができます。
数百行のNode.jsが毎回待たされる3つの真因
では、なぜ数百行程度のシンプルな Node.js スクリプトなのに、実行するたびに 100ms〜1,060ms もの待ち時間が発生していたのでしょうか。プロファイリングで浮かび上がった真犯人は以下の 3 つ でした。
空スクリプトでも発生するV8起動税78ミリ秒
1 つ目の真犯人は、スクリプトの中身を 1 行も実行する前から発生する 「Node.js(V8 JavaScript エンジン)のプロセス起動税」 です。
当サイトの母艦である iMac(Core i5-10600 / 64GB RAM / Node.js v24)で、文字通り「何もしない空っぽのコマンド」を計測した結果がこちらです。
# 何もしない空スクリプトの起動〜終了時間を実測(5回ウォーム計測の中央値)
$ node -e ""
# -> 実測中央値: 78.1 ms
Node.js は起動するたびに、巨大な実行バイナリの動的リンク解決、V8 ヒープ領域と Isolate(独立実行空間)の初期化、組み込みモジュールのブートストラップを行います。常駐 Web サーバーなら最初の 1 回だけで済みますが、AI エージェントが 1 つのタスクの中で検索コマンドや Hooks を 30 回呼び出せば、中身が 0 秒でも 78.1ms × 30回 = 約 2.3 秒 の純粋な待ち時間 が積み上がります。
なお、Node.js v22 以降にはバイトコードを保存して起動を助ける --compile-cache オプションもありますが、実際に試しても V8 自体の初期化とモジュール解決の土台コストは残るため、ネイティブ機械語バイナリ(起動〜終了まで 5ms 台)との 10 倍以上の差は埋まりませんでした。
静的import連鎖が招く9,000行の事前読込
2 つ目の真犯人は、ECMAScript Modules(ESM)の仕様による 「静的 import グラフの芋づる式ロード」 です。
たとえば Antigravity エディタでAIが思考を始める直前に毎回呼ばれる kb_hook_bridge.mjs(pre-invocation モード)は、本来なら「直前に編集されたファイルの通知キューが無ければ、ただ {} を出力して終わるだけ」の 実質 5 行の処理 です。ところが実際の所要時間を測ると 毎回 94.1ms もかかっていました。
原因をたどると、ファイルの先頭に書かれた import 文の連鎖に行き当たりました。
-
kb_hook_bridge.mjs(561 行) が、編集時用の関数を使うためにkb_query.mjs・sync_knowledge_db.mjs・article_toolkit.mjsを先頭で静的importしていました。 -
ESM の仕様上、プログラムの 1 行目が動き出す前に、参照先の
kb_query.mjs(2,732 行)、sync_knowledge_db.mjs(2,799 行)、article_toolkit.mjs(1,528 行)、さらに共通辞書やnpmパッケージ(gray-matter等の YAML パーサー群)まで 合計約 9,000 行超のソースコード をすべてディスクから探し出して構文解析(パース)していたのです。 -
その結果、「99% のターンは何もせず
{}を返すだけ」にもかかわらず、毎回フル装備の百貨店を開店させてから閉店するような無駄が発生していました。
FTS5仮想表の結合走査で消えていた1秒の正体
3 つ目の真犯人は、654.5MB(2,361 会話スレッド)に育ったチャット履歴データベース conversations.sqlite の差分同期(sync_knowledge_db.mjs --convos)に潜んでいました。
新しい会話が 1 件も増えていない(差分 0 件)にもかかわらず、実行するたびに 1,063.3ms(約 1.06 秒) もかかっていたのです。原因を分解すると、以下の 2 つの重い処理が毎回フル回転していました。
-
12MB 超の
threads_index.jsonパースと数千回のstat発行 : Google Takeout 由来の Web 版 Gemini スレッド(846 件)に変更がないか確かめるため、毎回 12MB 以上の JSON インデックスを丸ごと読み込み、個別ファイルの更新日時をシステムコールで確認していました。 -
FTS5 仮想テーブルに対する
LEFT JOINフルスキャン : 1〜2 文字検索用の補助索引(conversations_short_fts)に漏れがないか確認する際、FROM conversations_fts f LEFT JOIN convo_short_fts_tracker tr ON tr.fts_rowid = f.rowidという SQL を実行していました。SQLite の FTS5 は「仮想テーブル」であるため、主キーのように見えても通常の B-Tree インデックス結合が効かず、毎回 2,361 件(数百 MB 分)の仮想テーブル全行を端からなめていた のが 1 秒超えの正体でした。
外部依存ゼロ!2バイナリ集約のPure Rust設計
原因が完全に特定できたところで、次は「どうやって保守性を下げずに高速化するか」です。スクリプトごとにバラバラの Rust プロジェクト(8 個の Cargo.toml と 8 個のビルドフォルダ)を作ってしまうと、管理が煩雑になるだけでなく SSD や RAM ディスクの容量も無駄に食ってしまいます。
そこで今回は、既存の 2 つのコアバイナリに役割ごと相乗りさせる 「2 バイナリ完全集約アーキテクチャ」 を採用しました。
従来の憲法監査に加えて、--sync-rules(GEMINI.md 自動分割)、--audit-map、--outline、--fix(無改変 SHA-256 証明付き整形)を 1 本のバイナリへ統合しました。
残っていた 8 つの検索サブコマンド(stats / card / impact / axiom / affiliate 等)に加え、sync、hook(3 モード)、archive-cold-brain をインプロセスで直結しました。
外部クレート(crates.io)を 1 つも使わず、rustc --edition 2021 -O 単体で RAMDisk 上へ直接コンパイル。変更がない普段の呼び出しは exec で即座に機械語が走ります。
外部クレート0個とRAMDisk常駐の超速ビルド
Rust で CLI ツールを作るとき、一般的には serde・rusqlite・clap・regex・sha1 といった外部クレートをたくさん追加します。しかし個人開発やブログ基盤で外部クレートを何十個も抱え込むと、初回ビルドに何分もかかり、target/ ディレクトリが数 GB に膨れ上がるほか、外部パッケージの更新追従やサプライチェーン汚染のリスクも生まれます。
そこで今回は 「外部クレート依存 0 個(Rust 標準ライブラリ std + macOS 標準搭載の /usr/lib/libsqlite3.dylib のみ)」 を貫きました。
-
ビルドが数秒で終わり、
target/肥大化もゼロ :Cargoすら介さず、起動ラッパー(run_kb_search.sh/run_gemini_gate.sh)が.rsソースの更新日時を見て、変更があった時だけrustc --edition 2021 -O -C target-cpu=native -C strip=symbolsで RAM ディスク(/Volumes/RAMDisk/$USER/tmp/)へ直接バイナリを出力します。SSD やハードディスク(記憶装置)への書き込みは 1 バイトも発生しません。 -
インプロセス連携で「子プロセス起動リレー」を根絶 : これまで
kb_hook_bridge.mjsが編集通知を受けた際は、内部でさらに別のモジュールや DB 接続を張り直していました。統合後のkb-search hookは、自身のメモリ空間内にあるsync_knowledge_db関数やcompute_article_impact(連鎖波及計算)を プロセス再起動なしで直接呼び出す ため、無駄なオーバーヘッドが一切ありません。
シャドウ表と署名キャッシュによるO(1)スキップ
先ほど「差分 0 件でも 1.06 秒かかっていた」会話履歴 DB の同期(kb-search sync --convos)には、SQLite の内部構造を活かした 2 段の O(1)(データ量が増えても一瞬で終わる定数時間)ショートカット を組み込みました。
-- FTS5 仮想表本体ではなく、裏側の実 B-Tree シャドウ表 (*_docsize) を使った高速整合判定
SELECT COUNT(*), COALESCE(MAX(id), 0) FROM conversations_fts_docsize;
SELECT COUNT(*), COALESCE(MAX(fts_rowid), 0) FROM convo_short_fts_tracker WHERE convo_id != '';
SQLite の FTS5(通常のコンテンツ保持型)を作ると、データベース内部には conversations_fts_docsize という通常の B-Tree 構造を持つシャドウテーブル(実表) が自動的に作られ、各行の id(rowid と 1 対 1 対応)が綺麗に並んでいます。
仮想テーブル本体(conversations_fts)を LEFT JOIN すると全件展開が走ってしまいますが、この _docsize 実テーブルの件数・最大 ID とトラッカー表を比較するだけなら、B-Tree の端を見るだけなので 0.1ms 以下で完了 します。不一致が見つかった時だけ差分行を拾いに行く二段構えにしたことで、普段の整合チェック負荷がほぼゼロになりました。
さらに 12MB ある threads_index.json と threads/ フォルダの更新日時・ファイルサイズを文字列署名(sync_meta.takeout_sig)として記録し、Takeout の取り込みが起きていない通常時は JSON パース自体を丸ごとスキップする仕組みも加えました。
移植中に実機で踏んだUTF-8文字境界の落とし穴
ここで、今回の実装テスト中に実際に踏んだ 「Rust ならではの落とし穴」 も包み隠さず共有しておきます。
全モジュールのコードを一通り書き終えて、いざ本番と同じ 572 記事のデータで最初の kb-search sync --quick を走らせた瞬間、画面に次のようなパニック(強制停止)が表示されました。
thread 'main' panicked at tools/kb-search/src/mdx_dissect.rs:1648:16:
start byte index 5 is not a char boundary; it is inside '知' (bytes 4..7 of string)
JavaScript の文字列スライスは UTF-16 コード単位なので途中で落ちることは滅多にありませんが、Rust の文字列(&str)は UTF-8 バイト列であり、日本語 1 文字(3 バイト)の真ん中のバイト位置で &text[i..] と切り出そうとすると、メモリ安全を守るために即座にパニックを起こして止まります。
原因は、ドキュメント内の記事パス(review/...)を探す高速ループで添字 i を 1 バイトずつ進めながら、うっかり文字列スライス text[i..].starts_with("review/") を呼んでいたことでした。すぐに全モジュールのスライス箇所を総点検し、バイト列のまま判定する bytes[i..].starts_with(b"review/") や境界安全な .get(start..end) へ統一した上で、日本語と数式・リンクが混在する回帰テストを --self-test に組み込みました。
あら〜、やっぱり最初はエラーが出たのね!でも、曖昧なまま文字化けしたデータをデータベースに書き込んじゃうより、「そこは文字の途中ですよ!」ってハッキリ止めて教えてくれる方が、大事な記事データを守る上ではずっと安心ね。
おっしゃる通りです!Rust はコンパイラと実行時の境界チェックがとても厳格なので、一度すべての実データテストを通過してしまえば、その後はメモリ破壊や謎の文字化けに怯えずに何年も安定して使い続けられます。
実測比較:全CLIとHooksが最大43倍速に激変
すべての配線(.agents/hooks.json の Node.js 撤廃、package.json の各コマンド切替、既存 .mjs スクリプトからの自動委譲)を終えた状態で、移行前と同じ条件(5 回ウォーム実行の中央値)で計測した Before / After 実測ベンチマーク結果 がこちらです。
ミリ秒比較でわかった各処理の高速化インパクト
空の PreInvocation でも毎回 V8 初期化と 4 ファイル連鎖 import で 94.1ms 消費。ファイル編集直後の PostToolUse は 235〜300ms、会話 DB の差分確認には 1,063.3ms かかっていました。
ネイティブ直起動なら空ターン 5.94ms(ラッパー経由でも 18.03ms)。編集直後の PostToolUse もインプロセス同期で 109.5ms、654MB 会話 DB の差分同期は 24.7ms(43倍速) で完了します。
| 処理カテゴリ・実行コマンド | 移行前(Node.js v24) | 移行後(Pure Rust 統合版) | 高速化倍率・主な改善点 |
|---|---|---|---|
会話DB差分同期 sync --convos(654MB・差分0件) | 1,063.3 ms | 24.7 ms(--quiet 42.4ms) | 約 43.0 倍速(_docsize O(1) 判定+署名キャッシュ) |
Hooks pre-invocation(未編集の通常ターン) | 94.1 ms | 5.94 ms(ラッパー込 18.0 ms) | 最大 15.8 倍速(9,000 行 ESM 読込を完全撤廃) |
公理ピンポイント取得 axiom 7.5 | 102.8 ms | 22.0 ms | 約 4.7 倍速(V8 起動税ゼロ+即座に行範囲出力) |
記事統計サマリー stats | 111.9 ms | 27.7 ms(内部 9.09 ms) | 約 4.0 倍速(知識 DB+会話 DB の 2 庫同時集計) |
セクション全文検索 search "特別会計" | 103.5 ms | 25.5 ms | 約 4.1 倍速(FTS5 trigram + SIMD スニペット) |
Hooks session-start(起動時ルール&DB同期) | 376.8 ms | 108.3 ms | 約 3.5 倍速(gemini-gate 直起動+インプロセス同期) |
見出し・枠の物理行番号抽出 --outline | 87.3 ms | 25.3 ms(内部 1.28 ms) | 約 3.5 倍速(単体記事の構造解剖は内部 1 ミリ秒台) |
アフィリエイト辞書検索 affiliate garmin | 94.4 ms | 28.9 ms(内部 2.81 ms) | 約 3.3 倍速(406 商品の ASIN・検索語を即座に照合) |
記事カルテ表示 card total-investment-roadmap | 130.4 ms | 41.0 ms(内部 23.6 ms) | 約 3.2 倍速(11 セクション統合カルテを一瞬で生成) |
連鎖波及解析 impact ... --check "200兆" | 120.9 ms | 43.3 ms(内部 25.4 ms) | 約 2.8 倍速(多軸スコアリング+生 MDX 行番号照合) |
Hooks post-tool(ファイル編集直後の自動同期) | 235.9〜300.5 ms | 109.6 ms | 約 2.2〜2.7 倍速(ルール分割と知識 DB 更新を同時実行) |
全568公開記事の監査マップ生成 --audit-map | 546.4 ms | 219.4 ms(内部 190.9 ms) | 約 2.5 倍速(RAMDisk ミラー出力まで 0.2 秒で完結) |
GEMINI.md 分割ルール25本生成 --sync-rules | 71.1 ms | 34.0 ms | 約 2.1 倍速(24KB 予算検査+差分書込) |
知識DB差分同期 sync --quick --quiet | 219.4 ms | 76.6〜106.7 ms | 約 2.1〜2.9 倍速(さらに VACUUM で DB 容量 215.4MB へ圧縮) |
全572記事と分割ルール25本の完全一致を機械証明
速度が何十倍になっても、元の Node.js 版と出力結果が 1 文字でもズレてしまったら本末転倒です。今回の移行では「たぶん合っているだろう」という目視確認を一切排し、以下の 3 段階の機械証明 をすべてクリアしてから切り替えを行いました。
-
分割ルール全 25 ファイルの SHA-256 ハッシュ完全一致 :
GEMINI.mdから自動生成される.agents/rules/gemini-overflow-1.md〜25.mdについて、旧 Node.js 版の出力と新 Rust 版(gemini-gate --sync-rules)の出力の SHA-256 ハッシュ値を比較し、25 ファイルすべてが 1 バイトの狂いもなく完全一致 することを確認しました。 -
全 572 ファイル・453 万字のゼロからの再構築で全統計カウンタ完全一致 :
kb-search sync --quick --forceでデータベースを白紙から 12 スレッド並列再構築した結果、総 MDX 572 件(公開 568 件:AI 国家 363 / レビュー 205)、解剖セクション 6,524 ブロック、正規化キー 44 軸(2,190 件・未分類 0 件)、内部リンク 4,482 本、論理鎖・公理結合 313 本(72 ノード)、生タグ 2,794 件、経済定数 156 種、アフィリエイト商品 406 件(使用中 402 件) に至るまで、旧 Node.js 版と 全項目 1 件の誤差もなく一致 しました。 -
両バイナリ内蔵の自動自己診断テスト(
--self-test)合格 :gemini-gate --self-test(全 46 テスト項目・59.7ms)とkb-search --self-test(AVX2 境界・FTS5 削除整合・FIPS 180-4 SHA-1・UTF-8 文字列境界テスト・6.7ms)がいつでも 0.1 秒未満で自動検証できる体制を整えました。
まとめ:64GB母艦の快適コストとAI段階移行手順
今回の「Node.js スクリプト群の仕分けと Pure Rust 2 バイナリ統合」で得られた結論をもう一度整理します。
-
何でも Rust 化しないのがプロの流儀 : 外部 API 通信待ち、C++ 製
libvipsで動くsharp画像変換、起動しっぱなしの常駐サーバーは Node.js のまま残すのが正解です。 -
短命 CLI・Hooks・並列 DB 同期に集中投下する : 毎回約 78ms かかる V8 起動税と約 9,000 行の ESM 連鎖読込を断ち切り、
_docsizeシャドウ表で FTS5 仮想表スキャンをなくすことで、Hooks 最大 15.8 倍速・会話 DB 差分同期 43.0 倍速 という別次元のレスポンスが手に入ります。
毎日使えば缶コーヒー1本分で回る64GB母艦構成
なお、今回のように 「16GB の RAM ディスク上に Rust バイナリとビルド一時領域を常駐」+「合計約 870MB の SQLite 2 庫を OS メモリマップでオンメモリ保持」+「12 スレッド並列コンパイル&AI エディタ稼働」 を SSD スワップ(記憶装置への退避による速度低下)ゼロで回し続けるには、やはり 64GB メモリを搭載した母艦 Mac が最高の土台になります。
推論(試算)になりますが、たとえば約 22万〜25 万円クラスの 64GB メモリ搭載 Mac 母艦を 5 年間(1,825 日)毎日開発やブログ執筆の拠点として使った場合、1 日あたりの快適コストは約 120〜137 円(缶コーヒー 1 本分、1 日 4 時間作業なら 1 時間あたり約 30 円強) です。コマンドを叩くたびの「コンマ数秒〜1 秒の待ち時間」と SSD の書き込み摩耗を同時にゼロにできる投資として、これほどストレスを減らしてくれる環境はありません。
これから現行の Apple シリコン世代で 64GB 母艦を組むなら、購入後のメモリ増設ができない設計を踏まえ、最初から 64GB ユニファイドメモリ構成を選べる Apple Mac mini(Pro系チップ・64GB構成) が長く使える本命機になります。
また、広大な 27 インチ 5K Retina 画面と 64GB メモリを手頃な予算で揃えたい方には、今回の全ベンチマークを叩き出した現役母艦 iMac 27インチ Retina 5K(2020年モデル) に、背面のメモリスロットへ工具なしで装着できる 【Intel Mac増設用】Crucial DDR4-2666 SO-DIMM メモリ を組み合わせる構成も非常に優秀です(※ DDR4 SO-DIMM は Intel Mac 専用のため、Apple シリコン搭載機には使用できません)。
そして、AI が書いた Rust コードの「所有権」「UTF-8 文字列境界」「スレッド並列」「C 言語 FFI(libsqlite3 直結)」の仕組みを手元でしっかり理解・査読したい方には、体系的な解説で定評のある定番技術書 オライリー・ジャパン『プログラミングRust 第2版』 を 1 冊デスクに置いておくと、先ほどの文字境界パニックのような場面でも迷わず原因を見抜けるようになります。

毎回よっこらしょって大きな荷物を広げてたのをやめて、よく使う道具だけ机の上(RAMDisk)に並べたから一瞬で終わったニャ。空いた時間でたっぷりお昼寝するニャ〜。
最上位AIに計測と段階的Rust化を任せる手順
最後に、ご自身のプロジェクトでも「遅くなっている Node.js や Python のスクリプトを見極めて、効果が高いものだけ安全に Rust 化したい」という方へ実践手順をお伝えします。
今回途中で遭遇した UTF-8 マルチバイト文字境界の安全性 や SQLite シャドウ表の扱い、既存スクリプトとの 100% 出力互換テスト は、軽量モデルに「全部 Rust にして!」と丸投げすると事故が起きやすいポイントです。必ず 『Gemini 4 Argon』または同等以上の最上位推論モデル を選び、以下のプロンプトをコピー&ペーストして「まず実測による仕分けと計画合意」からスタートしてみてください。
以下の記事 URL の判断基準(Rust 化すべき 4 領域 vs Node.js のまま残すべき外部 API・ネイティブラッパー・常駐サーバーの仕分け、ESM 連鎖読込の罠、UTF-8 文字境界保護、旧実装との完全一致テスト)をすべて精読してください。
https://lab.chihouzakki.com/blog/review/nodejs-v8-startup-tax-pure-rust-cli-migration/
【厳守してほしい手順】
- いきなりコードを書き換えたり Rust プロジェクトを乱立させたりせず、まず私のプロジェクト内の全スクリプト・Hooks・定期ジョブを洗い出し、実測の起動時間・実行時間・呼び出し頻度にもとづいて「最優先で Rust 化すべき処理」「中優先」「Rust 化不要(現状維持が最適)」の 3 段階に分類して日本語で報告してください。
- 私が対象範囲に合意したら、事前バックアップと自動自己テスト(旧実装との出力一致確認・UTF-8 日本語境界テスト)を組み込んだ段階的な統合計画を提示してから実装を進めてください。