never-twice について
Never Twiceは、障害を分析し、同じ種類の再発を防ぐ対策を選ぶスキルです。構造的な修正を優先し、次にCIチェックを検討します。より強い対策が実現できない場合に、文書化したルールを使います。
主な機能
- 01繰り返す障害パターンの分類
- 02持続性に基づく対策の優先順位付け
- 03実際の障害を再現するフィクスチャの要求
- 04障害が起きる場所へのガード配置
- 05削除されるルールやチェックの監査
活用シーン
- 01繰り返す修正を構造変更に置き換える
- 02再現可能な障害にCIチェックを追加する
- 03インシデントにガードが必要か判断する
- 04既存の防止策を削除する変更を確認する
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vivswan/ skills --skill never-twiceインストール後、Claude Code で/never-twiceを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSE.mdREADME.md.codex-plugin/plugin.jsonagents/openai.yaml詳細
二度と繰り返さない
アーキテクチャを改善するか、より適切なデータ構造を選ぶことで、問題を根本からなくし、同じ種類の障害が再発しないようにします。個々の事例を一つずつ修正するよりも、こちらが優れています。
以下の基準を満たすあらゆる障害(エージェントへの修正の大半を含みます)には、到達可能なかぎり最も永続的な対策を適用します。
| 段階 | 対策 | この種の障害が今後も起こり得るか | 優先度 |
|---|---|---|---|
| 1 | アーキテクチャまたはデータ構造の改善 | 再発しない | 目標 |
| 2 | CI のリンタールールまたはテスト | 再発するが、取り込まれない | 許容可能 |
| 3 | スキルまたは文書化されたルール | 再発するが、次のエージェントには伝わる | 最終手段 |
| 4 | 人間の注意による監視 | 何でも起こり得る | 避ける |
この段階は選択肢の一覧ではありません。下に進むほど、優先度は指数関数的に下がります。段階 1 が目標で、段階 2 は明らかに劣るものの許容可能なゲートです。段階 3 と 4 はさらに大きく後退するため、より上位の段階が本当に実現不可能な場合に限って採用します。
段階 3 または 4 で対処したものは、解決ではなく負債です。上位の段階が実現可能になったら、ルールや注意喚起をその段階へ引き上げてください。
**この段階を支える基準:**障害にガードを設けるかどうかは、件数や一覧表で決めるのではなく、シナリオごとに判断します。判断の軸となるのは、障害を再現できるか、原因を具体的に理解しているか、通常運用で発生条件がどの程度の頻度で生じるか、そしてガードのコストと設置場所はどこか、という四つの問いです。
エージェントへの修正では、この四つの問いへの答えが自ずと明らかになります。デフォルトの挙動が具体的な原因であり、あらゆるプロンプトが発生条件となるため、通常は一度の修正で基準を満たします。「起こりやすい」とは、通常運用で発生条件が頻繁に生じることを意味します。障害(forge の停止や依存サービスの停止)は、起こりにくい発生条件の典型例です。
要求どおりに再現できても、デスク上で再現できるとは限りません。原因を具体的に把握しており、CI でしか起こらない、またはローカルでは準備できないものが必要で、実際の実行でも繰り返し発生する条件については、同じように判断できます。原因は特定済みで、発生条件も起こりやすいからです。
どのシナリオにも、二つの制約が適用されます。フィクスチャーは観測された障害を再現するものであり、再現なしに作成してはなりません。また、別の場所にある条件を代わりに再現するローカルフィクスチャーを作ってはなりません。ガードは、その条件が存在する場所に設けます。原因不明で再現できていないインシデントは記録しますが、ガードは設けません。
記録(発生した場所、観測された内容)は、インシデントを扱う PR の本文、レポート、または Issue に記載し、ルールには含めません。「二度起きた」という事実は判断材料ですが、それ自体が発生条件になるわけではありません。判断に迷う場合はユーザーに尋ねてください。黙って実装したり、何も言わずに見送ったりしてはなりません。
以下は判断の具体例であり、すべてを網羅するものではありません。
- リリースのステップが、誰かが事前に手作業でバージョンファイルを編集することに依存しています。編集を省けば障害が再現し、すべてのリリースでそのステップが実行され、バージョンの自動導出は 1 行で済むため、ステップ内でバージョンを導出します。
- マージ競合の原因はコードから把握できており、2 回のプッシュが 1 分以内に到着すると必ず競合が発生する可能性があります。デスク上では再現できませんが、通常運用ではそのタイミングが頻繁に発生します。そこで、競合が発生する場所であるマージステップに数行のロックを設けて順序を制御します。作為的なフィクスチャーは作りません。
- チェックが失敗するのは、CI ランナーのイメージが夜間に再構築された後だけで、ローカルでは起きません。原因は具体的で、再構築は毎晩行われ、パイプラインでイメージを 1 ステップ検査するコストも低いため、条件が存在する場所にガードを設けます。つまり、CI 側にトリップワイヤーを設置します。
- forge が 10 分間停止し、プッシュに失敗しました。通常運用で停止が起こることはまれなので、プッシュを再試行して事象を記録し、修正が依然として妥当と思われるかユーザーに尋ねます。
- レビューランチャーのスクラッチディレクトリが、実行中に一度消失しました。再現できず、原因も不明なため、実行を再開して事象を記録し、ガードは設けません。
ワークフロー
- クラスを定義します。「新しい Event メンバーは、名簿に追加しなくてもリリースできる」と一文で説明します。できない場合、まだクラスとして成立していません。インスタンスを修正して先に進みます。
- 基盤を見つけます。新しいメンバーを受け入れるものを探します。慣例によって同期されている2つの成果物、本来は閉じた集合にすべき場所にある文字列、文章として保持されている状態、手作業で入力する手順などです。
- 可能な限り段を上がります。タスクで可能な範囲で、最も上の段を目指します。タスクの範囲と権限の中で実装できる、最も永続性の高い段を選びます。
- リリースします。 下位の段で代替する場合は、より永続性の高い段とのギャップを報告書に明記してからリリースします。そのギャップをタスクとして作成する権限がある場合は、独立したタスクとして記録します。メモとして放置してはいけません。メモは文章として保持される状態であり、そのクラスを招き入れた基盤だからです。
リリースしたものをテストします。
明日、このクラスに新しいメンバーが加わった場合、修正は有効ですか。それとも、同じように気付かれずに通過しますか?
答えは3つです。
- 気付かれずに通過する:クラスはまだ存在しています。
- 遅れて大きなエラーになる(実行時、リリース後):インスタンスのガードです。クラスはまだ存在しています。
- それを防ぐ段で再発できない:構築不可能(1)、CI で阻止(2)、読み込まれたルールで検出(3)。
段1:クラスが再発できない
イベントの列挙型が、そのイベントをディスパッチする名簿よりも増え続けています。
// Fix 1 shipped Event.Deleted's missing entry. Fix 2 shipped
// Event.Archived's, plus a guard. Both read as complete:
handlers[Event.Archived] = onArchived;
assert(Object.keys(handlers).length === EVENT_COUNT); // fires at runtime, after the hole ships
// Rung 1: the roster is total, so the hole cannot be built:
const handlers: Record<Event, Handler> = {
[Event.Created]: onCreated,
[Event.Updated]: onUpdated,
[Event.Deleted]: onDeleted,
[Event.Archived]: onArchived,
};
// A new member fails compilation until the roster covers it.
型レベルの仕組み(閉じたユニオン、ブランド型、型状態)は、/no-invalid-states スキルで扱います。
段2:再発するが、取り込めない
同じクリーンアップが、手作業で何度もコミットされています。
$ git log --oneline -- docs/
9e8f7a6 fix: replace curly quotes with ASCII
a1b2c3d fix: replace curly quotes with ASCII (again)
# Rung 2: a CI check, marked required in branch protection.
# Fail-closed: hits and grep errors both fail; only "no matches" passes.
- name: check-typography
run: |
status=0
grep -rnP '[\x{2018}-\x{201D}\x{2014}]' docs/ || status=$?
test "$status" -eq 1
段3:再発するが、次のエージェントには伝わる
同じ修正が、セッションをまたいで何度も伝えられています。
"Timestamps in logs are ISO 8601, not epoch." (Tuesday)
"ISO 8601 in logs, please." (Thursday, new session)
# Rung 3: the correction becomes a rule in a file every session loads.
$ tail -1 AGENTS.md
Log timestamps are ISO 8601 (2026-08-26T14:03:00Z), never epoch.
ルールの書き方(置き場所、発動条件、品質基準)は、/craft-skills-and-memories スキルの役割です。この段では、読み込まれたルールを対応策とするかどうかを決めたうえで、そのスキルに引き継ぎます。
ガードの削除(チェスタトンの柵)
この段階的な仕組みはガードを設けるものであり、このルールはそれを取り除く場合に適用されます。ルール、ガード、チェックを削除する際は、なぜ設けられたのかを説明できないまま削除してはいけません。変更で行う削除はすべて、次の2つのどちらかに対応していなければなりません。そうでなければ、何も取り込みません。
- そのクラスをカバーする後継:ルールを体現するスクリプト、より強い段、ルールを維持する言い換え
- 理由を変更に記録した、意図的な削除
実例:ドキュメントの書き直しで、長年使われていたルールの行が90行削除されました。各行を後継/言い換え/明示的な削除として監査したところ、対応付けられていない実質的な損失が1つだけ見つかり、取り込み前に復元されました。
監査が仕組みです。このルールは、誰かが気付いた後の救済措置ではなく、すべての削除に対する既定の手順として監査を位置付けます。
この組み合わせが重要です。削除が監査されるからこそ、大胆な書き直しが認められます。大胆な削除を安全にするのは監査であり、監査は削除の歯止めではありません。
レビュー基準
コードレビューを行うスキル(/rubber-duck-review など)は、このスキルがインストールされると、このセクションをレビュープロンプトに展開します。レビュー担当者には、次の点を指摘するよう依頼してください。
- 同じ障害クラスに対する以前の修正を繰り返している修正。推測ではなく、根拠(過去のコミット、ドキュメントの行、または修正)を示します
- それぞれについて、その修正がどの段に位置するかを示し、より耐久性の高い具体的な段を提案し、この変更の範囲内で実現可能な理由(または実現不可能な理由)を述べます
- リリースされるものすべてにこのテストを適用します。そのクラスの新たな事例が明日発生した場合、ビルドできないのか、CI で止められるのか、読み込まれたルールで検出されるのか、それとも見逃されるのかを確認します
- 対象クラスをカバーする後継のルール、ガード、チェックにも、変更内に理由を記録した意図的な削除(上記の「ガードの削除」に記載)のどちらにも対応付けられない、ルール、ガード、チェックの削除
- 基準となる判断(上記「基準」)が裏付けていないガード。原因不明の未再現インシデントに対するガード、ユーザーの確認なしにガードする未再現のまれなトリガーや判断が不明確なケース、または観測された障害を再現しないフィクスチャ
- 基準となる判断がガードを支持するにもかかわらず、ガードを設けずに個別の事例だけを修正しているケース(具体的な原因があり、通常の操作で頻繁に発生するトリガーがあり、コストに見合うガードがある場合)。この修正は段階を上げる必要があります
ワークフローに従って、該当する指摘をトリアージしてください。