resilience-review について
resilience-reviewは、Webアプリの障害対応とエッジケースを評価するスキルです。リリース前の確認や信頼性改善に向け、ブラウザーで障害を注入して証拠を記録し、修正案とYAML回帰テストを提示します。
主な機能
- 01API呼び出し、依存関係、重要フローの整理
- 02エラー、縮退状態、エッジケースの検査
- 03ブラウザーでの障害注入と証拠記録
- 04ユーザー影響と確信度の報告
- 05修正案とYAML回帰テストの提示
活用シーン
- 01機能リリース前の障害対応確認
- 02本番インシデント後の信頼性調査
- 03新しいAPI連携やデータソースのテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ shiplightai/ agent-skills --skill resilience-reviewインストール後、Claude Code で/resilience-reviewを入力して読み込まれたか確認します。
詳細
レジリエンスレビュー
ネットワーク障害、API エラー、接続の遅延、データの欠落、エッジケースなど、問題が発生したときにアプリケーションがどのように動作するかを評価します。多くのアプリは正常系を前提に構築されています。このレビューでは、実際のユーザーが遭遇する異常系を体系的にテストします。
使用するタイミング
/resilience-review は、次のような場合に使用します。
- ユーザー向け機能の公開前
- 新しい API 連携やデータソースの追加後
- 信頼性が重要な場合(医療、金融、EC のチェックアウト)
- 未処理のエラーが原因で本番環境のインシデントが発生した後
- プロトタイプから本番品質へ移行するとき
参照する基準
- Google SRE Principles — エラーバジェット、適切な縮退
- Netflix Chaos Engineering Principles — 定常状態を確認し、現実に起こり得る障害を注入
- OWASP Error Handling — セキュアでユーザーフレンドリーなエラーレスポンス
- Nielsen Norman Group — エラーメッセージの使いやすさに関するヒューリスティック
フェーズの概要
Phase 1: EDUCATE → Why resilience matters and what we test
Phase 2: SCOPE → Map failure points, dependencies, critical flows
Phase 3: ANALYZE → Browser-based fault injection and edge case testing
Phase 4: REPORT → Findings with evidence and user impact assessment
Phase 5: REMEDIATE → Fix guidance + YAML regression tests
フェーズ 1:知識の共有
重要な理由: ユーザーがアプリを使うのは、理想的な環境とは限りません。ページの読み込みに 3 秒以上かかると、モバイル訪問の 53% が離脱します。案内のないエラーページは、サポートへの問い合わせを 5 倍に増やします。画面が真っ白になるのは、最悪の障害モードです。ユーザーに何も伝えず、復旧の手段も提供しません。レジリエントなアプリは、バックエンドシステムに障害が起きても信頼を保ちます。
このレビューでは、ブラウザー上で現実に起こり得る障害状況をシミュレートし、UI の応答を評価します。
フェーズ 2:範囲の設定
コンテキストの収集
-
コードベースから自動検出:
- API 呼び出しとそのエンドポイント
- エラーバウンダリーコンポーネント(React ErrorBoundary、Vue errorHandler)
- 読み込み状態の実装(スピナー、スケルトン、サスペンス)
- 空の状態を表示するコンポーネント
- 再試行ロジック/エラー復旧パターン
- オフライン対応(サービスワーカー、キャッシュ戦略)
- サードパーティサービスへの依存関係
-
ユーザーへの確認(一度に 1 つずつ):
- 対象 URL:アプリはどこで実行されていますか?
- 重要なユーザーフロー:どのフローでも画面が真っ白になってはいけませんか?(ルートから自動検出)
- 主要な API 依存関係:フロントエンドはどの API に依存していますか?(自動検出)
- 既知の脆弱な箇所:頻繁に問題が起きるページや機能はありますか?(任意)
-
障害ポイントのマッピング:
- フロントエンドが呼び出す API エンドポイント(それぞれで障害が起きた場合の動作)
- サードパーティへの依存関係(CDN、認証プロバイダー、分析、地図、決済)
- データ依存の UI(データが空、欠落、不正な形式の場合に表示されるもの)
- ユーザー入力のエッジケース(長文、特殊文字、空の送信)
フェーズ 3:分析
record_evidence: true を使用して new_session でブラウザーセッションを開始します。該当するすべてのチェックカテゴリを実行します。
カテゴリー A:エラー処理(ERR)
| チェック ID | チェック項目 | 標準 | 方法 |
|---|---|---|---|
| ERR-01 | API エラー時に、空白画面ではなくユーザーにわかりやすいメッセージが表示される | UX のベストプラクティス | API が 500 を返すようにモックし、UI の応答を確認する |
| ERR-02 | ネットワークタイムアウト時に適切な状態が表示される | UX のベストプラクティス | ネットワーク遅延(30s)をモックし、UI を確認する |
| ERR-03 | 404 ページがあり、役立つ情報が表示される | UX のベストプラクティス | 存在しないルートに移動する |
| ERR-04 | JavaScript エラーがページのクラッシュを引き起こさない | エラーバウンダリー | JS エラーを発生させ、ページが復旧するか確認する |
| ERR-05 | エラーメッセージが具体的な対応につながる | NN/g のヒューリスティック | エラーメッセージに、何が起きたか、なぜ起きたか、どうすればよいかが含まれているか確認する |
| ERR-06 | エラーによって技術的な詳細が漏えいしない | OWASP | エラーメッセージにスタックトレース、SQL、内部パスが含まれていないか確認する |
| ERR-07 | フォームのバリデーションエラーが明確で、適切な位置に表示される | UX のベストプラクティス | 無効なフォームを送信し、エラーの表示位置とテキストを確認する |
| ERR-08 | エラー状態からページを再読み込みせずに再試行できる | UX のベストプラクティス | エラー発生後、再試行ボタンまたは復旧操作があるか確認する |
| ERR-09 | 複数のエラーが同時に発生した場合も適切に処理される | レジリエンス | 複数の API エラーをモックし、UI で連鎖的に問題が発生しないか確認する |
| ERR-10 | エラーログによって PII が漏えいしない | OWASP / プライバシー | エラー発生時に get_browser_console_logs を確認する |
ブラウザーでの検証: description: + js: ステートメントを使い、page.route() 経由でネットワークリクエストをインターセプトして、失敗をシミュレートします。各失敗後の UI の状態を確認します。JavaScript エラーの確認には get_browser_console_logs を使用します。
// Example: Mock API 500 error
await page.route('**/api/**', route => {
route.fulfill({ status: 500, body: JSON.stringify({ error: 'Internal Server Error' }) });
});
カテゴリー B:グレースフルデグラデーション(DEG)
| チェック ID | チェック項目 | 標準 | 方法 |
|---|---|---|---|
| DEG-01 | JavaScript が無効でもページが動作する(基本コンテンツ) | プログレッシブエンハンスメント | JS を無効にし、コンテンツにアクセスできるか確認する |
| DEG-02 | 低速接続(3G シミュレーション)でもページが動作する | パフォーマンス | 低速 3G にスロットリングし、読み込み時の挙動を確認する |
| DEG-03 | 重要度の低い機能が縮退しても、重要な機能が壊れない | グレースフルデグラデーション | サードパーティスクリプトを無効にし、主要な機能を確認する |
| DEG-04 | オフライン状態が処理される(該当する場合) | PWA のベストプラクティス | オフラインにし、UI の状態とメッセージを確認する |
| DEG-05 | サードパーティサービスに障害が発生してもページの読み込みが妨げられない | レジリエンス | サードパーティドメインをブロックし、ページが読み込まれるか確認する |
| DEG-06 | 画像の読み込みに失敗した場合に代替表示が行われる | UX のベストプラクティス | 画像 URL をブロックし、代替テキストまたはプレースホルダーが表示されるか確認する |
| DEG-07 | フォントの読み込みに失敗してもテキストが隠れない | FOUT の処理 | フォント URL をブロックし、テキストが引き続き表示されるか確認する |
| DEG-08 | ブラウザー判定より機能検出を優先する | プログレッシブエンハンスメント | コード内で機能検出ではなく navigator.userAgent を使用していないか確認する |
ブラウザーでの検証: page.route() を使って特定のリソースをブロックします。CDP を使ってネットワーク状態をシミュレートします。ブラウザーの設定で JavaScript を無効にします。それぞれの縮退シナリオを検証します。
カテゴリ C:空の状態とエッジケース(EDGE)
| チェック ID | チェック項目 | 基準 | 方法 |
|---|---|---|---|
| EDGE-01 | データが空の状態で役立つメッセージが表示される | UX のベストプラクティス | データのないページに移動して、表示を確認する |
| EDGE-02 | ページネーションが検索結果 0 件に対応している | UX のベストプラクティス | 存在しない語句を検索して、ページネーションを確認する |
| EDGE-03 | 長いテキストによってレイアウトが崩れない | 防御的な CSS | 非常に長い文字列(500 文字以上)を入力して、はみ出しを確認する |
| EDGE-04 | 入力内の特殊文字によって UI が崩れない | 入力処理 | <script>、"'&<>、絵文字、Unicode を入力する |
| EDGE-05 | 大量のデータでも UI がフリーズしない | パフォーマンス | 最大量のデータがあるページを読み込み、応答性を確認する |
| EDGE-06 | ユーザーの素早い操作によって送信が重複しない | 状態管理 | 送信ボタンをダブルクリックする、素早く移動する |
| EDGE-07 | 戻る/進むナビゲーションで状態が維持される | 履歴管理 | フォームに入力して別のページに移動し、戻る |
| EDGE-08 | 更新後も想定される状態が維持される | 状態の永続化 | 複数ステップのフロー中に更新し、状態を確認する |
| EDGE-09 | 複数のタブ/セッションでの動作 | セッション管理 | 同じページを 2 つのタブで開き、操作を行う |
| EDGE-10 | 最大ファイルアップロードサイズが処理される | 入力検証 | サイズ超過のファイルをアップロードし、エラーメッセージを確認する |
ブラウザーでの検証: ページに移動して、各エッジケースをテストします。act を使ってフォームを操作し、空のデータや極端なデータを送信します。JavaScript を使って、UI のはみ出しやフリーズ状態を確認します。
カテゴリ D:API 契約とデータ処理(API)
| チェック ID | チェック項目 | 基準 | 方法 |
|---|---|---|---|
| API-01 | UI がすべての HTTP エラーコードを適切に処理する | API 契約 | 400、401、403、404、422、429、500、503 をモックする |
| API-02 | UI がクラッシュせずに null/undefined フィールドを処理する | 防御的コーディング | null フィールドを含む API レスポンスをモックする |
| API-03 | UI が空の配列/オブジェクトを処理する | 防御的コーディング | 空のコレクションを含む API レスポンスをモックする |
| API-04 | UI が想定外のデータ型を処理する | 防御的コーディング | 誤った型を含む API レスポンスをモックする |
| API-05 | API 呼び出し中に読み込み状態が表示される | UX のベストプラクティス | API に 2 秒の遅延を追加し、読み込みインジケーターを確認する |
| API-06 | 競合状態(古いレスポンス)が処理される | 状態管理 | 連続して素早くリクエストを発生させ、最新のものが反映されることを確認する |
| API-07 | レート制限(429)がユーザーへのフィードバックとともに処理される | API 契約 | 429 レスポンスをモックし、UI のフィードバックを確認する |
| API-08 | セッション中に認証が期限切れになった場合に処理される | セッション管理 | セッション中に 401 をモックし、ログインへのリダイレクトを確認する |
ブラウザーでの検証: page.route() を使って各レスポンスのシナリオをモックします。各モック後の UI の状態を確認します。
カテゴリ E:復旧とユーザーへの通知(REC)
| チェック ID | チェック項目 | 基準 | 方法 |
|---|---|---|---|
| REC-01 | 一時的な障害に対する再試行の仕組みがある | 耐障害性 | 断続的な障害をモックし、自動再試行を確認する |
| REC-02 | ユーザーが障害後に手動で再試行できる | UX のベストプラクティス | エラーの後、再試行の操作が可能か確認する |
| REC-03 | エラーが発生しても入力内容が失われない | UX のベストプラクティス | 長いフォームに入力してエラーを発生させ、データが維持されることを確認する |
| REC-04 | 機能が低下していることをユーザーに知らせる | コミュニケーション | 機能に障害が発生したとき、機能低下の通知があるか確認する |
| REC-05 | 復旧の操作が明確で、アクセスしやすい | NN/g のヒューリスティクス | エラーの種類ごとに、復旧時の UX を評価する |
| REC-06 | バックグラウンド処理のステータスインジケーターがある | UX のベストプラクティス | 非同期処理を開始し、進行状況のフィードバックを確認する |
ブラウザーでの検証: 障害を注入してから、復旧経路を確認します。
フェーズ 4:レポート
構造化されたレポートを shiplight/reports/resilience-review-{date}.md に保存します。
# Resilience Review Report
**Date:** {date}
**URL:** {url}
**Critical flows tested:** {list}
**API dependencies tested:** {count}
**Failure scenarios simulated:** {count}
## Overall Score: {X}/10 | Confidence: {X}%
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| Error Handling (ERR) | 5/10 | 2 critical, 1 high |
| Graceful Degradation (DEG) | 6/10 | 1 high, 2 medium |
| Empty & Edge States (EDGE) | 4/10 | 1 critical, 3 high |
| API Contract (API) | 7/10 | 1 high, 1 medium |
| Recovery (REC) | 3/10 | 2 high, 1 medium |
## Failure Matrix
| Failure Scenario | Expected Behavior | Actual Behavior | Status |
|-----------------|-------------------|-----------------|--------|
| API returns 500 | Error message + retry | Blank screen | FAIL |
| Network timeout | Loading → timeout message | Infinite spinner | FAIL |
| Empty data set | "No results" message | Blank page | FAIL |
| ... | | | |
## Findings
(structured findings with evidence, screenshots of failure states)
信頼度スコア
- 90-100%:障害を注入し、ブラウザーで障害時の動作を検証済み
- 70-89%:コード分析でエラーハンドリングの欠如が判明したが、実行時には検証していない
- 50-69%:パターンに基づく評価(例:エラーバウンダリーが検出されない)
- 50% 未満:報告しない
フェーズ 5:修正
1. 修正ガイダンス(例)
#### ERR-01: API error shows blank screen instead of error message
**Impact:** Users see empty page, think app is broken, leave
**File:** src/pages/Dashboard.tsx:45
**Current:** `const data = await fetch('/api/data').then(r => r.json())`
**Problem:** No error handling — fetch throws on network error, .json() throws on non-JSON response
**Fix:**
- Wrap in try/catch
- Add error state: `const [error, setError] = useState(null)`
- Render error UI with retry button
- Add React Error Boundary as fallback
2. YAML 回帰テスト
- name: err-01-api-error-shows-message
description: Verify API failure shows user-friendly error message instead of blank screen
severity: critical
standard: UX-Error-Handling
steps:
- description: Mock the data API to return a 500 error
js: |
await page.route('**/api/data**', route => {
route.fulfill({
status: 500,
contentType: 'application/json',
body: JSON.stringify({ error: 'Internal Server Error' })
});
});
- URL: /dashboard
- WAIT_UNTIL: Page has finished attempting to load data
timeout_seconds: 15
- VERIFY: An error message is visible explaining that data could not be loaded
- VERIFY: A retry button or recovery action is available to the user
- VERIFY: The page is NOT blank — navigation and header are still visible
すべての YAML テストを shiplight/tests/resilience-review.test.yaml に保存してください。
ヒント
description: + js:ステートメントでpage.route()を使用します。これが障害注入の主要なツールです。- 最も重要なユーザーフロー(チェックアウト、サインアップ、主要機能)からテストします。
- 画面が真っ白な状態は常に CRITICAL の指摘事項です。最悪の障害モードです。
get_browser_console_logsで捕捉されないプロミスの拒否を確認します。これはエラーハンドリングが不足していることを示します。- エッジケースのテスト(EDGE カテゴリー)では、多くの場合、短時間で最も多くのバグが見つかります。
close_sessionでセッションを終了し、証拠としてgenerate_html_reportを使用します。