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

バックアップを別の場所へ復元し、基準時点との3照合と戻らない変更を確かめる

この記事で身につくこと隔離した環境で復元し、件数・内容・関係・利用可否を確認する理由と、バックアップ以降の変更が復元されない可能性を説明できる。

記事内目次(24項目)
この記事の管理情報(該当工程・関連要件・成果物の閲覧と保存・実行記録)
記事ID
12-04
該当工程
12-04 バックアップから復元を確かめる(関連:12-03、05-04、06-02、13-04)
関連要件
REQ-008
到達目標
隔離した環境で復元し、件数・内容・関係・利用可否を確認する理由と、バックアップ以降の変更が復元されない可能性を説明できる
主要な成果物
確認環境と検証状況
演習コードは examples/12-04-restore-drill/ を正本とし、Claude Codeが2026-09-21にローカルで実行して stdout・stderr・終了コードを整形なしで記録済み。記事のコードは正本の全文、実行結果は実測そのもの。Phase 5B-2C1で、初版の整形した JSON と、実際には出ていなかった拒否の出力を、実測に置き換えた。人による実読・内容確認は未実施。
未検証の範囲
実際のバックアップの規模・保存先、実際のデータベースでの復元、戻らない変更の扱いの決定、利用再開の判断は、この記事の時点では確認していない。
実行記録

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

原稿の管理表(13項目:記事ID・カテゴリ・要件ID・先に読むと理解しやすい記事・成果物パス・対象ツール・検証状況・最終更新日など)
管理項目内容
記事ID12-04
主な中カテゴリ12-04 バックアップから復元を確かめる
関連中カテゴリ12-03、05-04、06-02、13-04
関連要件IDREQ-008
先に読むと理解しやすい記事12-03(記事C、障害から復旧し再発を防ぐ)を読んでいると理解しやすい。未読でも本文で必要な内容は説明する
到達目標隔離した環境で復元し、件数・内容・関係・利用可否を確認する理由と、バックアップ以降の変更が復元されない可能性を説明できる
3層の配置理解する=第3〜4節/作って確かめる=第5〜7節/設計を判断する=第8節
成果物パスtemplates/12-04-restore-drill_template.md、templates/12-04-restore-drill_example.md、examples/12-04-restore-drill/(drill.js、run.js、run_reject_check.js)、evidence_public/phase5b2c1-2026-09-21/12-04/run_log.md
出典第11節参照
対象ツール・バージョン教材演習用にNode.js v24.18.0(node:fs、node:pathのみ使用)
検証状況演習コードは examples/12-04-restore-drill/ を正本とし、Claude Codeが2026-09-21にローカルで run.js(復元と3照合)と run_reject_check.js(復元先が既にあるときの拒否)を実際に実行して、stdout・stderr・終了コードを整形なしで記録済み(第6〜7節、evidence_public/phase5b2c1-2026-09-21/12-04/run_log.md)。実際のバックアップ・実際のデータベースでの復元は未実施
残課題第11節参照
最終更新日2026-09-20(新規作成)。2026-09-21(Phase 5B-2C1:初版の第6節は、実行結果の JSON を1行にまとめて整形した形で載せ、拒否の確認も実際には例外の stack が出る node -e の結果を「拒否されました:」という出力があったかのように書き換えていた。本更新で、記事のコードを正本の全文(3照合のコードを含む)に、実行結果を再実行の実測そのまま(整形なし)に置き換え、拒否の確認は例外を受け止めて表示する run_reject_check.js を正本に加えて実測した。読む順路・第4節の判断項目・第5.5節「演習の設計」・第7節の確かめていないこと・CHECKLIST を追加)

この記事の会社・人物・データはすべて架空の設定です。実在する会社や案件とは関係ありません。この記事の演習は、記事C(SAMPLE-C)の復元演習と同じ考え方を、Node.js標準機能だけで小さく再現したものです。本文のコードは正本の全文で、第6節の実行結果は2026-09-21に実際にローカルで実行した出力をそのまま載せています(第7節)。演習領域(work/)の外には読み書きしません。

この記事は何の話か。架空の依頼・履歴データのバックアップ(基準時点)を、元の場所とは別の場所へ復元し、件数・内容・関係の3照合を行い、基準時点より後に加わった変更(新しい依頼、承認)が復元後には戻らないことを、実際に動かして確かめる話です。

なぜ必要か。バックアップを取っていても、実際に復元できるかどうか、復元した結果が期待どおりかどうかは、試してみなければ分かりません。また、「バックアップから復元すれば元どおりになる」という誤解を避ける必要があります。

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

  • 隔離した環境で復元し、件数・内容・関係・利用可否を確認する理由を説明できる
  • バックアップを別の場所へ復元し、基準時点との3照合、戻らない変更を復元演習記録に書ける
  • バックアップの頻度と保存先を、許容する損失の範囲と費用から判断できる
  • 記事に載っている実行結果が、正本のコードを実際に動かした出力そのものであるかを、証拠(実行記録)と照らして確かめられる

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

  • 基本だけ理解する:第1節→第3節(別の場所へ復元する理由、「基準時点どおり、元どおりではない」)→第4節(判断すること)→第5.1節(演習の流れ)→第6.3節の復元演習記録の表→第9節。コードを読まなくても、何を照合し、何が戻らないかが分かります。
  • 作って確かめる:上に加えて第5.2〜5.4節(演習コードの全文)→第5.5節(演習の設計:実行前に見るもの・失敗したとき・戻せるか・誰が)→第6.1〜6.2節の実行結果→第7節(確かめたこと・確かめていないこと)。
  • 設計判断を深める:上に加えて第8節(復元できたことと利用可否の判断、バックアップの頻度と保存先)。

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

この記事でやることは、架空の依頼・履歴データについて、ある時点(基準時点)でバックアップを取り、その後に業務が続いた状態(新しい依頼、既存の依頼の承認)を作ってから、バックアップを元の場所とは別の場所へ復元し、件数・内容・関係の3照合と、戻らない変更を確かめることです。

12-03(記事C)では実際の障害を想定した復元演習を行いましたが、この記事では、このFast Trackで使ってきたデータ形式(JSON)を使い、同じ考え方を小さく再現します。

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

  • 復元演習コード(examples/12-04-restore-drill/)
  • 復元演習記録(バックアップの基準時点、復元先、手順、件数照合、内容照合、関係の照合、利用可否、戻らない変更、実施者、日時)

2. 前提知識と読む順路

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

基準時点

一言でいうと、バックアップを取った時刻です。復元すると、この時点の内容に戻ります。

基準時点どおり、元どおりではない

一言でいうと、復元は「バックアップを取った時点の内容」に戻すことであり、「今の状態」に戻すことではない、という考え方です(12-03・記事Cで扱った考え方と同じです)。

3照合

一言でいうと、復元したデータをバックアップと突き合わせる3つの確認です。件数(依頼と履歴の数が同じか)、内容(各依頼の依頼者・件名が同じか)、関係(履歴が指す依頼が復元先に存在するか)。

これがないと、「バックアップがあるから大丈夫」と思っていても、実際に復元したときに、基準時点より後の変更が戻らないことに気づかず、業務に混乱が生じます。

読む順路:障害対応・復元演習の全体像は12-03(記事C)、復旧方針は05-04、環境の区別は06-02、コードの切戻し(データの復元とは別の作業)は11-04が該当します。この記事の復元演習記録は、13-04(引継ぎ・移行・廃止を行う)、05-04の方針見直しで使います。

3. 理解する:隔離した環境で復元し、3照合する理由

3.1 別の場所へ復元する理由

12-03(記事C)で確認したとおり、復元は元の場所を上書きせず、別の場所(この記事ではwork/restore/)へ行います。元のデータ(バックアップ、稼働中のデータ)を壊さずに、復元結果だけを確認できるようにするためです。復元先が既にある場合も上書きせず、拒否します(第6.2節で実際に確かめます)。

元を保ち、別の場所で確かめる。元データ・バックアップを保全:既存のものを上書きしない。別の場所へ復元:復元先が既にあれば拒否。基準時点と3照合:件数・内容・関係を照合する。戻らない変更を確認:基準時点より後の変更を別に扱う。起動できたことだけでは、復旧完了にしない。

3.2 よくある誤解

「バックアップから復元すれば元どおりになる」。12-03(記事C)で確認したとおり、復元は「基準時点どおり」であり、「元どおり」ではありません。基準時点より後に加わった変更(新しい依頼、承認など)は、復元しても戻りません(第6節で実際に確認します)。

「復元できれば、それで完了」。復元したデータが基準時点と一致するか(件数・内容・関係)を確認し、戻らない変更を明らかにしてから、利用を再開するかどうかを判断します(第8節)。

「記事に実行結果が載っていれば、動いた証拠になる」。載っている結果が、載っているコードを実際に動かした出力そのものでなければ、証拠になりません。この記事の初版は、実行結果の JSON を読みやすく1行にまとめ、拒否の確認も実際には出ていない形の出力を書いていました(第11節)。本更新では、正本のコードの全文と、実行した出力そのまま(整形なし)を載せ、実行記録(evidence)と一致させています。

4. 判断すること

復元演習で人が判断することは、次の5つです。

判断することなぜ判断が必要か仮置きしてよいか間違えた場合の影響
いつ演習してよいか復元先が稼働中のデータと隔離されていること(この記事では work/restore/)が前提。隔離されていなければ演習しない不可。復元先が既にある場合は拒否する(演習コードは例外で止まる)稼働中のデータやバックアップを上書きする
何を照合し、何を「一致」とするか件数・内容・関係の3つ。内容は依頼者・件名で比べる(状態は基準時点より後に変わりうるので、戻らない変更として別に扱う)可(比べる項目は業務に合わせて増やす)状態の違いを「不一致」と誤読して復元失敗と判断する、または戻らない変更を見落とす
戻らない変更をどう扱うか基準時点より後の新しい依頼(REQ-D04)と状態変更(REQ-D01)は、復元では戻らない。作り直すか諦めるかは関係者と決める不可。演習コードは一覧を作るだけで、扱いを決めない利用者の操作が黙って消える
何を証拠として残すかコード(正本)、コマンド、stdout・stderr・終了コードをそのまま。整形した結果を「実行結果」として載せない不可記事の結果と実際の動作が食い違い、証拠にならない(初版の問題)
誰が実施し、誰が利用再開を判断するか実施は運用担当(架空)。利用再開の判断は運用管理者と業務担当者(架空)。復元できたことと利用可否は別(第8.1節)可(架空の体制で仮置き)3照合が一致しただけで利用を再開し、戻らない変更に気づかない

勝手に決めてはいけないこと:実際のバックアップ・実際のデータベースを対象にしたかのように書きません。この記事は架空データによる演習です。復元できたことを、そのまま利用再開の判断として扱いません(第8.1節)。実行結果を整形・省略して「実行結果」として載せません。戻らない変更の扱い(作り直す・諦める)を演習の実施者が決めません。

AIに任せる範囲:演習コードの下書き、実行して結果をそのまま返すこと、3照合の集計、戻らない変更の一覧化はAIに任せられます。任せてはいけないのは、復元先が隔離されているかの最終確認、戻らない変更の扱い、利用再開の判断です。

5. 作って確かめる:復元演習を実行する

5.1 演習の流れ

手順内容関数(drill.js)
1演習用の初期データ(依頼3件、履歴3件)を work/live.json に作るsetupInitialData()
2バックアップを work/backup.json に取る(この時点が基準時点)takeBackup()
3基準時点のあと、業務が続く(REQ-D04 を追加、REQ-D01 を承認)applyAfterBackupChanges()
4バックアップを別の場所 work/restore/restored.json へ復元する。復元先が既にあれば拒否restore()
5件数・内容・関係の3照合と、戻らない変更の一覧を作るreconcile()

演習領域(work/)の外は読み書きしません(assertInsideWork)。

5.2 演習コード(drill.js)

演習コードは examples/12-04-restore-drill/ を正本とします。以下は全文です。

// 教材演習用:バックアップからの復元演習(記事Cの演習と同じ考え方を、Node.js標準機能だけで小さく再現する)。
// 「元どおり」ではなく「基準時点どおり」に戻ることを、架空データで確かめる。
// 演習領域(このフォルダ直下の work/)の外は読み書きしない。
const fs = require("node:fs");
const path = require("node:path");

const WORK_DIR = path.join(__dirname, "work");
const LIVE_FILE = path.join(WORK_DIR, "live.json");
const BACKUP_FILE = path.join(WORK_DIR, "backup.json");
const RESTORE_DIR = path.join(WORK_DIR, "restore");
const RESTORED_FILE = path.join(RESTORE_DIR, "restored.json");

function assertInsideWork(targetPath) {
  const resolved = path.resolve(targetPath);
  if (!resolved.startsWith(WORK_DIR + path.sep) && resolved !== WORK_DIR) {
    throw new Error("演習領域(work/)の外への操作は拒否します: " + targetPath);
  }
}

function readJson(file) {
  assertInsideWork(file);
  return JSON.parse(fs.readFileSync(file, "utf8"));
}
function writeJson(file, data) {
  assertInsideWork(file);
  fs.writeFileSync(file, JSON.stringify(data, null, 2));
}

// 手順1:演習用の初期データ(基準時点の直前)を作る。
function setupInitialData() {
  fs.mkdirSync(WORK_DIR, { recursive: true });
  const initial = {
    requests: [
      { id: "REQ-D01", requester: "佐藤", title: "会議室の予約", state: "提出済み", approver: "鈴木" },
      { id: "REQ-D02", requester: "田中", title: "備品購入申請", state: "承認済み", approver: "鈴木" },
      { id: "REQ-D03", requester: "高橋", title: "交通費精算", state: "提出済み", approver: "佐藤" },
    ],
    history: [
      { requestId: "REQ-D01", action: "作成", actor: "佐藤" },
      { requestId: "REQ-D02", action: "作成", actor: "田中" },
      { requestId: "REQ-D02", action: "承認", actor: "鈴木" },
    ],
  };
  writeJson(LIVE_FILE, initial);
}

// 手順2:バックアップを取る(この時点が「基準時点」)。
function takeBackup() {
  const live = readJson(LIVE_FILE);
  writeJson(BACKUP_FILE, live);
}

// 手順3:基準時点のあと、業務が続く(新しい依頼、既存の依頼の承認)。
function applyAfterBackupChanges() {
  const live = readJson(LIVE_FILE);
  live.requests.push({ id: "REQ-D04", requester: "田中", title: "研修参加申請", state: "提出済み", approver: "鈴木" });
  live.history.push({ requestId: "REQ-D04", action: "作成", actor: "田中" });
  const target = live.requests.find((r) => r.id === "REQ-D01");
  target.state = "承認済み";
  live.history.push({ requestId: "REQ-D01", action: "承認", actor: "鈴木" });
  writeJson(LIVE_FILE, live);
}

// 手順4:バックアップを、元の場所とは別の場所(work/restore/)へ復元する。復元先が既にあれば拒否する。
function restore() {
  if (fs.existsSync(RESTORE_DIR)) {
    throw new Error("復元先が既に存在します。上書きしません: " + RESTORE_DIR);
  }
  fs.mkdirSync(RESTORE_DIR, { recursive: true });
  const backup = readJson(BACKUP_FILE);
  writeJson(RESTORED_FILE, backup);
}

// 手順5:件数・内容・関係の3照合と、戻らない変更の一覧を作る。
function reconcile() {
  const backup = readJson(BACKUP_FILE);
  const restored = readJson(RESTORED_FILE);
  const live = readJson(LIVE_FILE);

  const countCheck = {
    requests: { backup: backup.requests.length, restored: restored.requests.length, ok: backup.requests.length === restored.requests.length },
    history: { backup: backup.history.length, restored: restored.history.length, ok: backup.history.length === restored.history.length },
  };

  const contentCheck = backup.requests.map((r) => {
    const found = restored.requests.find((x) => x.id === r.id);
    return { id: r.id, ok: !!found && found.requester === r.requester && found.title === r.title };
  });

  const relationCheck = restored.history.map((h) => ({
    requestId: h.requestId,
    ok: restored.requests.some((r) => r.id === h.requestId),
  }));

  const restoredIds = new Set(restored.requests.map((r) => r.id));
  const lostNewRequests = live.requests.filter((r) => !restoredIds.has(r.id)).map((r) => r.id);
  const lostStateChanges = live.requests
    .filter((r) => restoredIds.has(r.id))
    .map((r) => ({ id: r.id, liveState: r.state, restoredState: restored.requests.find((x) => x.id === r.id).state }))
    .filter((r) => r.liveState !== r.restoredState);

  return { countCheck, contentCheck, relationCheck, unreturnedChanges: { newRequestsNotRestored: lostNewRequests, stateChangesNotRestored: lostStateChanges } };
}

module.exports = { WORK_DIR, LIVE_FILE, BACKUP_FILE, RESTORE_DIR, RESTORED_FILE, setupInitialData, takeBackup, applyAfterBackupChanges, restore, reconcile };

5.3 実行コード(run.js)

// 教材演習用:復元演習を手順どおりに実行する。
const fs = require("node:fs");
const { WORK_DIR, setupInitialData, takeBackup, applyAfterBackupChanges, restore, reconcile } = require("./drill.js");

if (fs.existsSync(WORK_DIR)) fs.rmSync(WORK_DIR, { recursive: true, force: true }); // 演習領域を初期化

console.log("手順1:初期データを作る");
setupInitialData();

console.log("手順2:バックアップを取る(基準時点)");
takeBackup();

console.log("手順3:基準時点のあと、業務が続く(新しい依頼、既存の依頼の承認)");
applyAfterBackupChanges();

console.log("手順4:バックアップを別の場所(work/restore/)へ復元する");
restore();

console.log("手順5:件数・内容・関係の3照合と、戻らない変更の確認");
const result = reconcile();
console.log(JSON.stringify(result, null, 2));

5.4 復元先が既にあるときの拒否を確かめるコード(run_reject_check.js)

restore() は復元先が既にあると例外を投げて止まります。そのまま呼ぶと Node.js の stack(エラーの発生位置の一覧)が stderr に出て終了コード1になるので、この記事では例外を受け止めて内容を表示するコードで確かめます。

// 教材演習用:復元先(work/restore/)が既に存在するときに restore() が上書きせず拒否することを確かめる。
// 先に node run.js を実行して work/restore/ を作っておく。例外を受け止めて内容を表示する(パスの先頭を <examples> に置き換える以外、整形はしない)。
const fs = require("node:fs");
const path = require("node:path");
const { RESTORE_DIR, restore } = require("./drill.js");

if (!fs.existsSync(RESTORE_DIR)) {
  console.log("復元先がまだ無い(先に node run.js を実行する)");
  process.exit(1);
}
try {
  restore();
  console.log("復元先が既にあるのに上書きされた(想定外)");
  process.exit(2);
} catch (e) {
  console.log(`拒否されました: ${e.message.replace(path.dirname(__dirname), "<examples>")}`);
  process.exit(0);
}

5.5 演習の設計

項目内容
何のための操作かバックアップを隔離した場所へ復元し、基準時点と一致すること(3照合)と、基準時点より後の変更が戻らないことを、実際に動かして確かめる。あわせて、復元先が既にあるときに上書きしないことを確かめる
実行前に見るもの今いる場所が examples/12-04-restore-drill/ か。work/ は実行のたびに消して作り直される(演習用。他の記事の正本や 11-02 の配置サンドボックスは触らない)
コマンドnode run.js のあと node run_reject_check.js
期待結果run.js:3照合がすべて ok: true、newRequestsNotRestored に REQ-D04、stateChangesNotRestored に REQ-D01(承認済み→提出済み)。終了コード0。run_reject_check.js:「拒否されました: 復元先が既に存在します…」で終了コード0
結果の読み方countCheck と contentCheck と relationCheck の ok がすべて true か。unreturnedChanges の中身が第5.1節の手順3で加えた変更と一致するか。拒否の表示があり、work/restore/restored.json が書き換わっていないか
失敗したときok: false がある→ backup.json と restored.json を直接比べる。拒否の確認で終了コード1(「復元先がまだ無い」)→ 先に run.js を実行する。終了コード2(上書きされた)→ restore() の存在確認を見直す。「演習領域(work/)の外への操作は拒否します」→ パスの指定を見直す
元に戻せるか作るのは work/ の中だけ。work/ を消せば元どおり。稼働中のデータに相当する live.json は復元で書き換えない
業務運用では誰が実施/判断するか実施:運用担当(架空)。戻らない変更の扱いと利用再開:運用管理者と業務担当者(架空)。この演習ではすべて Claude Code

6. 実行結果(復元演習記録)

6.1 復元と3照合(node run.js)

examples/12-04-restore-drill/ で実行した stdout です(整形・省略なし。stderr への出力はありませんでした)。

$ node run.js
手順1:初期データを作る
手順2:バックアップを取る(基準時点)
手順3:基準時点のあと、業務が続く(新しい依頼、既存の依頼の承認)
手順4:バックアップを別の場所(work/restore/)へ復元する
手順5:件数・内容・関係の3照合と、戻らない変更の確認
{
  "countCheck": {
    "requests": {
      "backup": 3,
      "restored": 3,
      "ok": true
    },
    "history": {
      "backup": 3,
      "restored": 3,
      "ok": true
    }
  },
  "contentCheck": [
    {
      "id": "REQ-D01",
      "ok": true
    },
    {
      "id": "REQ-D02",
      "ok": true
    },
    {
      "id": "REQ-D03",
      "ok": true
    }
  ],
  "relationCheck": [
    {
      "requestId": "REQ-D01",
      "ok": true
    },
    {
      "requestId": "REQ-D02",
      "ok": true
    },
    {
      "requestId": "REQ-D02",
      "ok": true
    }
  ],
  "unreturnedChanges": {
    "newRequestsNotRestored": [
      "REQ-D04"
    ],
    "stateChangesNotRestored": [
      {
        "id": "REQ-D01",
        "liveState": "承認済み",
        "restoredState": "提出済み"
      }
    ]
  }
}
終了コード: 0

読み方:countCheck は依頼3件・履歴3件でバックアップと復元先が一致、contentCheck は3件とも依頼者・件名が一致、relationCheck は復元先の履歴3件がすべて存在する依頼を指しています。unreturnedChanges は、基準時点より後に加えた REQ-D04(新しい依頼)と REQ-D01 の状態変更(稼働中は承認済み、復元先は提出済み)が戻らないことを示しています。

6.2 復元先が既にあるときの拒否(node run_reject_check.js)

run.js の直後に実行した stdout です(整形・省略なし。stderr への出力はありませんでした。パスの先頭はコードの中で <examples> に置き換えて表示しています)。

$ node run_reject_check.js
拒否されました: 復元先が既に存在します。上書きしません: <examples>/12-04-restore-drill/work/restore
終了コード: 0

参考:例外を受け止めずに node -e "require('./drill.js').restore()" と呼ぶと、stdout には何も出ず、stderr に発生位置(drill.js:67)と throw new Error("復元先が既に存在します。上書きしません: " + RESTORE_DIR); の行から始まる stack が出て、終了コード1になります(実行記録に先頭3行を記録)。初版の記事はこの node -e の結果を「拒否されました: …」という stdout があったかのように載せていました(第11節)。

6.3 復元演習記録

バックアップの基準時点復元先手順件数照合内容照合関係の照合利用可否戻らない変更実施者日時
依頼3件・履歴3件の時点(work/backup.json)work/restore/restored.json(隔離。既にあれば拒否)第5.1節の手順1〜5依頼3件・履歴3件で一致3件とも依頼者・件名が一致復元先の履歴3件すべてが対象の依頼を持つ第8.1節参照(復元できたことと利用可否は別)REQ-D04(新しい依頼)、REQ-D01の状態変更(提出済み→承認済み)が戻らないClaude Code(演習)2026-09-21

7. 確認結果

実行環境:macOS 26.6.2、Node.js v24.18.0(node:fs、node:pathのみ使用)、2026-09-21に実行。実行場所は examples/12-04-restore-drill/。演習領域(work/)の外には読み書きしていません。stdout・stderr・終了コードは evidence_public/phase5b2c1-2026-09-21/12-04/run_log.md に整形なしで記録しています。

完了条件との照合:

完了条件期待実測判定
復元先が本番と隔離されているwork/restore/ のみを使用、既にあれば拒否restore() は work/restore/restored.json に書き、run_reject_check.js で拒否を確認一致
件数・内容・関係の3照合があるすべて ok: true件数2組・内容3件・関係3件、すべて true一致
戻らない変更が具体例で示されているREQ-D04、REQ-D01 の状態変更newRequestsNotRestored: ["REQ-D04"]、stateChangesNotRestored: [REQ-D01 承認済み→提出済み]一致
記事のコードが正本と同一drill.js・run.js・run_reject_check.js の全文第5.2〜5.4節は正本の全文一致
記事の実行結果が実測と同一整形・省略なし第6.1〜6.2節は実行記録の stdout そのまま一致

この記事で確かめたこと:架空データで、別の場所への復元、3照合の一致、戻らない変更の一覧化、復元先が既にあるときの拒否が、正本のコードで実際に成立すること。

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

範囲理由どこで確かめるか
実際のバックアップ(規模・保存先・取得方法)演習は依頼3〜4件の JSON05-04の復旧方針に基づく実際の環境
実際のデータベースでの復元題材アプリは JSON ファイル保存実際の保存先を決めてから
戻らない変更の扱い(作り直す・諦める)関係者の判断で、演習では決めない実際の復旧時に運用管理者と業務担当者が決める
利用再開の判断復元できたことと利用可否は別(第8.1節)実際の復旧時
11-02 の配置サンドボックスのデータ(REQ-NEW-001)の復元この演習は独立した work/ で行う。11-04で残ったデータは扱っていない11-04 の切戻し判断時に、この記事の手順を当てはめる

残る制限:この演習は、小規模な架空データ(依頼3〜4件)を対象にしたものです。この記事の本文と演習コードはClaude Codeが作成したもので、業務担当者による内容確認は行っていません。

8. 設計を判断する

8.1 復元できたことと、利用可否の判断は別

復元して3照合が一致したことは、「バックアップの内容が正しく戻せた」ことを示すものであり、それだけで利用を再開してよいことにはなりません。戻らない変更(この記事ではREQ-D04、REQ-D01の状態変更)を関係者に伝え、それらをどう扱うか(作り直す、諦めるなど)を決めてから、利用再開を判断します。

8.2 バックアップの頻度と保存先を判断する

選択肢内容適する場合
バックアップの頻度を高くする戻らない変更の量を減らせるが、確認の手間・保存の費用が増える変更の頻度が高く、損失の影響が大きい業務
バックアップの頻度を低くする確認の手間・費用を抑えられるが、戻らない変更が増える可能性がある変更の頻度が低い、または損失の影響が小さい業務

この記事の題材アプリ(社内の依頼・承認)では、業務日ごとの変更量は多くないと考えられるため、日次程度の頻度が候補になります(架空の仮定であり、実際の運用では業務担当者と確認する必要があります)。

8.3 コードの切戻しとデータの復元を組み合わせるとき

11-04のコードの切戻しでは、新版の稼働中に増えたデータ(REQ-NEW-001)が残りました。データも基準時点へ戻す必要があるときに、この記事の手順(別の場所へ復元→3照合→戻らない変更の一覧→扱いを決める)を当てはめます。コードだけ戻すか、データも戻すかの判断は 11-04 の第8.2節にあります。

9. 持ち帰る成果物

成果物空欄版記入例
復元演習記録ひな形(バックアップの基準時点、復元先、手順、件数照合、内容照合、関係の照合、利用可否、戻らない変更、実施者、日時)templates/12-04-restore-drill_template.mdtemplates/12-04-restore-drill_example.md
復元演習コード一式examples/12-04-restore-drill/(drill.js、run.js、run_reject_check.js)同上
実行記録(stdout・stderr・終了コード、整形なし)—evidence_public/phase5b2c1-2026-09-21/12-04/run_log.md

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

  1. 演習用の架空データでバックアップ(基準時点)を作る
  2. 基準時点より後の変更を加える
  3. 別の場所へ復元し、件数・内容・関係の3照合を行う。復元先が既にあれば上書きしない
  4. 戻らない変更を洗い出し、利用再開の判断材料として記録する
  5. コード・コマンド・出力・終了コードをそのまま実行記録に残す

10. 次工程への受渡し

次へ渡すもの:復元演習記録、復元演習の実行記録。

次工程での使われ方:13-04(引継ぎ・移行・廃止を行う)では、この演習記録を引継ぎ資料の一部として使います。05-04の復旧方針の見直しにも使います。11-04でデータも戻す必要が出た場合は、この記事の手順を当てはめます。

前工程へ戻る条件:復旧方針そのものに見直しが必要な場合は、05-04に戻って確認します。

11. 根拠と更新情報

  • この記事の会社・人物・データはすべて架空の設定です。
  • 「基準時点どおり、元どおりではない」という考え方、別の場所への復元、戻らない変更の扱いは、記事C(SAMPLE-C、12-03)と同じものです。
  • 制作の来歴:本文はClaude Codeが作成しました。第5節のコードは examples/12-04-restore-drill/ を正本とし、2026-09-21にmacOS 26.6.2・Node.js v24.18.0の環境で実際に実行して、stdout・stderr・終了コードを evidence_public/phase5b2c1-2026-09-21/12-04/run_log.md に記録しています。人(ユーザー)による実読・内容確認は未実施です。
  • 2026-09-21(Phase 5B-2C1):初版(2026-09-20)の第6節は、run.js の出力 JSON を1行にまとめて整形したものを「実行結果」として載せ、第5.5節の reconcile() は本体を省略した抜粋だった。また、拒否の確認は node -e "require('./drill.js').restore()" の結果として「拒否されました: …」という stdout を載せていたが、実際にはこの呼び方では stdout に何も出ず、stderr に例外の stack が出て終了コード1になる。本更新で、記事のコードを正本の全文に、実行結果を再実行の実測そのまま(整形なし)に置き換え、拒否の確認は例外を受け止めて表示する run_reject_check.js を正本に加えて実測した。演習の内容(データ・手順・3照合の結果)は変えていない。
  • 未確認事項:実際のバックアップの規模・保存先、実際のデータベースでの復元、戻らない変更の扱いの決定、利用再開の判断は、この記事の時点では確認していません。