運用・障害対応学習記事全11節Operate

「提出したのに履歴が残らない」申告から、初動手順をたどる

この記事で身につくこと記録(ログ)、通知、利用者の申告という3つの入口から、症状→事実確認→仮説→切り分け→原因→暫定対応→恒久対応/残課題の順で初動を進め、影響範囲と対応区分を判断する流れを説明できる。

記事内目次(24項目)
この記事の管理情報(該当工程・関連要件・成果物の閲覧と保存・実行記録)
記事ID
12-02
該当工程
12-02 異常を検知し影響を判断する(関連:12-01、08-04、10-03、08-03、12-03、11-04)
関連要件
REQ-005、REQ-007
到達目標
記録(ログ)、通知、利用者の申告という3つの入口から、症状→事実確認→仮説→切り分け→原因→暫定対応→恒久対応/残課題の順で初動を進め、影響範囲と対応区分を判断する流れを説明できる
主要な成果物
確認環境と検証状況
題材の障害は 08-04 の正本(storage_v2.js)で再現できる部分失敗に合わせ、演習コード examples/12-02-incident-response/investigate.js を正本として、Claude Codeが2026-09-21にローカルで再現・調査を実行し stdout・stderr・終了コードを記録済み。Phase 5B-2C1で、記録を読まずに書かれていた初版の申告(承認したのに状態が変わらない)を、再現できる失敗に合わせて書き直した。申告は想定例で、実際に発生した障害ではない。人による実読・内容確認は未実施。
未検証の範囲
実際の利用者からの申告と対応、通知の入口(未実装)、不整合データ(REQ-0003)の扱いの決定、恒久対応(トランザクション)の適用は、この記事の時点では確認・決定していない。09-04・10-04から引き継いだ残課題は初動まで回収、設計判断は未決。
実行記録

正本の原稿にある管理表(記事ID・先に読むと理解しやすい記事・成果物パス・最終更新日など)は、この下の本文冒頭に「原稿の管理表」として開閉できる形で残しています。

原稿の管理表(13項目:記事ID・カテゴリ・要件ID・先に読むと理解しやすい記事・成果物パス・対象ツール・検証状況・最終更新日など)
管理項目内容
記事ID12-02
主な中カテゴリ12-02 異常を検知し影響を判断する
関連中カテゴリ12-01、08-04、10-03、08-03、12-03、11-04
関連要件IDREQ-005、REQ-007
先に読むと理解しやすい記事12-01(稼働状況・業務結果・費用を把握する)、08-04(エラー処理と保守しやすさを整える)を読んでいると理解しやすい。未読でも本文で必要な内容は説明する
到達目標記録(ログ)、通知、利用者の申告という3つの入口から、症状→事実確認→仮説→切り分け→原因→暫定対応→恒久対応/残課題の順で初動を進め、影響範囲と対応区分を判断する流れを説明できる
3層の配置理解する=第3〜4節/作って確かめる=第5〜7節/設計を判断する=第8節
対象ツール・バージョンNode.js v24.18.0(標準機能 node:fs・node:path のみ。追加パッケージなし。実行記録は macOS 26.6.2 で取得)
成果物パスtemplates/12-02-incident-response_template.md、templates/12-02-incident-response_example.md、examples/12-02-incident-response/(investigate.js)、evidence_public/phase5b2c1-2026-09-21/12-02/run_log.md
出典第11節参照
検証状況題材の障害は 08-04 の正本(examples/08-04-error-handling/storage_v2.js)で再現できる部分失敗(状態は「提出済み」に変わったが履歴の書き込みに失敗)。演習コード examples/12-02-incident-response/investigate.js を正本とし、Claude Codeが2026-09-21にローカルで実際に再現・調査を実行して stdout・stderr・終了コードを記録済み(第6〜7節、evidence_public/phase5b2c1-2026-09-21/12-02/run_log.md)。申告は想定例で、実際に発生した障害・実際の利用者による申告ではない
残課題第11節参照
最終更新日2026-09-20(新規作成)。2026-09-21(Phase 5B-2C1:初版の申告「承認したのに状態が変わらない」は 08-03・08-04 のどの失敗とも一致せず、記録も読まずに書かれた想定だった。08-04 で再現できる部分失敗に題材を合わせ、実際の記録(状態・履歴・失敗ログ)を読む演習コードを追加し、症状→事実確認→仮説→切り分け→原因→暫定対応→恒久対応/残課題の順に書き直した。09-04・10-04 から引き継いだ残課題のうちこの記事で回収する範囲を明記。読む順路・第4節の判断項目・第5.4節「演習の設計」・第7節の確かめていないこと・CHECKLIST を追加)。2026-09-21(Final Content Audit:題名を「承認したのに状態が変わらない」から「提出したのに履歴が残らない」に改め、Phase 5B-2C1 で変えた本文の題材(08-04 の部分失敗)と一致させた。本文・コード・実行結果は不変)

この記事の会社・人物・データはすべて架空の設定です。実在する会社や案件とは関係ありません。この記事の障害は、08-04 の正本で再現できる部分失敗をローカルで実際に再現したものですが、申告(誰が何を言ったか)は想定例であり、実際に発生した障害・実際の利用者からの申告ではありません(第7節)。

この記事は何の話か。「提出したら『履歴の記録に失敗しました』と表示されたが、一覧では提出済みになっている」という依頼者からの申告を例に、記録(ログ)・通知・利用者の申告という3つの入口から、症状→事実確認→仮説→切り分け→原因→暫定対応→恒久対応/残課題の順で初動を進め、影響範囲を判断し、拡大防止と関係者連絡を行う手順を作る話です。題材の障害は08-04で再現できる部分失敗(状態は変わったが履歴の保存に失敗)です。

なぜ必要か。12-01で運用項目を決めても、実際に異常が起きたときに何をどう確認し、誰に連絡するかが決まっていなければ、対応が後手に回ります。申告の言葉をそのまま信じて対応すると、原因を取り違えます。記録を読んで事実を確かめ、事実と矛盾する仮説を消していく順序が必要です。

この記事を読むとできるようになること。

  • 記録(ログ)、通知、利用者の申告という3つの入口から、影響範囲と初動の優先順位を判断する流れを説明できる
  • 申告を受けたら、状態ファイル・履歴ファイル・失敗ログを読んで事実を確かめ、仮説を切り分けて原因に至る手順をたどれる
  • 暫定対応(拡大防止・関係者連絡・切戻しの要否)と恒久対応/残課題を分けて、異常時の初動手順に書ける
  • 影響の大きさに応じた対応の区分(様子見/即時対応/利用停止)を判断できる

読む順路。この記事は3つの深さで読めます。全部を順に読む必要はありません。

  • 基本だけ理解する:第1節→第3節(3つの入口、症状から原因までの順序、申告と事実の違い)→第4節(判断すること)→第5.1〜5.2節(申告と、確認する記録)→第6.2節の初動手順の表→第9節。コードを読まなくても、申告を受けてから何を読み、何を消し、何を暫定対応にするかが分かります。
  • 作って確かめる:上に加えて第5.3節(演習コード)→第5.4節(演習の設計:実行前に見るもの・失敗したとき・戻せるか・誰が)→第6.1節の実行結果→第7節(確かめたこと・確かめていないこと)。
  • 設計判断を深める:上に加えて第8節(対応区分の判断、切戻しの要否、残課題の回収範囲、適用限界)。

1. 今回の業務課題と完成するもの

この記事でやることは、依頼者役からの申告「提出したら『履歴の記録に失敗しました』と表示されたが、一覧では提出済みになっている」を例に、確認する記録、影響を受ける役割と依頼、仮説の切り分け、原因、暫定対応(拡大防止、関係者連絡、切戻しの要否)、恒久対応/残課題を異常時の初動手順にまとめることです。

12-01では定期的に確認する運用項目を決めましたが、想定外の異常が起きたときにどう動くかはまだ扱っていませんでした。この記事では、それを扱います。

この記事を読み終えると、次のものが手元にできます。

  • 異常時の初動手順(入口、症状、確認する記録と事実、仮説と切り分け、原因、影響範囲の判定、対応区分、暫定対応、恒久対応/残課題、初動の担当、連絡先)
  • 記録を読んで切り分ける演習コードと、その実行記録

2. 前提知識と読む順路

この記事で使う言葉を先に説明します。

入口

一言でいうと、異常に気づくきっかけです。この記事では、記録(ログ)、通知、利用者の申告の3つを扱います。

部分失敗

一言でいうと、ひとつの操作の中で、一部の保存だけ成功し、残りが失敗した状態です。08-04では、状態は「提出済み」に変わったのに履歴の保存が失敗する例を再現し、失敗ログを残すようにしました。この記事の題材はその失敗です。

切り分け

一言でいうと、考えられる原因(仮説)を並べ、記録から分かる事実と矛盾するものを消していくことです。残った仮説を、失敗ログの内容で裏付けて原因とします。

拡大防止

一言でいうと、これ以上被害・混乱が広がらないようにする、初動の対応です。原因の完全な特定より先に行います。

これがないと、異常に気づいてから、何を確認すればよいか、誰に連絡すればよいかを都度考えることになり、対応が遅れます。

読む順路:運用項目は12-01、失敗ログは08-04、通信失敗の種類は08-03、問い合わせ手順は10-03、切戻しは11-04が該当します。この記事の初動手順は、12-03(記事C)の障害対応の入口になります。

3. 理解する:3つの入口から、症状→原因の順にたどる

3.1 記録・通知・申告

入口内容この記事での例
記録(ログ)08-04 で作った失敗ログのように、システムが自動的に残す記録失敗ログに履歴の書き込み失敗が1件記録されている(第6.1節の手順2)
通知基準を超えたときに自動的に知らせる仕組み(12-01 で検討した「通知に任せる項目」)この題材アプリでは未実装(12-01参照)
利用者の申告利用者が「おかしい」と気づいて連絡してくることこの記事の例(依頼者役からの申告。08-04 の処理は失敗時に利用者へ「運用担当者へ連絡してください」と表示する)

入口の情報から、症状をたどる。利用者の申告:「提出したのに履歴が残らない」。記録(ログ):履歴の書き込み失敗を確認。通知:題材アプリでは未実装。初動:影響・追加被害・保全を確認する。原因を決めつけず、記録と申告を照合する。

3.2 症状から原因までの順序

初動は、症状→事実確認→仮説→切り分け→原因→暫定対応→恒久対応/残課題、の順に進めます。申告は「症状」であって「事実」ではありません。事実は記録(状態ファイル・履歴ファイル・失敗ログ)を読んで確かめます。仮説は複数並べ、事実と矛盾するものを消し、残ったものを失敗ログの内容で裏付けて原因とします。暫定対応は原因の確定を待たずに始められること(拡大防止・連絡)で、恒久対応は原因を取り除く設計の変更です。この記事では恒久対応の候補を挙げるだけで、決めません(第8.3節)。

3.3 よくある誤解

「申告があったら、まず原因を完全に特定してから動く」。原因の完全な特定には時間がかかる場合があります。まず拡大防止(他の依頼にも同様の問題がないか確認するなど)を行い、原因調査は並行して進めます(第5.2節)。

「申告の言葉どおりに原因を決める」。「状態が変わらない」と「履歴が残っていない」は別の失敗で、原因も対応も違います。この記事の初版は「承認したのに状態が変わらない」という申告を題材にしていましたが、08-03・08-04 で再現できるどの失敗とも一致せず、記録を読まずに書かれた想定でした。本更新で、08-04 で実際に再現できる部分失敗に題材を合わせています(第11節)。

「1件の申告だから様子見でよい」。1件の申告の背後に、同じ原因で影響を受けている他の依頼がある可能性があります。影響範囲を確認してから対応区分を判断します(第8.1節)。

「異常が出たら、まず切り戻す」。切戻し(11-04)は、新版の配置に起因する障害への対応です。配置の版が変わっていないのに切り戻しても、原因は残ります。切戻しの要否は、版の記録を読んで判断します(第6.1節の手順6)。

4. 判断すること

初動で人が判断することは、次の5つです。

判断することなぜ判断が必要か仮置きしてよいか間違えた場合の影響
いつ初動を始めるか(入口)申告・失敗ログ・通知のどれかがあれば始める。申告の内容が曖昧でも、記録を読むことは始められる不可。「原因が分かってから」と待たない拡大防止が遅れ、同じ症状の依頼が増える
何を事実として確かめるか申告は症状。状態ファイル・履歴ファイル・失敗ログの3つを読んで事実にする不可。記録を読まずに原因を書かない申告の言葉どおりに原因を決め、対応を誤る
どの仮説を残すか(切り分け)通信失敗(08-03)、権限・状態の拒否(08-03)、部分失敗(08-04)は、記録の残り方が違う。事実と矛盾する仮説を消す不可。残った仮説は失敗ログの種別で裏付ける原因を取り違え、恒久対応の方向を誤る
暫定対応で何をし、何をしないか(止める条件、切戻しの要否)拡大防止と連絡は始める。データの書き換え(履歴を補う・状態を戻す)は運用管理者の判断。切戻しは版が変わっている場合だけ可(この記事では「同じ症状が他に0件なら影響は1件に限る」「版が変わっていなければ切り戻さない」と仮置き)自動で状態を戻して利用者の操作を消す。原因と無関係な切戻しで混乱を広げる
誰が判断し、誰に連絡するか初動の実施は運用担当(架空)。データの扱いと利用停止の判断は運用管理者・総務課長(架空)。連絡先は依頼者本人と総務課長可(架空の体制で仮置き)判断者が決まらず、依頼者への連絡が遅れる

勝手に決めてはいけないこと:実際に発生した障害・実際の利用者からの申告であるかのように書きません。この記事の障害は 08-04 の正本で再現した説明用のもので、申告は想定例です。記録を読まずに「原因は〇〇である」と断定しません。演習コードで状態や履歴を自動的に書き換えたり戻したりしません(戻すかどうかは人が決めます)。09-04・10-04 から引き継いだ残課題(履歴の書き込み失敗時に状態を戻すか)を、この記事で「解決した」ことにしません(第8.3節)。

AIに任せる範囲:記録を読んで事実を並べること、仮説と事実の照合、影響範囲の集計、初動手順の下書き、実行して結果をそのまま返すことはAIに任せられます。任せてはいけないのは、対応区分(様子見/即時対応/利用停止)の判断、データを書き換えるか戻すかの判断、切戻しの判断、関係者への連絡の実施です。

5. 作って確かめる:記録を読んで初動手順をたどる

5.1 申告の内容(想定例)と、その前提

08-04 の処理(submitRequest)は、状態を「提出済み」に保存したあとで履歴の保存に失敗すると、失敗ログを残し、利用者へ「履歴の記録に失敗しました。状態は変更されていますが履歴が残っていません。運用担当者へ連絡してください。」と返します。この記事では、依頼者役(佐藤)からの申告を次のように想定します。

「REQ-0003 を提出したら『履歴の記録に失敗しました…運用担当者へ連絡してください』と表示された。一覧では提出済みになっている」

この障害は、08-04 と同じ方法(履歴データに循環参照を渡して、履歴の書き込みだけを失敗させる)でローカルに再現します。実際に発生した障害ではありません。

5.2 確認する記録、切り分け、影響範囲、暫定対応

段階内容
事実確認状態ファイル(practice-state.json)で REQ-0003 の状態、履歴ファイル(practice-history.json)で REQ-0003 の履歴の件数、失敗ログ(practice-fail-log.json)の件数と種別(errorType)・発生時刻を読む
影響範囲状態が「提出済み」なのに「提出」の履歴が無い依頼が、REQ-0003 以外にあるか。失敗ログの件数
仮説と切り分けA. 通信が失敗して処理側に届かなかった(08-03の ECONNREFUSED 型)→ この仮説なら状態は変わらない。B. 権限や状態の確認で拒否された(08-03 の 403/409 型)→ 状態は変わらず失敗ログも無い。C. 状態は保存されたが履歴の書き込みだけ失敗した(08-04 の部分失敗型)→ 状態は変わり、履歴は無く、失敗ログがある
原因残った仮説を、失敗ログの errorType と note で裏付ける
暫定対応拡大防止(同じ症状の依頼の有無、失敗ログの増加の監視)、対象依頼の扱いは運用管理者が決める、関係者連絡(依頼者本人、総務課長)、切戻しの要否(配置の版が変わっているか)
恒久対応/残課題候補を挙げ、この記事で決めない範囲を明記する(第8.3節)

5.3 演習コード

演習コードは examples/12-02-incident-response/investigate.js を正本とします。再現には 08-04 の正本(examples/08-04-error-handling/storage_v2.js)をそのまま使い、記録は 08-04 のフォルダの practice-*.json に作られます。このコードは記録を読むだけで、状態・履歴を書き換えたり戻したりしません。

// 教材演習用:08-04 で再現できる部分失敗(状態は「提出済み」に変わったが、履歴の書き込みに失敗)を題材に、
// 申告 → 事実確認 → 影響範囲 → 仮説と切り分け → 原因 → 暫定対応 → 恒久対応/残課題 の初動を、実際のファイルを読んで行う。
// 再現には 08-04 の正本(../08-04-error-handling/storage_v2.js)をそのまま使う。実際に発生した障害ではない。
// このスクリプトはファイルを読むだけで、状態・履歴を書き換えたり戻したりしない(戻すかどうかは人が決める)。
const fs = require("node:fs");
const path = require("node:path");
const { submitRequest, STATE_FILE, HISTORY_FILE, FAIL_LOG_FILE, loadJson } = require("../08-04-error-handling/storage_v2.js");
const VERSION_FILE = path.join(__dirname, "..", "11-02-deploy-record", "deploy_target", "VERSION");

// 手順0:08-04 と同じ方法で部分失敗を再現する(説明用。履歴データに循環参照を渡して履歴の書き込みだけを失敗させる)
[STATE_FILE, HISTORY_FILE, FAIL_LOG_FILE].forEach((f) => { if (fs.existsSync(f)) fs.unlinkSync(f); });
const circular = { note: "説明用" }; circular.self = circular;
const result = submitRequest("REQ-0003", "佐藤", circular);
console.log("手順0:08-04 の部分失敗を再現した(説明用)。処理の戻り値:", JSON.stringify(result));
console.log("");

// 手順1:申告(想定例)
console.log("手順1:申告(想定例)");
console.log("  依頼者役(佐藤):「REQ-0003 を提出したら『履歴の記録に失敗しました…運用担当者へ連絡してください』と表示された。一覧では提出済みになっている」");
console.log("");

// 手順2:事実確認(申告を信じず、記録を読む)
const state = loadJson(STATE_FILE, {});
const history = loadJson(HISTORY_FILE, []);
const failLog = loadJson(FAIL_LOG_FILE, []);
console.log("手順2:事実確認(記録を読む)");
console.log(`  状態ファイル: REQ-0003 の状態 = ${state["REQ-0003"] ?? "(無い)"}`);
console.log(`  履歴ファイル: REQ-0003 の履歴 = ${history.filter((h) => h.requestId === "REQ-0003").length} 件`);
console.log(`  失敗ログ: ${failLog.length} 件${failLog.length ? `(requestId=${failLog[0].requestId}, errorType=${failLog[0].errorType}, at=${failLog[0].at})` : ""}`);
console.log("");

// 手順3:影響範囲(同じ症状の依頼が他にないか:状態が変わっているのに、その操作の履歴が無い依頼)
const inconsistent = Object.entries(state).filter(([id, st]) => st === "提出済み" && !history.some((h) => h.requestId === id && h.action === "提出")).map(([id]) => id);
console.log("手順3:影響範囲");
console.log(`  状態が「提出済み」なのに「提出」の履歴が無い依頼: ${inconsistent.length} 件(${inconsistent.join(", ") || "なし"})`);
console.log(`  失敗ログの件数: ${failLog.length} 件`);
console.log("");

// 手順4:仮説と切り分け(事実と矛盾する仮説を消す)
console.log("手順4:仮説と切り分け");
const hypotheses = [
  { h: "A. 通信が失敗して処理側に届かなかった(08-03 の ECONNREFUSED 型)", expect: "状態は変わらない", fact: state["REQ-0003"] === "提出済み" ? "状態は変わっている" : "状態は変わっていない", ok: state["REQ-0003"] !== "提出済み" },
  { h: "B. 権限や状態の確認で拒否された(08-03 の 403/409 型)", expect: "状態は変わらず、失敗ログも無い", fact: `状態は${state["REQ-0003"] === "提出済み" ? "変わっている" : "変わっていない"}、失敗ログ ${failLog.length} 件`, ok: state["REQ-0003"] !== "提出済み" && failLog.length === 0 },
  { h: "C. 状態は保存されたが、履歴の書き込みだけ失敗した(08-04 の部分失敗型)", expect: "状態は変わり、履歴は無く、失敗ログがある", fact: `状態=${state["REQ-0003"]}、履歴 ${history.filter((x) => x.requestId === "REQ-0003").length} 件、失敗ログ ${failLog.length} 件`, ok: state["REQ-0003"] === "提出済み" && failLog.length > 0 },
];
for (const x of hypotheses) console.log(`  ${x.h}\n    この仮説なら: ${x.expect} → 事実: ${x.fact} → ${x.ok ? "残る" : "消える"}`);
const cause = hypotheses.filter((x) => x.ok);
console.log("");

// 手順5:原因(切り分けで残ったもの。失敗ログの種別で裏付ける)
console.log("手順5:原因");
console.log(`  残った仮説: ${cause.map((x) => x.h.slice(0, 1)).join(", ") || "なし"}。失敗ログの errorType=${failLog[0]?.errorType}、note=「${failLog[0]?.note}」と一致`);
console.log("  → 履歴の書き込み失敗(08-04 の部分失敗)。状態と履歴が別々に書かれる作り(08-02・08-04)に起因する");
console.log("");

// 手順6:暫定対応(拡大防止・連絡。データは自動で書き換えない)
const version = fs.existsSync(VERSION_FILE) ? fs.readFileSync(VERSION_FILE, "utf8").trim() : "(11-02 の配置なし)";
console.log("手順6:暫定対応(初動)");
console.log(`  拡大防止: 同じ症状の依頼が他に ${inconsistent.length - 1} 件。0 件なら影響は REQ-0003 に限られる。運用担当は失敗ログの増加を監視する`);
console.log(`  対象依頼: REQ-0003 は「提出済み」だが「提出」の履歴が無い。履歴を補うか、状態を戻すかは運用管理者が決める(このスクリプトは書き換えない)`);
console.log("  関係者連絡: 依頼者(佐藤)へ「提出は記録されているが履歴が欠けており確認中」と伝える。総務課長(架空)へ報告");
console.log(`  切戻し(11-04)の要否: 配置の版は ${version} のまま変わっておらず、新版の配置に起因する障害ではない → コードの切戻しは行わない`);
console.log("");

// 手順7:恒久対応/残課題
console.log("手順7:恒久対応と残課題");
console.log("  恒久対応の候補: 状態変更と履歴追加を「全部成功か全部取り消し」にする(記事B のトランザクション)。この題材アプリ(JSON ファイル保存)への適用は未決");
console.log("  この記事で回収する範囲: 初動(事実確認・影響範囲・切り分け・暫定対応)まで");
console.log("  残課題: 状態を戻すか履歴を補うかの設計判断(09-04 の残課題2、10-04 の未解決問題)は、この記事でも決めていない");

5.4 演習の設計

項目内容
何のための操作か申告を受けてから、記録を読んで事実を確かめ、仮説を切り分けて原因に至り、暫定対応と恒久対応/残課題を分ける一連の初動を、実際の記録で行う
実行前に見るもの今いる場所が examples/12-02-incident-response/ か。../08-04-error-handling/storage_v2.js があるか。08-04 のフォルダにある practice-*.json は実行時に消して作り直される(演習用のファイルで、他の記事の正本ではない)。11-02の配置があれば版を読んで切戻しの要否に含める(無くても動く)
コマンドnode investigate.js
期待結果手順2で状態=提出済み・履歴0件・失敗ログ1件(TypeError)。手順3で不整合1件(REQ-0003)。手順4で仮説A・Bが消え、Cが残る。手順6で「切戻しは行わない」。終了コード0
結果の読み方手順4の「この仮説なら」と「事実」が矛盾するものが消えているか。手順5の errorType と note が残った仮説と合っているか。手順6の「同じ症状の依頼が他に N 件」が0件か
失敗したときstorage_v2.js が無い(Cannot find module)→ 08-04 の正本を確認する。手順2で失敗ログが0件→ 08-04 の再現方法が変わっていないか確認する。手順4で複数の仮説が残る→ 事実の読み方(どのファイルの何を見たか)を見直す
元に戻せるかこのコードは 08-04 のフォルダの practice-*.json を消して作り直すだけで、11-02 の配置サンドボックスも他の正本も書き換えない。演習後に practice-*.json を消せば元どおり
業務運用では誰が実施/判断するか事実確認・影響範囲の集計・連絡:運用担当(架空)。データの扱い(履歴を補う・状態を戻す)と利用停止:運用管理者・総務課長(架空)。切戻し:運用管理者(11-04)。この演習ではすべて Claude Code

6. 実行結果(初動の演習と、異常時の初動手順)

6.1 演習の実行結果

examples/12-02-incident-response/ で実行した stdout です(整形・省略なし。stderr への出力はありませんでした。手順2の失敗ログの発生時刻 at= は実行するたびに変わります)。

$ node investigate.js
手順0:08-04 の部分失敗を再現した(説明用)。処理の戻り値: {"success":false,"state":"提出済み","partial":true,"error":"履歴の記録に失敗しました。状態は変更されていますが履歴が残っていません。運用担当者へ連絡してください。"}

手順1:申告(想定例)
  依頼者役(佐藤):「REQ-0003 を提出したら『履歴の記録に失敗しました…運用担当者へ連絡してください』と表示された。一覧では提出済みになっている」

手順2:事実確認(記録を読む)
  状態ファイル: REQ-0003 の状態 = 提出済み
  履歴ファイル: REQ-0003 の履歴 = 0 件
  失敗ログ: 1 件(requestId=REQ-0003, errorType=TypeError, at=2026-09-20T15:20:31.775Z)

手順3:影響範囲
  状態が「提出済み」なのに「提出」の履歴が無い依頼: 1 件(REQ-0003)
  失敗ログの件数: 1 件

手順4:仮説と切り分け
  A. 通信が失敗して処理側に届かなかった(08-03 の ECONNREFUSED 型)
    この仮説なら: 状態は変わらない → 事実: 状態は変わっている → 消える
  B. 権限や状態の確認で拒否された(08-03 の 403/409 型)
    この仮説なら: 状態は変わらず、失敗ログも無い → 事実: 状態は変わっている、失敗ログ 1 件 → 消える
  C. 状態は保存されたが、履歴の書き込みだけ失敗した(08-04 の部分失敗型)
    この仮説なら: 状態は変わり、履歴は無く、失敗ログがある → 事実: 状態=提出済み、履歴 0 件、失敗ログ 1 件 → 残る

手順5:原因
  残った仮説: C。失敗ログの errorType=TypeError、note=「状態は提出済みに変更されたが、履歴の記録に失敗した」と一致
  → 履歴の書き込み失敗(08-04 の部分失敗)。状態と履歴が別々に書かれる作り(08-02・08-04)に起因する

手順6:暫定対応(初動)
  拡大防止: 同じ症状の依頼が他に 0 件。0 件なら影響は REQ-0003 に限られる。運用担当は失敗ログの増加を監視する
  対象依頼: REQ-0003 は「提出済み」だが「提出」の履歴が無い。履歴を補うか、状態を戻すかは運用管理者が決める(このスクリプトは書き換えない)
  関係者連絡: 依頼者(佐藤)へ「提出は記録されているが履歴が欠けており確認中」と伝える。総務課長(架空)へ報告
  切戻し(11-04)の要否: 配置の版は v0.1.0-sandbox のまま変わっておらず、新版の配置に起因する障害ではない → コードの切戻しは行わない

手順7:恒久対応と残課題
  恒久対応の候補: 状態変更と履歴追加を「全部成功か全部取り消し」にする(記事B のトランザクション)。この題材アプリ(JSON ファイル保存)への適用は未決
  この記事で回収する範囲: 初動(事実確認・影響範囲・切り分け・暫定対応)まで
  残課題: 状態を戻すか履歴を補うかの設計判断(09-04 の残課題2、10-04 の未解決問題)は、この記事でも決めていない
終了コード: 0

読み方:手順1の申告に対し、手順2で3つの記録から事実を確かめると「状態は提出済み・履歴0件・失敗ログ1件(TypeError)」です。手順4で、通信失敗(A)と拒否(B)は「状態は変わっている」という事実と矛盾して消え、部分失敗(C)だけが残り、手順5で失敗ログの note と一致します。手順6の暫定対応では、同じ症状の依頼が他に0件で影響は REQ-0003 に限られ、配置の版は v0.1.0-sandbox のまま変わっていないので切戻しは行いません。手順7で、恒久対応の候補(トランザクション)とこの記事で決めない範囲を分けています。

6.2 異常時の初動手順

入口症状(申告)確認する記録と事実仮説と切り分け原因影響範囲の判定対応区分暫定対応恒久対応/残課題初動の担当連絡先
利用者の申告(依頼者役・佐藤)+失敗ログ提出時に「履歴の記録に失敗しました」と表示。一覧では提出済み状態ファイル:提出済み/履歴ファイル:0件/失敗ログ:1件(TypeError)A 通信失敗→消える、B 拒否→消える、C 部分失敗→残る履歴の書き込み失敗(08-04 の部分失敗。状態と履歴が別々に書かれる作りに起因)同じ症状の依頼が他に0件、失敗ログ1件→REQ-0003 に限る即時対応(第8.1節)失敗ログの増加を監視、REQ-0003 の扱い(履歴を補う/状態を戻す)は運用管理者が決める、依頼者へ連絡、総務課長へ報告、版が変わっていないため切戻しは行わない候補:状態変更と履歴追加を全部成功か全部取り消しにする(記事B)。この題材アプリへの適用は未決運用担当(架空)総務課長(架空)、依頼者本人

7. 確認結果

実行環境:macOS 26.6.2、Node.js v24.18.0(node:fs・node:path のみ使用)、2026-09-21に実行。実行場所は examples/12-02-incident-response/。読み書きしたのは examples/08-04-error-handling/practice-*.json(演習用に作り直す)と、examples/11-02-deploy-record/deploy_target/VERSION(読むだけ)で、外部のサーバー・サービスには接続していません。stdout・stderr・終了コードは evidence_public/phase5b2c1-2026-09-21/12-02/run_log.md に整形なしで記録しています。

完了条件との照合:

完了条件期待実測判定
ログ・通知・申告の3入口がある第3.1節に記載、うち記録と申告は演習で使う記載あり。失敗ログ1件と申告(想定例)を使った一致
症状が、再現できる失敗と一致している08-04 の部分失敗(状態は変わり、履歴の保存に失敗)手順0の戻り値 partial: true、手順2で状態=提出済み・履歴0件・失敗ログ1件一致
事実と矛盾する仮説が消え、原因が失敗ログで裏付けられるA・B が消え C が残る。errorType=TypeError手順4・手順5のとおり一致
影響範囲の判定基準がある同じ症状の依頼の件数と失敗ログの件数不整合1件(REQ-0003)、失敗ログ1件一致
対応区分と判断者が書かれている第6.2節・第8.1節記載あり一致
切戻しの要否が版の記録から判断されている版が変わっていなければ切り戻さないv0.1.0-sandbox のまま→切戻しは行わない一致
演習コードが記録を書き換えていない状態・履歴の書き換え・削除なし読むだけ(loadJson)。手順0の再現で practice-*.json を作り直すのみ一致

この記事で確かめたこと:08-04 で再現できる部分失敗について、記録を読んで事実を確かめ、仮説を切り分け、原因に至り、暫定対応と恒久対応/残課題を分ける初動が、実際の記録で成立すること。切戻しの要否を版の記録から判断できること。

この記事で確かめていないこと:

範囲理由どこで確かめるか
実際の利用者からの申告と、その対応申告は想定例。利用者も画面も無い実際の限定試行(10-04の条件が満たされてから)
通知(入口の2つ目)この題材アプリでは未実装12-01の判断に従い、実装後に
REQ-0003 の扱い(履歴を補う/状態を戻す)演習コードは書き換えない。運用管理者と業務担当者の判断実際の運用で、運用管理者が決める
恒久対応(トランザクション)の題材アプリへの適用設計判断で、この記事の範囲外記事Bの設計を前提に、実装へ戻して判断する
実際の運用担当・総務課長への連絡架空の体制実際の運用開始時

残る制限:この記事の本文と演習コードはClaude Codeが作成したもので、業務担当者による内容確認は行っていません。申告者役・運用担当役・判断者役はすべて Claude Code で、独立した確認ではありません。

8. 設計を判断する

8.1 対応区分(様子見/即時対応/利用停止)を判断する

対応区分目安この記事での判断
様子見影響が1件のみで、業務への支障が小さい場合該当しない(提出の履歴が無いと、後の承認・監査で「誰がいつ提出したか」を追えないため)
即時対応(この記事で採用)業務に影響するが、他の利用者・依頼への影響は限定的と考えられる場合手順3で同じ症状の依頼が他に0件と確認でき、影響は REQ-0003 に限られるため、即時対応とする
利用停止原因が特定できず、影響が広がる可能性が高い場合該当しない(原因が失敗ログで裏付けられ、影響範囲も限定的)。ただし失敗ログが増え続ける場合は、総務課長(架空)に相談して利用停止を検討する

判断者は運用担当(架空)とし、影響が広範囲に及ぶ可能性が見つかった場合は、総務課長(架空)に相談して利用停止を検討します。

8.2 切戻しの要否

切戻し(11-04)は、新版の配置に起因する障害に対する暫定対応です。この記事の障害では、配置の版は v0.1.0-sandbox のまま変わっておらず、原因は現在の版の作り(状態と履歴が別々に書かれる)にあるため、切り戻しても原因は残ります。切戻しの要否は「版が変わっているか」を記録で確かめてから判断します。版が変わっていて、変更後に症状が出始めた場合は、11-04 の手順で切り戻し、切戻し後に同じ確認(手順2〜3)をやり直します。

8.3 引き継いだ残課題を、この記事でどこまで回収するか

09-04の残課題2(履歴の書き込み失敗時に状態を戻さない設計)は、10-04で「演習の範囲では受容。限定試行へ進む前に扱いを決める(12-02)」とされ、09-04 の更新時点では「12-02 の本文はこの残課題を扱っておらず、未回収」と記録されていました。この記事で回収するのは次の範囲です。

項目この記事での扱い
この失敗が起きたとき、どう見え、何を確認し、何を暫定対応にするか(初動)回収した(第6節)
影響範囲の判定と、切戻しの要否回収した(第6.1節の手順3・手順6)
REQ-0003 のような不整合データを、履歴を補って直すか、状態を戻すか未決。運用管理者と業務担当者の判断であり、この記事では決めない
状態変更と履歴追加を「全部成功か全部取り消し」にする設計の、題材アプリへの適用未決。候補として挙げるにとどめる(記事B)

つまり、10-04 の「限定試行へ進む前に扱いを決める」は、この記事の時点でも「初動の手順は決まったが、データの扱いと設計の適用は未決」です。限定試行へ進む前に、残り2件を決める必要があります。

8.4 適用限界

この記事の初動手順は、08-04 で再現できる1種類の部分失敗に基づくものです。通信失敗(08-03)や権限の拒否は、記録の残り方が違うため、仮説A・Bとして「消える」側で扱っただけで、それらが実際に起きたときの初動は演習していません。実際の申告があった場合、この記事の手順をひな形として使いつつ、実際に確認できる記録の内容に応じて手順を調整する必要があります。

9. 持ち帰る成果物

成果物空欄版記入例
異常時の初動手順ひな形(入口、症状、確認する記録と事実、仮説と切り分け、原因、影響範囲の判定、対応区分、暫定対応、恒久対応/残課題、初動の担当、連絡先)templates/12-02-incident-response_template.mdtemplates/12-02-incident-response_example.md
記録を読んで切り分ける演習コードexamples/12-02-incident-response/investigate.js同上
実行記録(stdout・stderr・終了コード、整形なし)—evidence_public/phase5b2c1-2026-09-21/12-02/run_log.md

自分の業務に使うときの手順は次のとおりです。

  1. 記録・通知・申告の3入口から、異常に気づく仕組みを整理する
  2. 申告があった場合に読む記録(状態・履歴・失敗ログに相当するもの)を決める
  3. 考えられる失敗の種類ごとに「この仮説なら記録はこう残る」を書き、事実と照らして消す
  4. 影響範囲の判定基準を決め、拡大防止・関係者連絡・切戻しの要否の初動を書く
  5. 対応区分(様子見/即時対応/利用停止)の目安と、データを書き換える判断者を決める
  6. 恒久対応の候補と、この段階で決めないことを分けて残す

10. 次工程への受渡し

次へ渡すもの:異常時の初動手順、演習の実行記録、未決の2件(不整合データの扱い、トランザクション設計の適用)。

次工程での使われ方:12-03(記事C)では、この初動手順を障害対応の入口として使い、状態の保全からコードの切戻し・データの復元へつなげます。12-04では、データを戻す側の演習を行います。未決の2件は、10-04の「限定試行へ進む前に扱いを決める」に戻します。

前工程へ戻る条件:運用項目自体に見直しが必要な場合は、12-01に戻って確認します。恒久対応として設計を変える場合は、08-04(と記事B)へ戻ります。

11. 根拠と更新情報

  • この記事の会社・人物・データはすべて架空の設定です。
  • 部分失敗の再現と失敗ログは08-04、通信失敗の種類は08-03、問い合わせ手順は10-03、切戻しは11-04、残課題の出所は09-04・10-04に基づきます。
  • 制作の来歴:本文はClaude Codeが作成しました。第5.3節・第6節の演習コードは examples/12-02-incident-response/investigate.js を正本とし、08-04 の正本 examples/08-04-error-handling/storage_v2.js を使って、2026-09-21にmacOS 26.6.2・Node.js v24.18.0の環境で実際に実行し、stdout・stderr・終了コードを evidence_public/phase5b2c1-2026-09-21/12-02/run_log.md に記録しています。
  • 2026-09-21(Phase 5B-2C1):初版の申告「承認したのに状態が提出済みのまま変わらない」は、08-03(通信失敗・拒否では状態が変わらない)とも 08-04(状態は変わるが履歴が残らない)とも一致せず、記録を読まずに書かれた想定例だった。本更新で題材を 08-04 で再現できる部分失敗に合わせ、実際の記録を読む演習コードを追加し、症状→事実確認→仮説→切り分け→原因→暫定対応→恒久対応/残課題の順に書き直した。09-04・10-04 から引き継いだ残課題について、この記事で回収する範囲(初動まで)と未決の範囲(データの扱い、設計の適用)を第8.3節に明記した。
  • 2026-09-21(Final Content Audit):題名が初版の申告「承認したのに状態が変わらない」のままで、Phase 5B-2C1 以降の本文の題材(提出時の履歴記録の失敗)と食い違っていたため、題名を「提出したのに履歴が残らない」申告に改めた(ひな形・README・記事登録情報・CONTENT_MAP の到達目標も同じ文言に)。本文・コード・実行結果は不変。
  • 未確認事項:実際の利用者からの申告と対応、通知の入口、不整合データの扱いの決定、恒久対応の適用、実際の関係者への連絡は、この記事の時点では行っていません。