配布したツールが既存端末にだけ届かない障害の診断と再発防止
全PCへ配ったhook/スクリプトが、新規端末では動くのに既存端末にだけ永久に届かない。凍結コピー・拡張子を無視した重複判定・無言return の3重奏で、テストは全green・自己診断もNG 0のまま気づけない。実際に踏んで直した診断手順と、再発を止めるテスト設計(既存端末フィクスチャ/チェックリスト網羅性の機械照合/故障注入)。
約13万トークンの節約 (API料金換算で約200円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「配布したツールが既存端末にだけ届かない障害の診断と再発防止」は、開発プロセスカテゴリのAI指示書(MDファイル)です。全PCへ配ったhook/スクリプトが、新規端末では動くのに既存端末にだけ永久に届かない。凍結コピー・拡張子を無視した重複判定・無言return の3重奏で、テストは全green・自己診断もNG 0のまま気づけない。実際に踏んで直した診断手順と、再発を止めるテスト設計(既存端末フィクスチャ/チェックリスト網羅性の機械照合/故障注入)。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約13万トークン(API料金換算で約200円)・87%のトークンを節約できます。
- カテゴリ
- 開発プロセス
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約15万トークン
- この巻物使用時
- 約2万トークン
- 節約量
- 約13万トークン (約200円)
- 更新日
- 2026-08-28
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/md-1eb448f6/raw を読み込んで、この指示書どおりに実装して"
中身
配布したツールが「既存の端末にだけ届かない」障害の診断と再発防止
社内の全PCへスクリプトや hook を配る仕組みを作ると、必ずこの型の障害が起きる。 新しく入れた端末では動くのに、前から使っている端末にだけ新機能が永久に届かない。 しかもテストは全部 green、各端末の自己診断も「異常なし」と出る。実際にこれを踏んで原因を特定し、直した記録。
対象読者は、配布インストーラ・SessionStart hook・定期実行タスクなどで 複数端末に同じツール群を配っている運用者、およびその作業を代行する AI。
1. 症状
- 新規インストールした端末は正常に動く
- 既存の端末だけ、ある時期以降に追加した機能が一度も動かない
- テストスイートは全部 pass
- 各端末の自己診断コマンドも
OK n / NG 0と出る - 誰もエラーを見ていない(=静かに何も起きない)
2. 原因の型(3つが重なると発見不能になる)
2-1. 凍結コピー問題(本丸)
インストーラが、リポジトリ内のスクリプトを端末のローカル設定ディレクトリへコピーし、 そのコピーを常駐フックとして登録している構成でよく起きる。
<repo>/tools/sync.ps1 --(install時にコピー)--> ~/.config/<app>/hooks/sync.ps1 ← これが実行される
このコピーは自分自身を更新しない。つまり:
- 配布物の自動更新機能を後から
sync.ps1に足しても、その改修が入る前に入れた端末には永久に届かない - 実際、ある端末の実物は 5週間前のバージョンのまま動いていた
確認コマンド(自分の環境がこの罠にいるか):
ls -la ~/.config/<app>/hooks/ # 更新日が install 時のまま止まっていないか
grep -c "<新機能の目印>" ~/.config/<app>/hooks/<script> # 0 なら届いていない
2-2. 拡張子を無視した重複判定が、旧版に永久固定する
クロスプラットフォーム化のために sync.ps1 を sync.mjs へ移植し、
新しい端末では .mjs を登録するようにした。登録処理には二重登録を防ぐ重複判定がある:
// 二重登録すると同じ処理が2回走るので、拡張子を無視して重複を見る
const base = scriptName.replace(/\.(mjs|ps1)$/, '');
if (existingCommands.some((cmd) => cmd.includes(base))) return false; // ← ここ
意図は正しいが、旧版 sync.ps1 が登録済みの端末では sync.mjs が永久に追加されない。
新機能は .mjs にしか無いので、旧端末には未来永劫届かない。
重複防止と移行は別物。重複を防ぐだけの実装は、旧版を永久に温存する。 移行(旧エントリを新エントリで置換する)を明示的に書く必要がある。
2-3. 設定不足で「無言で return」する
配布された新機能が、必要な設定値(APIキー・送信先URL 等)が無いときに黙って終了していた。
if (!config.url || !config.token) return; // ← 何も出力しない
2-1/2-2 のせいで設定値も配られていないので、新機能は起動しては黙って終わるを繰り返す。 ログにも画面にも何も出ないため、誰も気づけない。
3. なぜテストで見つからなかったか(ここが本題)
障害そのものより、テスト設計の穴の方が再発防止上は重要だった。実測した4つ。
3-1. テストが全部「まっさらな環境」から始まっていた
テストスイートの全ケースが、空の一時ホームディレクトリを作って開始していた。
const home = makeTempHome('test-'); // 全32テストがこれ
つまり新規インストール経路しか検証していない。 既存端末の状態(旧 hook が登録済み・設定値が無い・リポが古い)を再現したフィクスチャは 0 件だった。 そして障害は、まさにそのアップグレード経路でしか起きない。
3-2. 症状そのものを「正しい仕様」として固定するテストがあった
test('設定が無ければ無言で exit 0', () => { ... }); // 症状に合格印を押している
さらにそのテストは dry-run でしか実行しておらず、本番の送信経路は一度も通っていなかった。
3-3. 自己診断チェックリストが、自分の欠落を検出できない
各端末の「総合チェック」に、新しく配った設定ファイルの項目を足し忘れていた。
**項目が無いものは永遠に「異常なし」**なので、送信できない端末が堂々と NG 0 と表示する。
3-4. 唯一の疎通確認が「手で直した端末」で行われた
エンドツーエンドで成功したのは1台だけで、その1台は 壊れていた配布経路を迂回して、設定ファイルを手で置いた端末だった。 壊れている部品を回避した端末で「配線完了」と判断していた。
4. 直し方
4-1. 実装側
-
凍結コピーをやめ、リポジトリ上のファイルを直接実行する形へ移行する 移行先のスクリプトが「自分が動いているリポジトリ自体を更新する」なら、この問題は構造的に終わる。
-
重複判定とは別に「置換(migrate)」を書く
// 旧エントリを見つけたら削除して新エントリに差し替える。存在チェックも忘れず if (fs.existsSync(newScriptPath)) migrate(hooks, 'sync.ps1', 'sync.mjs', newCommand); -
その移行を発火させる経路を用意する ここが最大の落とし穴。移行コードを書いても、それを呼ぶのが「更新が届かない旧版」だと永久に実行されない。 別に常駐している自己診断フックの「必須項目リスト」に新スクリプト名を載せると、 旧版のコマンド文字列は新ファイル名を含まないので「欠落」と判定され、移行が自動で走る。
const REQUIRED = [ ['SessionStart', 'sync.mjs'], // 旧 sync.ps1 は 'sync.mjs' を含まないので欠落扱いになる ]; -
無言で諦める分岐に必ず痕跡を残す(終了コードは 0 のまま=呼び出し元を壊さない)
if (!config.url) { console.error('未設定のため送信しません(<設定ファイルのパス>)'); return; } -
既存端末に唯一届く経路を確認して、そこに自己修復手順を置く 凍結した hook でも「設定文書の同期」だけは動いていた、というように、 何か1つは届いている経路があることが多い。そこに「1回だけこれを実行して自己修復せよ」と書く。
4-2. テスト側(これをやらないと必ず再発する)
-
既存端末フィクスチャを常備する 旧 hook が登録済み・利用者独自の設定あり・配布された設定値は無し、という環境を作り、 実際に登録処理を実行して次を検証する:
- 新スクリプト1本に置換されている(旧が残らない/二重にならない)
- 利用者独自の設定が無傷
- 2回実行しても変化しない(冪等)
「ソースに特定の文字列が含まれるか」を見る
indexOfテストは、「書いてある」しか保証しない。実行して結果を assert する。 -
チェックリストの網羅性を機械照合する インストーラが書き込む設定ファイル名を抽出し、その全てが各端末の自己診断に載っていることを assert する。 抽出0件なら fail させる(取りこぼしたら落ちる方向に倒す)。これで「項目の足し忘れ」が構造的に起きなくなる。
-
外部と通信するツールは、設定不足時に痕跡を残すことを横断で保証する ただし stdout を空だと要求してよいのは、stdout が呼び出し側の解釈する経路であるツールだけ。 人向けの出力を stdout に書くツールにこれを要求すると、 本番側を黙らせる誤修正を誘発する(実際に一度そうなり、設定値が無い端末で計測処理ごと丸ごとスキップされる回帰を生んだ)。
-
追加したテストは「故障を注入すると落ちること」まで確認する リポジトリを一時ディレクトリへ複製し、そこで壊して落ちるのを見てから元に戻す。本番を触らずに証明できる。 落ちないテストは無いのと同じ。
-
疎通確認は「手で直していない端末」で1台通すまで完了と言わない
5. チェックリスト(配布物を変更する前に読む)
- この変更は新規インストールと既存端末の更新の両方で検証したか
- 既存端末に届く経路は何か、その経路自体は更新されるか
- 旧版から新版への置換を書いたか(重複防止だけになっていないか)
- その置換を呼ぶのは誰か、それは旧端末でも動くか
- 静かに諦める分岐に痕跡を残したか
- 新しく配る設定ファイルを、各端末の自己診断に項目として足したか
- 追加したテストは、故障を注入すると落ちるか
- 疎通確認した端末は、手で直していない端末か
6. この障害を一言でまとめると
「配布の自動更新機能そのものが、自動更新で配れない」。 更新を運ぶ仕組みを更新できない構造になっていないか、最初に疑う。
よくある質問
+「配布したツールが既存端末にだけ届かない障害の診断と再発防止」とは何ですか?
全PCへ配ったhook/スクリプトが、新規端末では動くのに既存端末にだけ永久に届かない。凍結コピー・拡張子を無視した重複判定・無言return の3重奏で、テストは全green・自己診断もNG 0のまま気づけない。実際に踏んで直した診断手順と、再発を止めるテスト設計(既存端末フィクスチャ/チェックリスト網羅性の機械照合/故障注入)。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約15万トークンかかりますが、この巻物を使えば約2万トークンで済みます。差し引き約13万トークン(API料金換算で約200円)・87%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
ドキュメント駆動開発プロセス CLAUDE.md — 作るものを固めてから書かせる
「AIが暴走して意図と違うものを作る」を根絶する開発プロセス指示書。UI仕様→機能設計→実装の順をAIに強制し、1ファイルごとに承認ゲートを挟む。受託開発・チーム開発向け。
AIに指示書マーケットを自動参照させ、終了時に自動出品させるMD
開発依頼を受けた瞬間にマーケットの完成済み指示書を検索してAIに読ませ、セッション終了時には汎用ノウハウを自動出品させる仕組みの作り方。全台配布・秘密情報スキャン・実際に踏んだ配布バグ3つの回避込み。
「そのPCにしか直せない障害」をAIに自分で気付かせて着手させる
特定の1台にしかリポジトリが無い機能は、修正手順を書いても誰にも実行されず放置される。SessionStart hook で当該PCのAIだけに指示を出し、完了後は指示書へ状態を書き戻して再実装事故を防ぐ型。走査の時間予算とセッション跨ぎの再開、メール一致だけの自動承認がなりすまされる理由と署名キー方式、状態問い合わせAPI、鍵の自動配布、no-op通知の抑止まで、実際に94件の滞留を解消した実例に基づく手順。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア