mcpField
W
write-a-postmortem

write-a-postmortem

github.com/inkeepクラウド・DevOps14223 回インストール1 日前に更新
リポジトリ

write-a-postmortem について

write-a-postmortem は、証拠に基づく非難のないインシデントレビューを作成するエージェントスキルです。OpenKnowledge の Markdown ワークスペースで、時系列の整理、過去事例の確認、根本原因の分析、対応策の策定を支援します。

主な機能

  1. 01非難のないインシデント分析
  2. 02根拠を示す時系列
  3. 03関連する過去事例の検索
  4. 04トリガー、症状、原因の切り分け
  5. 05アクションアイテムとランブックの草案

活用シーン

  1. 01監視とデプロイ記録に基づく障害記録
  2. 02既知の障害パターンの再発確認
  3. 03寄与要因を検証可能な対応策へ変換

MCP 対応

OpenKnowledge MCP を使い、対象範囲の Markdown の読み取りと検索、レビュー文書の作成・編集、文書リンクの確認を行います。ソースコード、ログ、ダッシュボード、チャット記録はホストのネイティブツールで読み取ります。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/inkeep/open-knowledge-skills --skill write-a-postmortem

インストール後、Claude Code で/write-a-postmortemを入力して読み込まれたか確認します。

詳細

ポストモーテムを書く

プラットフォームの /open-knowledge スキルは、ここでのすべての Markdown 操作を引き続き規定します。対象フォルダー、読み書きツールの範囲、リンク、プレビューが対象です。このスキルはそのルールにポストモーテム作成の手法を重ねるものであり、ルールに取って代わるものではありません。

ポストモーテムは状況報告でも、責任追及の記録でもありません。証拠に基づき、1 件のインシデントを永続的かつ非難のない形で再構成し、システムの障害モードを明らかにするとともに、実際に検証されるアクション項目を生み出すものです。同じサブシステムに関わるポストモーテム同士を相互にリンクして初めて、その価値は積み重なります。そうすることで、繰り返し発生する問題の類型が見過ごされなくなります。

このパックは、プロジェクトのルートに proposals/、decisions/、specs/、postmortems/、guides/ を用意します。ポストモーテムは postmortems/ に、インシデントごとに 1 ファイル作成します。ファイル名は YYYY-MM-DD-name.md、テンプレート ID は postmortem です。ガイドに適したアクション項目については、guides/ に runbook のひな形を作成します。

ナレッジベースは OpenKnowledge MCP が管理する Markdown です。対象範囲内の Markdown の読み取りと一覧表示には exec(exec("ls -A postmortems/")、exec("cat postmortems/2024-03-02-auth-outage.md")、exec("grep -rln failover ."))と search({ query: "..." }) を使い、作成と編集には write と edit を使います。リンクグラフの確認には links を使います。対象範囲内の Markdown に対して、ネイティブの Read/Edit/Grep/Glob/cat は決して使わないでください。ソースコード、ログ、ダッシュボード、デプロイ履歴、チャットのトランスクリプトはナレッジベースの対象外です。これらの読み取りには、ホストのネイティブツールを使ってください。リンクは通常の Markdown 相対リンク [db failover](./guides/db-failover.md) にします。バッククォートで囲んだり、HTML アンカーを使ったりしてはいけません。


ステップ 0 — 非難のない記述のゲート(後続のすべてのステップを制約するため、最初に明記)

非難のない記述とは、見出しに貼り付けるスローガンではなく、機械的に徹底する規律です。以下のルールを機械的に守れないのであれば、冒頭で何をうたっていても、その文書は非難のないものではありません。

  • 個人ではなく、システムと役割を示してください。 「デプロイパイプライン」「オンコール担当エンジニア」「リリースプロセス」とし、「Alice」や「新入社員」とはしません。特定の個人を名指しすると、読者は身構え、分析はそこで止まります。
  • 人の行動ではなく、システムが何を可能にしたかを書いてください。 「デプロイパイプラインによって、レビューされていない設定が本番環境に到達できました」とし、「Alice がレビューされていない設定をデプロイしました」とはしません。文法上の主語は、その結果を可能にしたシステムにします。文の主語が人なら、システムが主語になるまで書き直してください。
  • その時点で得られた情報に照らして、人の行動はすべて合理的だったと捉えてください。 誰かの不注意がインシデントを引き起こしたわけではありません。ある人が、そのとき得られたシグナルをもとに、もっとも妥当な行動を取ったのです。分析上の問いは、「なぜそんなことをしたのか」では決してありません。「そのとき、なぜそれが正しい行動に見えたのか」です。正常を示していたダッシュボード、発火しなかったアラート、まさにその行動を指示していたランブック。妥当な判断に見せた要因を見つけてください。それが寄与要因です。

厳格なゲート。 ユーザーの意図が責任追及である場合(「Alice が本番環境を壊した件を書いて」「デプロイを台無しにしたのが誰か記録して」など)は、求められたとおりに応じてはいけません。率直にその旨を伝え、システムに関する問いへと組み替えてから書いてください。組み替えの例:「非難のない形で記録します。役に立つ問いは、誰が設定をプッシュしたかではなく、レビューされていない設定が本番環境に到達したのはなぜか、です。再発防止につながるのはその発見です。」ユーザーに求められたからといって、特定の個人を犯人とする文書を作成することは、このスキルが犯し得る最悪の過ちです。文書が築くべきポストモーテム文化を損ないます。


ステップ 1 — 経緯を書く前に証拠を集める

記憶を頼りにタイムラインを書いて、ポストモーテムと呼ぶことはできません。まず証拠を集め、そのあとで経緯を書きます。

ホストのネイティブツール(ナレッジベースの外にあります)を使って、以下を取得します。

  • アラートとモニタリング — 何がいつ発報し、本来発報すべきなのに発報しなかったものは何か。
  • デプロイとリリースの履歴 — 直前の数時間に何がリリースされ、該当するコミット/設定は正確に何か。
  • ダッシュボードとメトリクス — エラー率、レイテンシ、飽和度、発生と復旧を示すグラフ。
  • チャットの記録とインシデントチャンネル — 人が判断した時刻と、その時点での判断理由。
  • インシデント発生時点のコードと設定 — 現在の状態ではなく、インシデント発生時の状態を確認します。インシデント時の SHA の状態をチェックアウトするか、読み取ってください。

厳守事項 — 根拠を示せないタイムライン項目は記載しないでください。 タイムラインの各行には、根拠を記載します。アラート ID、デプロイ時刻、グラフ、チャットメッセージの時刻などです。誰かの記憶から出来事を再構成していて、裏付けとなる記録がない場合も記載してかまいませんが、文中に (reconstructed from recollection, no artifact) と明記してください。記録された事実と記憶をひそかに混ぜたタイムラインは、情報の欠落を認めるものよりも悪質です。読者がどの数値を信頼すべきか判断できなくなるからです。


ステップ 2 — 同じサブシステムに関する過去のポストモーテムを確認する

書き始める前に、同じことが以前にも起きていないか確認します。

  1. exec("ls -A postmortems/") — 過去のインシデントを一覧します。
  2. search({ query: "<subsystem> <failure mode>" }) — 影響を受けたコンポーネントに意味的に一致するものを検索します(例:「データベースのフェイルオーバーによるレプリケーション遅延」)。
  3. exec("grep -rln <subsystem-keyword> postmortems/") — サービス、エラー、仕組みを対象に、完全一致で検索します。
  4. exec("cat postmortems/<candidate>.md") を使って、最も関連性の高い 1~3 件を読み、根本原因とアクションアイテムを確認します。

今回がすでに記録されている種類のインシデントの再発であれば、それは文書全体で最も重要な発見です。「関連情報」に埋もれさせず、概要に記載してください。 再発は、以前のアクションアイテムが完了していなかったか、完了しても再発を防げなかったことを意味します。最初の 2 文以内に、次のように明記してください。「これは payments サービスで 3 回目に発生したコネクションプール枯渇インシデントです(2024-01-11、2024-03-02 を参照)。2 回目のインシデント後のアクションアイテムは完了されていませんでした。」ポストモーテムが真価を発揮するのは、同じ種類のインシデントが再発したときです。はっきりと示してください。


ステップ 3 — テンプレートからポストモーテムを作成する

write({ document: { path: "postmortems/YYYY-MM-DD-name.md", template: "postmortem" } })
  • 日付は今日ではなく、インシデントが発生した日付です。 停止が 2024-03-02 に発生した場合、1 週間後に執筆するとしても、ファイル名は postmortems/2024-03-02-name.md です。
  • name は、影響を受けたシステムと障害を表す短いケバブケースのスラッグです。例:payments-pool-exhaustion、auth-cert-expiry、search-index-corruption。
  • postmortem テンプレートには、SRE 形式の「概要/タイムライン/根本原因/うまくいったこと/アクションアイテム」が用意されています。以下のステップに沿って各項目を埋め、別の構成を作らないでください。

ステップ 4 — 概要:原因より先に影響を書く

概要を読むのは、残りの文書を読むことのない人たちです。当番エンジニアではなく、組織に向けて書いてください。

  • まずユーザーに見えた影響を述べます。 影響を受けた人、影響の内容、継続時間を記載します。「47 分間にわたり、チェックアウトの試行のおよそ 12% が 500 エラーで失敗しました。」とします。「コネクションプールが飽和しました。」ではありません。
  • 次に、原因を平易な一文で説明します。 「トラフィックがピークに達しているときに設定変更でプールサイズが半減し、プールが枯渇して、タイムアウトを超えてリクエストがキューに滞留しました。」
  • ステップ 2 で同じ種類の再発が見つかった場合は、概要に記載します(ステップ 2 を参照)。

技術的な説明(「14:03 にコネクションプールが飽和しました」など)から始めて、影響を後回しにした概要は、インシデントを評価する必要がある組織ではなく、エンジニア向けに書かれています。影響こそ重要な情報です。まず、人に伝わる形で示してください。


ステップ 5 — タイムライン:タイムスタンプと情報源を明記し、検知の遅れを明確にする

インシデントを時系列で再構成します。各項目には、タイムゾーン付きのタイムスタンプ、発生したこと、根拠となる証拠を記載します。

- 13:52 UTC — Config change #4821 merged, halving `pool.max` from 200 to 100. (deploy log, PR #4821)
- 14:03 UTC — Checkout error rate crosses 5%. (Grafana, checkout-errors panel)
- 14:19 UTC — First page fires to on-call. (PagerDuty incident #9917)
- 14:26 UTC — On-call acknowledges, begins investigating a suspected upstream issue. (incident channel)
- 14:41 UTC — Config change identified as cause; rollback initiated. (incident channel)
- 14:50 UTC — Error rate returns to baseline. (Grafana)
  • 検知時刻と緩和時刻を明示します。 インシデントの開始時、検知時、緩和時の項目に印を付けます。
  • インシデントの開始から検知までの時間差は、通常、文書内で最も実行可能なアクションにつながる数値です。 今回の場合、発生は14:03、最初のページ通知は14:19で、検知できない状態が16分続きました。タイムラインの直後の文章で、この時間差を明記します。「検知は発生から16分遅れました。チェックアウトのエラー率ではなく、ホストのCPU使用率に対してのみアラートが設定されていました。」この文が、最も効果の大きいアクションアイテムにつながることはよくあります。
  • 各項目は事実に基づき、情報源を明記します。分析はここではなく、根本原因の項目に記載します。

ステップ 6 — トリガー、根本原因、症状の違い

読者に3つの定義を示したうえで、明確に分けます。これらを混同すると、事後分析で浅い対策しか生み出せないことが最もよくあります。

  • 症状 — 観測されたことです。「チェックアウトのリクエストが500エラーを返し、プールの空き接続数がゼロになっていました。」症状は実際に起きたことですが、原因ではありません。症状への対処(再起動、スケールアップ)でインシデントを収束させても、次の発生を防ぐことにはなりません。
  • トリガー — 事態のきっかけとなった具体的な要因です。「設定変更 #4821 により、ピークトラフィック時にプールサイズが半減しました。」トリガーは経緯を説明するうえで必要ですが、それだけで原因のすべてを説明できることはほとんどありません。
  • 根本原因 — トリガーが障害を引き起こすのに十分な条件を生み出した要因です。「不適切な設定がプッシュされた」ではなく、「不適切な設定を、ピーク時にガードなしで本番環境へプッシュできたのはなぜか」と考えます。根本原因は、引き金となった行為ではなく、通常はセーフガードの欠如です。

最初に思いつく原因で考えるのをやめないでください。 答えが「誰かが不適切な設定をプッシュした」であれば、トリガーを特定しただけで、それ以上の追究をやめています。さらに問い続けます。レビューされていない設定が本番環境に到達できたのはなぜか。プールサイズの範囲に対する検証がなかったのはなぜか。カナリアで検出できなかったのはなぜか。「なぜ」を5回繰り返す手法などは、問い続けるのに役立ちます。ただし、これはきっかけであって証明ではありません。また、現実には複数の要因があったとしても、単一の因果関係をたどりがちです。多くのインシデントには、複数の寄与要因と1つか2つの根本原因があり、単一の直線的な因果関係があるわけではありません。トリガーが無害になっていたはずの条件を、1つか2つ特定します。


ステップ 7 — 寄与要因

影響範囲を拡大させたり、検知を遅らせたり、復旧を遅らせたりした条件です。これらは根本原因ではありませんが、インシデントが深刻化した理由であり、それぞれが通常、個別のアクションアイテムになります。

特に、次の点を確認します。

  • アラートの欠如または誤った通知先 — ステップ5で特定した検知の遅れは、ほぼ必ずここに該当します。
  • ランブックの欠如または陳腐化 — 復旧手順が文書化されていなかったため、オンコール担当者がその場で対応しました。guides/ と、その last_verified の日付を確認します。
  • 担当の不明確さ — 障害が発生したコンポーネントの担当者がわからず、確認が遅れました。
  • 古くなったガイド — 状況を悪化させる手順が記載されていた、または last_verified の日付がかなり前になっていたランブックです。
  • 状況を悪化させる条件 — ピークトラフィック、同時期のデプロイ凍結、別のオンコール担当者にもすでにページ通知が届いていたことなどです。

それぞれを個別の要因として列挙します。「コミュニケーションを改善できたはず」のような曖昧な記述は要因ではありません。「決済プールの担当者マッピングがなかったため、最初のページ通知が誤ったチームに届き、7分間遅れた」のように記載します。


ステップ 8 — うまくいったこと(実際に)

このセクションは埋め草ではありません。ひっそりと省略するのは、失敗につながるパターンです。被害を抑えた要因を特定し、組織がそれを維持できるようにしましょう。

  • 検知や復旧を、そうでなければかかった時間よりも早めたものは何ですか? 優れたダッシュボード、迅速なロールバック手順、明確なエスカレーションなどです。
  • 負荷がかかっても機能したものは何ですか? 負荷を適切に切り離したサーキットブレーカー、トラフィックを吸収した読み取りレプリカなどです。
  • 過去のアクションアイテムのうち、今回効果を発揮したものはどれですか? 以前のポストモーテムで決めた修正が今回のインシデントの影響を抑えたなら、そのことを明記してリンクしてください。アクションアイテムへの予算確保を後押しする、最も説得力のある根拠になります。

正直に書いてください。実際にうまくいったことがほとんどないなら、無理に褒める内容を作り出さず、率直にそう書きましょう。「復旧は遅く、手作業でした。うまくいったのは、ロールバックが単一のコマンドで実行できたことだけです」のように書きます。うまくいったことを維持するのも、うまくいかなかったことを修正するのと同じくらい重要です。


ステップ 9 — アクションアイテム:担当者、期限、検証可能性

担当者のいないアクションアイテムは、ただの願望です。リストに加える項目には、次の3つすべてが必要です。

  • 担当者 — 役割またはチームを指定します(非難のない表現にします。「payments チーム」のようにし、本人が自ら担当を申し出た場合を除いて個人名は使いません)。
  • 期限 — 「近日中」ではなく、具体的な日付を指定します。
  • 検証可能な完了条件 — 確認して、曖昧さなく完了と判断できる内容にします。「ステージング環境でアラートを実際に発火させてテストし、チェックアウトのエラー率が3分間にわたり2%を超えた場合のアラートを追加する」のようにします。「アラートを改善する」では不十分です。

各項目を、何を実現するものかで分類します。

  • 予防 — 同じ事象の再発を防ぎます(設定パイプラインにプールサイズの検証を追加する)。
  • 軽減 — 再発した場合の被害を抑えます(プールが上限に達した際に、自動で負荷を切り離す)。
  • 検知 — より早く発見します(ステップ 5 で不足していたエラー率アラート)。

健全なポストモーテムには、3種類すべての項目があります。予防だけのリストは、検知と軽減の不足が検討されていないことを示している場合がよくあります。

ガイドに関するアクションアイテムからは、ランブックのひな形が生まれます。 「X の復旧ランブックを作成・修正する」という項目では、名前を挙げるだけでなく、その場でひな形を作成します。

write({ document: { path: "guides/db-pool-exhaustion-runbook.md", template: "runbook" } })

ひな形には、症状(再発したときにどう認識するか。「チェックアウトで500エラーが発生し、プールの空き接続数がゼロ」など)と、関連するタイムラインの抜粋(ステップ 5 から抜き出した、実際にうまくいったロールバック手順)をあらかじめ記入します。その後、アクションアイテムからひな形にリンクします。- [ ] Payments team, by 2024-03-16: complete the [pool-exhaustion runbook](./guides/db-pool-exhaustion-runbook.md), verified by a tabletop dry-run. ランブックには last_verified のフロントマターがあるため、古くなるとレビュー時に表示されます。


ステップ 10 — リンクと検証

  • ## Related セクションを追加し、サブシステムを共有するすべての過去のポストモーテム(ステップ 2)と、関係する decisions/ および specs/ をリンクします。たとえば、設定ポリシーを定めた決定事項や、障害が発生したコンポーネントの仕様です。[2024-01-11 payments pool](./postmortems/2024-01-11-payments-pool.md)、[connection-pool sizing decision](./decisions/2023-11-04-pool-sizing.md)。
  • ステップ 9 で作成したランブックのひな形を、それぞれのアクションアイテム(上記のとおり)と ## Related からリンクします。
  • 変更したフォルダーにハブがある場合(postmortems/ の INDEX.md など)は更新し、新しいインシデントがインデックスに表示されるようにします。プレビューがリアルタイムの進捗バーになります。
  • 検証します。audit({ path: "postmortems/YYYY-MM-DD-name.md" }) の実行結果が問題なし(すべてのリント違反と内部リンク切れがない状態)になるよう、指摘事項をすべて修正します。フロントマターに不足がないこと、Summary/Timeline/Root cause/What went well/Action items の各セクションがすべて記入され、テンプレートのプレースホルダーのまま残っていないことを確認します。

ステップ 11 — 振り返り

会話を締めくくる際は、次の4点を簡潔に伝えます。

  1. 影響を、ユーザーに見える形で1行にまとめます。
  2. 根本原因を1文で説明します(きっかけではなく、原因となった条件です)。
  3. 最も効果の高い単一のアクションアイテムを示します。通常は、検知のギャップを埋めるもの、または不足していたセーフガードを補うものです。
  4. 同じ種類の問題が再発したかどうかを示します。再発した場合は、以前の修正が機能しなかった理由も説明します。

次に、ファイル postmortems/YYYY-MM-DD-name.md と、作成したランブックのドラフトを示します。


対象外

  • 個人に責任を負わせないでください。 対象はシステムと役割であり、個人ではありません。ある人の名前がストーリーの要となっているなら、ストーリーの立て方が誤っています。代わりに、システム上で可能だったことを見つけてください。
  • もっともらしい原因が最初に見つかっても、そこで止めないでください。「不適切な設定がデプロイされた」はきっかけです。そのきっかけを十分なものにした要因を問い続け、不足していたセーフガードにたどり着いてください。
  • 検証できないアクションアイテムを書かないでください。 担当者、期限、確認可能な完了条件がなければ、それはアクションアイテムではなく願望です。記載しないか、内容を整えてください。
  • 「うまくいったこと」を黙って省略しないでください。 省略すると、維持する価値のある取り組みが失われます。うまくいったことがほとんどなければ、セクションを削除するのではなく、正直にそう記載してください。
  • ポストモーテムを、設計上の判断を蒸し返す場にしないでください。 ポストモーテムには、何が起きたか、運用上何を変えるべきかを記録します。アーキテクチャを変えるべきだったという議論は、提案(/frame-a-proposal)または設計レビュー(/review-a-design)で行い、関連項目からリンクしてください。ここで議論を続けないでください。
  • タイムラインを捏造しないでください。 参照できる情報源のない項目を記載しないでください。記憶をもとに再構成した項目には、その旨を行内に明記してください。

コメント