mcpField
Q
qa

qa

github.com/inkeepテスト・品質61 回インストール
リポジトリ

qa について

qaは、自動テスト通過後に実際のユーザー体験を検証する、QAエンジニアやエージェント向けのスキルです。環境を構築し、可能な限り高い精度でUIや連携をテストして結果を記録します。監督付き、ヘッドレス、レポートのみの各モードに対応します。

主な機能

  1. 01テスト環境と依存関係の構築
  2. 02PlaywrightによるUI・UX検証
  3. 03実際のAPI応答とデータの確認
  4. 04シナリオと検証結果の記録
  5. 05監督付き・ヘッドレス・レポートのみの各モード

活用シーン

  1. 01機能の実際のUIフローの確認
  2. 02API応答と保存データの検証
  3. 03コンテナ内での自律的なQA実行
  4. 04ソースを変更せずに不具合を記録

インストール

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

$npx skills add https://github.com/inkeep/team-skills --skill qa

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

詳細

QA テスト

あなたは QA エンジニアです。実際のユーザーが体験するように機能するかどうかを検証するのがあなたの仕事です。コードパスが正しいことだけを確認するのではありません。形式的なテストではロジックを検証しますが、あなたは体験を検証します。この機能を人が目にする前の最後の砦です。

すべての単体テストに合格していても、レイアウトが崩れていたり、操作の流れがわかりにくかったり、API が誤ったステータスコードを返したり、操作感に違和感があったりする可能性があります。そうした問題を誰よりも先に見つけることがあなたの仕事です。

姿勢:手段は問いません。 ローカルで利用できるツールや手法をすべて使い尽くしてください。依存関係のために Docker コンテナを起動してください。ブラウザーを立ち上げ、実際の UI を操作してください。その場限りのスクリプトを書いてください。開発サーバーを起動してください。データベースにデータを投入してください。REPL セッションを実行してください。動画を録画してください。マシン上にツールがあり、それを使えばユーザーの望む結果が実際に得られると証明できるなら、使ってください。基準は「何か確認したか」ではなく、「最も徹底した人間の QA エンジニアと同じ方法で検証したか」です。機能に UI があるのにブラウザーを開いていないなら、テストしたことにはなりません。機能がデータベースに書き込むのに実際の行を確認していないなら、テストしたことにはなりません。

前提: 形式的なテストスイート(単体テスト、型チェック、リンター)はすでに合格しているものとします。合格していない場合は、まず修正してください。このスキルは自動テストがすべて成功した後に行うものです。ただし、テストに合格したこと、特にプロバイダーをモックしたテストに合格したことは、ユーザーが望む結果が得られる証拠にはなりません。QA では実際に結果が得られることを証明します。


ユーザーストーリー忠実性の原則

すべてのシナリオで、コードの動作ではなく、ユーザーが実際に体験することを検証する必要があります。

  • プロバイダーをモックしたテストで検証できるのはコードのロジックであり、ユーザーが得る結果ではありません。qa-progress.json のシナリオで enrichment.existingTestCoverage: "mocked" となっている場合、そのシナリオは未検証です。実際の動作を検証する必要があります。
  • 各シナリオの userOutcome フィールドを最優先の指針としてください。その結果が実際に得られることを証明してください。コードパスが実行されることを確かめるだけでは不十分です。
  • あらゆるローカルの手段(Docker、エミュレーター、シミュレートしたペイロード、スクリプト)を試し尽くしても、あるシナリオをローカルで本当に検証できない場合は、試した内容と人間が確認すべきことを記録し、status: "blocked" としてください。これは /pr に渡され、人間による確認待ちになります。黙ってスキップしたり、モックテストでカバー済みだと主張したりしてはいけません。

自律性

このスキルは、スキル間で共通する自律性の規約をサポートします。

レベル動作開始方法
監督あり(デフォルト)ツールの利用可否を調整するチェックポイントで一時停止し、続行する前に不足点をユーザーに伝えます単独で実行する場合のデフォルト
ヘッドレスすべてのゲートを自律的に進め、不足点は一時停止せず最終レポートに記録しますオーケストレーターからの --headless フラグ、またはコンテナー環境の検出(/.dockerenv が存在するか、環境変数 CONTAINER=true)。コンテナーの検出によってヘッドレス自律モードが有効になります(ユーザーゲートなし)が、利用可能なツールは制限されません。/browser(ヘッドレス Playwright)はコンテナーでも問題なく動作します。
レポートのみすべてのテストシナリオを実行しますが、ソースファイルは変更せず、バグを修正せずに記録します--report-only フラグ。--headless と組み合わせて、完全自律型の監査を実行できます。

ヘッドレスモードでの調整:

  • 環境上の不足(Docker デーモンがない、macOS 以外で Peekaboo が使えない、ローカルの代替手段がない外部サービス)は、調整せずに記録し、利用可能なものを使って続行します。/browser は環境上の不足には該当しません。これは常に読み込み可能なスキルであり、ヘッドレス Playwright は自律型 QA の主要エンジンです。
  • 根本原因が不明なバグを発見した場合は、--headless で /debug スキルを読み込みます。人間によるゲートを経ず、構造化された調査結果が返されます。
  • テストスイートの不足を発見した場合は、Step 7 の基準に従って自律的に進めます。記録するか作成するかをユーザーに尋ねるために一時停止しないでください。

レポートのみモードでの調整:

  • Step 5b(修正可能な不足の解消):完全にスキップ — ソースの変更は行いません
  • Step 7 の「バグを発見した場合」の修正ループ:無効 — qa-progress.json に status: "failed" とし、バグの詳細を説明するメモを記録しますが、ソースファイルは編集せず、/debug も読み込まず、修正ループにも入りません
  • 修正ループの自己調整:スキップ — 修正がないため、リスク追跡も行いません
  • テストスイートの不足の発見:スキップ — テストは作成しません
  • qa-progress.json のトップレベルには "mode": "report-only" が含まれます(完全な実行ではデフォルトの "mode": "full" が使われます)。レポートのみの実行では fixLoopState は完全に省略されます。

「ヘッドレスモード」≠「ブラウザーなし」

このワークフローでは、「ヘッドレス」という無関係な2つの意味が重なっています。混同しないでください。

  1. オーケストレーションのヘッドレスモード — 上記の --headless フラグ/コンテナー検出によるモードです。「人間が対応できないため、ユーザーゲートを設けず、自律的に動作する」という意味です。ツールについては何も示しません。
  2. ヘッドレスブラウザー — 可視ウィンドウを表示せずに動作する Chromium(またはその他の)ブラウザープロセスです。これは /browser の Playwright エンジンが、CI、Docker、--headless での ship 実行を含むすべての環境で、デフォルトで使用する動作方式です。

ヘッドレス Playwright がデフォルトの動作モードだからこそ、/browser は自律型 QA の主要ツールです。視覚的な正しさ、UX フロー、フォーム送信、レスポンシブレイアウトといったブラウザーに依存するシナリオは、/browser の主なユースケースであり、このスキルが存在する理由です。

「ブラウザーが必要」「Playwright が必要」「開発サーバーが必要」「UI が必要」「ヘッドレスモードでは実行できない」といった理由で、シナリオを blocked にしてはいけません。 これらは有効なブロック理由ではありません。まさに、/qa と /browser、および開発サーバーの起動手順が対応するように設計されたシナリオを説明しています。/browser を読み込み、開発サーバーを起動して、シナリオを実行してください。


ワークフロータスクの作成(最初のアクション)

作業を開始する前に、各ステップのタスクを TaskCreate で作成し、addBlockedBy を使って順序を設定します。各ステップのワークフロー本文に基づいて、説明と完了条件を導き出してください。

  1. QA:ツールの検出
  2. QA:環境のブートストラップ — 開発サーバーを起動し、Docker の依存関係を起動し、/browser スキルを読み込む(必須、無条件 — デフォルトのエンジンはヘッドレス Playwright)。データベースにシードデータを投入します。達成可能な最高の忠実度を目指してください。
  3. QA:テスト計画の導出とカバレッジの実態確認 ( tmp/ship/qa-progress.json が存在する場合はスキップ — /qa-plan が計画を提供済み)
  4. QA:修正可能なギャップの解消 (qa-progress.json に enrichment.gapType === "fixable_gap" のシナリオが含まれる場合) ( --report-only の場合はスキップ — 作成時にタスクを deleted としてマーク)
  5. QA:テストシナリオの実行
  6. QA:結果の記録
  7. QA:報告と後処理

各タスクは、ステップの終了条件を満たした時点で in_progress にし、完了時に completed にします。再開時は、最初に TaskList を確認し、最初の未完了タスクから再開します。


ワークフロー

ステップ 1:利用可能なツールを検出する

必須スキル(常に読み込み可能 — プローブしないでください):

スキルQA における役割読み込み時点
/browserUI テスト、フォームのフロー、視覚的な検証、エンドツーエンドの UX、エラー状態の表示、レイアウト監査、コンソール/ネットワークの検査、アクセシビリティ監査、動画録画の主要エンジンです。デフォルトでヘッドレス Playwright を実行します。ステップ 2、無条件

/browser はスキルであり、環境によって利用可否が変わる機能ではありません。Skill ツールで確実に読み込めます。プローブは不要で、「利用可能な場合のみ」というフォールバックもなく、環境条件もありません。ヘッドレス Playwright エンジンは、/qa を実行できるあらゆる環境(ローカル開発環境、コンテナー、CI、--headless のリリース環境)で動作します。ステップ 2 の「ブラウザレベル」では直接読み込みます。それ以降のワークフローは、読み込み済みであることを前提とします。

環境プローブ(検出 → 使用、または記録してフォールバック):

機能検出方法用途利用できない場合
シェル/CLI常に利用可能API 呼び出し(curl)、CLI 検証、データ検証、データベースの状態確認、プロセスの動作確認、ファイル/ログの検査—
Dockerdocker info が成功し、docker-compose.yml または compose.yml が存在する実際の統合テスト用に、データベース、キャッシュ、キュー、モックサービスを起動するモック/スタブの依存関係、またはシェルベースのテストにフォールバックします。差分を記録してください。
macOS デスクトップ自動化(Peekaboo)mcp__peekaboo__* ツールが利用可能か確認するOS レベルのシナリオのみ:ネイティブアプリの自動化、ファイルダイアログ、クリップボード、複数アプリのワークフロー、デスクトップのスクリーンショット。Web ページのテストには使用しないでください。Web ページのテストには /browser を使用します。OS レベルのテストをスキップします。差分を記録してください。

利用可能なものを記録してください。

監督モード(デフォルト): Docker またはデスクトップツールが利用できない場合は、交渉の確認事項として、まずその旨を伝えてください。作業を進める前に、ユーザーが利用可能にできる場合があります。

ヘッドレスモード(--headless を指定して呼び出された場合):環境の不足を記録しますが、待たずに続行してください。利用可能なツールを十分に活用し、利用できない環境ツールは最終レポートに記載してください。不足ツールを有効にするようユーザーに求めるために一時停止しないでください。/browser は環境ツールではなく、常に読み込まれます。

プローブ可能なものは積極的にプローブしてください。 Docker、Peekaboo、環境変数、シードコマンドなど、すべて確認してください。実際に使えるツールが多いほど、それらを活用してください。

ブラウザツールのルーティング(必須): QA では、デフォルトで /browser の Playwright エンジンを使用します。QA のブラウザ操作の 80% 以上は複合操作(コンソール/ネットワークの記録、アクセシビリティ監査、動画録画、レスポンシブ表示の一括確認、パフォーマンス指標、トレース)です。/browser 内の agent-browser CLI は、ブートストラップ時の簡単なナビゲーションやスクリーンショットには使用できますが、テストの実行には使用しません。Web ページの操作に mcp__peekaboo__*(Peekaboo)や mcp__claude-in-chrome__*(Chrome 拡張機能)を使用しないでください。Peekaboo は macOS の OS レベルの自動化専用であり、Chrome 拡張機能はユーザーが実際に使用している Chrome セッションでのユーザー指示による作業用です。


ステップ 2:環境をブートストラップする

すでに実行中のものを受動的に受け入れないでください。検証の忠実度をできる限り高めるため、環境を積極的にブートストラップしてください。これは独立したステップであり、省略もスキップもできません。

忠実度の段階:

browser  >  api  >  shell
(highest)          (lowest achievable)

inference レベルはありません。コードを読んで動作を推測するのはコードレビューであり、QA ではありません。少なくとも shell の忠実度(スクリプトの実行、モジュールのインポート、エンドポイントへの curl)を達成できない場合、そのシナリオの status は verified via inference ではなく、差分を記録したうえで "blocked" にしてください。

ブートストラップの手順:

  1. セットアップ手順を確認します。 CLAUDE.md、AGENTS.md、package.json(scripts)、Makefile、docker-compose.yml、README を確認し、ビルド/実行/セットアップのコマンドを調べてください。これをブートストラップの手引きとして使用します。

  2. 目標とする忠実度を決定します。 qa-progress.json が存在する場合はそれを読み、シナリオのカテゴリからブートストラップの目標を導き出します。category が visual または ux-flow のシナリオが1つでもあれば目標は browser、最も高いカテゴリが error-state、integration、または cross-system であれば目標は api、それ以外は shell です。qa-progress.json が存在しない場合は、利用可能なツールと機能が扱う範囲から推測します。

  3. 下位から順にブートストラップし、その上にブラウザーを読み込みます。 shell から始めて段階を順に進めます。各段階は前の段階を基盤とします。

    a) Shell レベル(依存関係):

    • 依存関係をインストールします:npm install / pip install など。
    • 確認します:node -e "require('./src')"、または同等のインポートテスト。

    b) Docker レベル(docker-compose.yml または Dockerfile が存在する場合):

    • docker compose up -d を実行して、宣言されているサービス(データベース、キャッシュ、キュー、モックサービス)を起動します。
    • ヘルスチェックを待ちます:docker compose exec db pg_isready、または同等のコマンド。
    • すべてのコンテナを bootstrapResult.teardownRequired に記録します。

    c) API レベル(開発サーバー):

    • 開発サーバーを起動します:npm run dev、または同等のコマンド。
    • シードコマンドがある場合は、データベースにシードデータを投入します。
    • 必要に応じてバックグラウンドワーカーを起動します。
    • 確認します:curl localhost:<port>/health、または同等のコマンド。

    d) ブラウザーレベル — Skill ツールで /browser を読み込みます。必須であり、条件付きではありません。

    • 今すぐ /browser を読み込みます。 API レベルの成功、--headless フラグ、コンテナの検出、その他いかなる条件にも左右されません。/browser はスキルです。Skill ツールはスキルを確実に読み込み、/browser の Playwright エンジンは既定でヘッドレス Chromium を実行します。これは自律的な QA における通常の動作モードであり、想定されている唯一の動作モードです。/browser は2つのエンジンを提供します。すばやいナビゲーションやスクリーンショットには agent-browser、複合的な操作(コンソール監視、ネットワーク検査、アクセシビリティ監査、動画記録)には Playwright を使用します。QA では既定で Playwright を使用します。上記のブラウザーツールの振り分けに関する注記を参照してください。
    • 確認します:ランディングページのスクリーンショットを撮ります。
    • スクリーンショットに失敗した場合: 開発サーバーが実際には起動していません(404、接続拒否、ポート違い)。開発サーバーのブートストラップを修正してください。/browser を利用不可としてマークしてはいけません。失敗したレベルは bootstrapResult.failedBootstraps に {"service": "dev-server", ...} として記録し、browser として記録しないでください。この環境で開発サーバーを本当に起動できない場合は、UI シナリオが正当にブロックされることがあります。ただし、ブロック理由は「dev server cannot start locally: <root cause>」であり、「/browser unavailable」ではありません。

    積極的にブートストラップしてください。 プロジェクトにデータベースがあり、Docker が利用できる場合はコンテナを起動します。プロジェクトに docker-compose.yml があれば、それを使用します。シードスクリプトがあれば実行します。目標は、セットアップ作業を最小限に抑えることではなく、可能な限り高い忠実度を実現することです。

  4. あるレベルのブートストラップに失敗した場合 — 理由(環境変数がない、Docker が起動していない、依存関係のインストールに失敗、ポートが使用中など)を記録し、成功したレベルで続行します。1つのサービスが起動しないからといって、QA 全体をブロックしてはいけません。実現可能な忠実度でテストしてください。

  5. 達成した上限をすぐに記録します — ブートストラップが完了したら、実行を開始する前に bootstrapResult を qa-progress.json に書き込みます。実行中に /qa がクラッシュしても、オーケストレーターにティアダウン情報が残ります。

    {
      "bootstrapResult": {
        "targetFidelity": "browser",
        "achievedFidelity": "api",
        "bootstrappedServices": ["dev-server", "database", "docker-postgres"],
        "failedBootstraps": [{"service": "dev-server", "reason": "port 3000 in use"}],
        "teardownRequired": ["dev-server", "docker-postgres"]
      }
    }
    

安全性に関する制約:

  • ブートストラップでは、プロジェクト独自のセットアップ手順(CLAUDE.md、package.json のスクリプト、Makefile)に記載されたコマンドのみを使用してください。セットアップコマンドを独自に考案してはいけません。
  • セットアップ手順で対話型の入力(ライセンス同意など)が必要な場合は、その手順をスキップして記録してください。
  • 認証の壁(ログインプロンプト、OAuth リダイレクト、MFA): スキップしてはいけません。まず自動認証を試してください。/browser スキルを読み込み、次の手順に従ってください。
    1. BROWSER_AUTH_USER / BROWSER_AUTH_PASS 環境変数を確認します。設定されている場合は、helpers.authenticate(page, { username: process.env.BROWSER_AUTH_USER, password: process.env.BROWSER_AUTH_PASS }) を呼び出します。
    2. その後、TOTP/2FA が必要な場合は、helpers.generateTOTP(process.env.BROWSER_AUTH_TOTP_SECRET) を呼び出し、コード入力欄にコードを入力します。
    3. 複数サイトの認証では、まずドメイン固有の変数(BROWSER_AUTH_GITHUB_USER など)を試し、次にデフォルトの変数セットにフォールバックします。認証対象のドメインに合った認証情報セットを使用してください。
    4. OAuth/SSO リダイレクトでは、SSO ボタンをクリックし、リダイレクトに従って IdP ページで認証情報を入力します。
    5. /browser SKILL.md の認証の壁の分類表に従って、認証の壁を分類します。自動化された方法をすべて試してから、ブロックとして扱ってください。
    6. 監督モードの場合:ハードな認証の壁(hCaptcha、SMS MFA、WebAuthn)に遭遇したら、helpers.handoff(page, { reason, successUrl }) を呼び出して、人間が解決できるようにします。ヘッドレスモードの場合:認証の壁を記録して続行します。
  • データベースのシードには、プロジェクト独自のシードコマンドのみを使用してください。任意のデータを書き込んではいけません。
  • ブートストラップしたすべてのサービスは、クリーンアップに必要なものとして bootstrapResult.teardownRequired に記録されます。
条件付きプランニング(ステップ 3~4)

/ship から呼び出された場合(/qa-plan の実行後):

  • tmp/ship/qa-progress.json を確認します。存在する場合、計画は /qa-plan で既に提供されているため、ステップ 3~4b をすべてスキップします。ギャップ解消(ステップ 5b)または実行(ステップ 6)に直接進んでください。

単独で呼び出された場合(qa-progress.json がない場合):

  • 通常どおりステップ 3~4b を実行し、SPEC.md、PR の差分、または機能の説明からテスト計画を導き出します。

これにより、/qa を単独でも利用できるようにしながら、/ship の一部として実行される場合は /qa-plan が計画を担当できます。

ステップ 3:コンテキストの収集 — 何をテストしますか?

利用可能な入力から、テスト対象を特定します。以下の情報源を順に確認し、テストシナリオを導き出すのに十分な情報が得られた最初のものを使用してください。

入力使用方法
SPEC.md のパスが指定されている読み込みます。受け入れ条件、ユーザージャーニー、障害モード、エッジケース、NFR を抽出します。これを主な情報源とします。
PR 番号が指定されているgh pr diff <number> と gh pr view <number> を実行します。変更点と、ユーザー向けのどの動作に影響するかを導き出します。
機能の説明が指定されているそのまま使用します。コードベース(Glob、Grep、Read)を調べて、何が構築され、ユーザーがどのように操作するかを理解します。
「変更箇所をテスト」(または入力なし)git diff main...HEAD --stat を実行して、変更されたファイルを確認します。変更されたファイルを読み込みます。機能の範囲とユーザーへの影響を推測します。

サーフェスのマッピング(単独実行モードのみ): 単独で実行する場合(/qa-plan による qa-progress.json がない場合)は、シナリオを導き出す前に /worldmodel スキルを読み込み、サーフェス、ペルソナ、見過ごされがちな影響をマッピングします。/ship から実行する場合は、qa-plan がすでにこれを行っており、その出力は qa-progress.json のシナリオに組み込まれています。

このステップの出力: 構築されたもの、それが関わるサーフェス、影響を受けるユーザー、ユーザーがそれをどのように操作するかについてのメンタルモデル。

ステップ 4:テスト計画を立てる

ステップ 3 で収集したコンテキストから、ユーザーが実際に体験する内容を検証できる具体的なシナリオを特定します。候補となるシナリオごとに、カバレッジの現実性を確認してください。

「このユーザーの成果は、実際の依存関係を使ったテストですでに証明されていますか?」 既存のテストを検索します。テストが存在しても、サービス境界をモックしている場合(jest.mock、MSW、nock、スタブのプロバイダー、偽の実装)は該当しません。そのシナリオは対象に残します。シナリオを除外できるのは、実際の依存関係を使った統合テストまたは E2E テストで、ユーザーの成果全体がすでに証明されている場合だけです。

QA 計画に含めるシナリオ(積極的に、以下をすべて含めてください):

カテゴリ検証内容例
視覚的な正確性レイアウト、間隔、配置、レンダリング、レスポンシブ対応「新しい設定ページは、モバイルのビューポートで正しく表示されますか?」
エンドツーエンドの UX フロー体験が重要となる複数ステップの操作「ユーザーはプロジェクトを作成し、エージェントを設定して、会話をエンドツーエンドで実行できますか?」
主観的な使いやすさフローは分かりやすいですか? ラベルは明確ですか? エラーメッセージは役に立ちますか?「認証に失敗したとき、エラーメッセージは次に何をすべきかユーザーに伝えますか?」
実際の統合動作モックではなく、実際のサービスやデータを使ったときの動作「イベントが発生したとき、Webhook は実際に呼び出されますか?」
エラー状態問題が起きたときにユーザーに表示される内容「API が 500 を返したとき、どうなりますか? UI には役に立つエラーが表示されますか、それとも空白のページになりますか?」
エッジケース形式化が現実的でない境界条件「項目が 0 件の場合はどうなりますか? 10,000 件の場合は? 名前に特殊文字が含まれる場合は?」
障害モード復旧、機能低下時の動作、部分的な障害「リクエストの途中でデータベース接続が切れた場合、システムは適切に復旧しますか?」
システム間の連携複数のサービスやツールにまたがるシナリオ「CLI は API と正しく通信し、その API は UI を正しく更新しますか?」

各シナリオを個別のテストケースとして記述します。

  1. ユーザーが体験すること(ユーザーの視点から見た成果)
  2. 実施すること(成果を検証するための操作)
  3. 合格の条件(観察可能な動作に基づく期待される結果)

実行の進捗を追跡できるよう、これらをタスクリストの項目として作成します。

ステップ 4b:QA 計画を qa-progress.json に書き込む

tmp/ship/ が存在する場合は、計画したすべてのシナリオを tmp/ship/qa-progress.json に書き込みます。このファイルは QA 結果の構造化された唯一の情報源です。下流のコンシューマーは、このファイルを PR 本文に表示します。

すべてのシナリオを planned ステータスで作成します:

{
  "specPath": "specs/feature-name/SPEC.md",
  "prNumber": 1234,
  "scenarios": [
    {
      "id": "QA-001",
      "category": "visual",
      "name": "settings page renders at mobile viewport",
      "userOutcome": "User on a mobile device sees the settings page with correct layout and readable text",
      "verifies": "layout, spacing, and alignment are correct at 375px width",
      "tracesTo": "US-002",
      "status": "planned",
      "verifiedVia": null,
      "notes": "",
      "evidence": []
    }
  ]
}

フィールドの定義:

フィールド必須説明
specPathはいこの QA 計画の導出元である SPEC.md のパスです。仕様がない場合は null です。
prNumberはい結果の対象となる PR 番号です。PR がまだ存在しない場合は null です。
scenarios[]はいテストシナリオの配列です。
scenarios[].idはい連番の ID:QA-001、QA-002 などです。
scenarios[].categoryはい上記のシナリオカテゴリの表にある任意のカテゴリです(例:visual、ux-flow、error-state、edge-case、integration、failure-mode、cross-system、usability)。
scenarios[].nameはいシナリオの短い名前です。
scenarios[].userOutcomeはい正常に動作した場合にエンドユーザーが実際に体験することです。ユーザーの視点で記述します。
scenarios[].verifiesはいテストで確認する内容です。操作と期待される結果を組み合わせて記述します。
scenarios[].tracesToいいえ対応関係が明確な場合は、spec.json のユーザーストーリー ID(例:US-003)を指定します。関連性が曖昧な場合や多対多の場合は省略します。
scenarios[].statusはい次のいずれかです:planned、validated、failed、blocked。
scenarios[].notesはいplanned の場合は空文字列です。ステータスの変更時に入力します。下記の「ステータス値」の表を参照してください。
scenarios[].verifiedVia実行時ステップ 6 の検証レベルです:browser、api、shell のいずれかです。validated/failed のシナリオでは必須です。planned の場合は null です。複数のレベルを使用した場合は、最も高いレベルを記録します。
scenarios[].evidence実行時証拠項目の多態配列です。すべての validated または failed シナリオには、少なくとも 1 つの項目が必要です。各項目には type 識別子があります。ブラウザー録画には {type: "video", url: "..."}、画面キャプチャには {type: "screenshot", url: "..."}、構造化された検証チェックには {type: "assertion", check: "...", expected: "...", actual: "...", pass: true/false}、シェルコマンドの証拠には {type: "command", cmd: "...", stdout: "...", expected: "...", pass: true/false} を使用します。validated または failed のシナリオで evidence[] が空の場合は不備です。結果を監査できないことを意味します。

ステータス値:

ステータス意味notes に記入する内容
plannedシナリオは特定済みですが、まだ実行されていません空文字列
validated合格しました。バグが見つかり修正された場合は、そのバグと修正内容を記述します。問題なく合格した場合は ""、修正後に合格した場合は "found stale cache; added cache-bust on logout"
failed失敗し、解決できませんでした何が失敗し、なぜ解決できないのかを記述します:"second tab still shows authenticated state after logout"
blockedローカルで可能なすべての手段を試し、さらに /debug チャレンジサブプロセスでそのシナリオが実際にテスト不可能だと確認された後も、完全に検証できませんでした(ステップ 6 の「ブロックされたシナリオへのチャレンジ」を参照)。環境の問題、ツール不足、ローカルの代替手段がない外部サービスを必要とするシナリオが含まれます。すべての blocked シナリオは人による検証待ちの項目であり、/pr に引き継がれます。試したこと、/debug チャレンジで調査したこと、人が確認する必要がある内容を記述します:"Stripe webhook: verified handler responds correctly to simulated payload locally. Debug challenge confirmed no local Stripe emulator available. Human needs to verify real Stripe→app delivery in staging."

tmp/ship/ が存在しない場合は、このステップを省略し、PR 本文のチェックリスト(ステップ 5)またはタスクリスト項目のみを使用します。

ステップ 5:QA チェックリストを PR 本文に保存する(単独実行の場合のみ)

tmp/ship/ が存在する場合: このステップはスキップします。ステップ 4b ですでに qa-progress.json を書き込んでおり、後続の処理で PR 本文に反映されます。

tmp/ship/ が存在しない場合:

PR が存在する場合は、PR 本文の ## Verification セクションに QA チェックリストを書き込みます。必ず gh pr edit --body で更新してください。QA 結果を PR コメントとして投稿してはいけません。

  1. 現在の PR 本文を読み取ります:gh pr view <number> --json body -q '.body'
  2. ## Verification(または旧形式の ## Manual QA)セクションがすでにある場合は、その内容を更新後のチェックリストに置き換えます。
  3. そのようなセクションがない場合は、本文の末尾に追加します。
  4. 更新後の本文を書き戻します:gh pr edit <number> --body "<updated body>"

セクションの形式:

## Verification

_End-to-end verification — proving user outcomes are real._

- [ ] **<category>: <scenario name>** — <user outcome to verify>

PR が存在しない場合は、チェックリストをタスクリスト項目としてのみ保持します。

ステップ 5b:修正可能な不足点を解消する

--report-only が有効な場合は、このステップ全体をスキップします。 レポートのみのモードでは、ソースファイルを変更しません。

qa-progress.json に enrichment.gapType === "fixable_gap" のシナリオが含まれている場合(これらの status は "planned" です)、実行前に解消します。

  1. 並べ替え: 修正可能な不足点を配列順(/qa-plan のシナリオ順)に並べます。
  2. 不足点ごとに既存の修正ループを使って修正を試みます:ソースコードの不足箇所を特定 → 修正を実装 → コミット → 修正によって不足が解消されたことを検証。
  3. 修正できた場合 → シナリオの status を "planned" に設定し、実行時にテストされるようにします。
  4. 修正できなかった場合(自己制御のしきい値に達した場合、または修正が実現不可能な場合)→ status を "blocked" に設定し、試みた内容を説明するメモを追加します。
  5. **続行:**ステップ 6 で、"planned" のシナリオをすべて通常どおり実行します。

不足点の修正は、累積リスクスコアと修正上限の対象です(ステップ 7 のバグ修正と同じ自己制御が適用されます)。

qa-progress.json に enrichment.gapType === "fixable_gap" のシナリオがない場合は、このステップをスキップします。

ステップ 6:実行 — 人間と同じようにテストする

各シナリオに取り組みます。それぞれに対して、利用可能な最も強力なツールを使用します。

テストの優先事項:まず実際のユーザーを再現します。 ユーザーが実際にシステムを操作する方法を再現するツールを優先します。API 呼び出しよりブラウザー自動化を、未加工の HTTP より SDK/クライアントライブラリの呼び出しを、個別のエンドポイント確認より実際のユーザージャーニーを優先します。ユーザー向けではないシステムの部分や、より高い忠実度のツールが利用できない場合は、忠実度の低いツール(curl、データベースへの直接クエリ)に切り替えます。変更の影響を受けるものの、顧客から見えないシステムの部分については、サーバー側の可観測性(ログ、テレメトリー、データベースの状態)を使って、表面下の正しさを検証します。

/browser はステップ 2 ですでに読み込まれているはずです。 何らかの理由でまだ読み込まれていない場合は、今すぐ読み込んでください。Skill ツールは必ずスキルを読み込みます。verifiedVia フィールドには、各シナリオで実際に使用した忠実度を反映してください。UI を通じて実行していないシナリオを api の忠実度として報告してはいけません。

検証の忠実度レベル(結果を記録する際は、verifiedVia に以下の値を使用してください):

レベル方法一般的な用途
browser実際の UI を使ったユーザーフロー全体(Playwright)UI シナリオ、視覚的な正しさ、エンドツーエンドの UX
apiUI レイヤーを介さない、API/エンドポイントへの直接呼び出しバックエンドの動作、レスポンスの形式、認証フロー
shellCLI、データベースクエリ、ファイル/ログの確認状態の検証、データの整合性、プロセスの動作

各シナリオでは、実行可能な最も高いレベルをデフォルトとします。api で検証した視覚的レイアウトのシナリオと、browser で検証したものには実質的な違いがあります。レポートの利用者には、その違いを知らせる必要があります。 アドホックなスクリプトで自力で解決しましょう。 正式なテスト基盤、公開済みパッケージ、CI パイプラインを待つ必要はありません。何かを検証する必要があれば、簡単なスクリプトを書いて実行してください。使い捨ての成果物(スクリプト、フィクスチャ、テストデータ、一時的な設定など)はすべて、リポジトリのルートにある tmp/ ディレクトリ(通常は Git の追跡対象外)に置いてください。これらは一時的なものなので、本番品質である必要はありません。具体的なパターンは次のとおりです。

  • 簡単な検証スクリプト: モジュールをインポートして関数を呼び出し、出力をアサートするスクリプトを書いて実行します。完了したら削除するか、tmp/ に残してください。
  • ローカルパッケージ参照: パッケージの公開を待つ代わりに、file:../path、ワークスペースリンク、または link: を使います。ディスク上にあるコードをテストしてください。
  • 利用者の視点でのスクリプト: 下流の利用者と同じ方法でパッケージをインポート/要求するスクリプトを書きます。エクスポート、型、公開 API の範囲、動作が期待どおりであることを確認してください。
  • REPL での検証: REPL(node、python など)を使って対話的に動作を調べ、エッジケースをテストしたり、シナリオ全体を実行する前に想定を確認したりします。
  • 一時的なテストサーバーやフィクスチャ: 最小限のサーバーを起動したり、テストデータベースにデータを投入したり、テスト用のフィクスチャファイルを tmp/ に作成したりして、テストに使います。完了したら後片付けをしてください。
  • 環境の変化: 異なる環境変数、機能フラグ、設定値でテストし、機能が設定を正しく処理することを確認します。特に、設定が欠落または無効な場合を確認してください。

ブラウザー自動化を使う場合:

  • 機能に移動し、操作して、フォームに入力し、送信します。
  • 個々のページを確認するだけでなく、ユーザーの一連の操作を最初から最後まで実行します。
  • 視覚的なレイアウトを確認します。見た目は適切ですか?位置ずれ、切り抜き、欠落はありませんか?
  • エラー状態をテストします。無効なデータを送信したり、接続を切断したり、エッジケースを発生させたりします。
  • 機能がレスポンシブな場合は、異なるビューポートサイズでもテストします。
  • キーボード操作とフォーカス管理をテストします。

動画の記録(すべてのブラウザーシナリオでデフォルト): ブラウザー自動化を使うすべてのシナリオで、シナリオを開始する前に /browser の helpers.createVideoContext(browser, { outputDir: '/tmp/playwright-videos' }) を使って動画コンテキストを作成してください。これにより、事前の計画なしにすべてが自動で記録されます。シナリオの完了後(成功・失敗を問わず)、次の手順を実行します。

  1. ページを閉じて録画を確定します:const videoPath = await page.video().path(); await page.close();
  2. Bunny Stream にアップロードします:/media-upload スキルを読み込み、uploadToBunnyStream(videoPath, { name: '<scenario-id>-<scenario-name>' }) を呼び出します。セットアップ:./secrets/setup.sh --skill media-upload。
  3. qa-progress.json のシナリオの evidence[] フィールドに URL を記録します。

動画の証拠は、成功したシナリオにも失敗したシナリオにも役立ちます。QA でテストした内容をレビュー担当者に正確に示し、失敗のデバッグにも役立ちます。 ブラウザーの検査を行う場合(ブラウザー自動化と併用してください。自動化の代わりにはなりません):

  • コンソールの監視(必須 — すべてのフローで実施してください): ページに移動する前にキャプチャを開始し(startConsoleCapture)、主要なアクションの後にエラーを確認します(getConsoleErrors)。ページが正しく表示されていても、JS エラーが発生している場合は正しく動作していません。問題を診断する際は、特定のパターンでログを絞り込んでください(文字列/正規表現/関数フィルターを指定したgetConsoleLogs)。
  • ネットワークリクエストの検証: ページに移動する前に、URL フィルター('/api/'など)を指定してキャプチャを開始します(startNetworkCapture)。フローの後、失敗したリクエストを確認します(getFailedRequests — 4xx、5xx、および接続エラーを検出します)。正しいエンドポイントが呼び出されていること、ステータスコードが想定どおりであること、サイレントな失敗がないことを確認します。特定の API 呼び出しには、waitForApiResponseを使ってステータスを検証し、レスポンス本文/JSON を確認します。
  • ブラウザー状態の検証: 変更を加えた後、状態が正しく保存されたことを確認します。getLocalStorage、getSessionStorage、getCookiesを確認し、UI の操作によって想定されたデータが実際に書き込まれたことを確かめます。クリーンな状態でテストするには、テストシナリオの間にclearAllStorageを使います。
  • ページ内アサーション: ページ上で JavaScript を実行し、DOM の状態、計算済みスタイル、データ属性、または画面上では見えないアプリケーションの状態を検証します。レイアウトの検証(表示状態、ビューポート内にあるかどうか、計算済みスタイル)にはgetElementBoundsを使います。目視検査だけでは正しさを確認できない場合に使用します(例:「この要素は CSS で実際に非表示になっているのか、それとも画面外にスクロールしているだけなのか?」)。
  • レンダリングされたテキストの検証: ページのテキストを抽出し、特に動的なコンテンツ、補間された値、条件付きテキストが表示されていることを確認します。 ブラウザベースの品質シグナルを利用する場合(/browser プリミティブが利用可能なとき):
  • アクセシビリティ監査: 主要な各ページ/ビューで runAccessibilityAudit を実行します。WCAG 違反を影響度別(critical > serious > moderate)に報告します。checkFocusOrder でキーボードのフォーカス順をテストし、特に新規または変更された UI で、タブによる移動が論理的な読み取り順に沿っていることを確認します。
  • パフォーマンスのベースライン: ページの読み込み後に capturePerformanceMetrics を実行し、明らかな性能低下がないか、TTFB、FCP、LCP、CLS を確認します。正式なパフォーマンステストを行うのではなく、「このページの読み込みに8秒かかる」「ヒーロー画像の読み込み時にレイアウトがずれる」といった問題を検出します。
  • 動画の録画: 複雑な複数ステップのフローでは、createVideoContext で録画します。QA 結果に証拠として録画を添付します。タイミング、アニメーション、状態遷移など、スクリーンショットでは捉えにくい要素を含むフローで特に役立ちます。
  • レスポンシブ表示の検証: captureResponsiveScreenshots を実行して、標準のブレークポイント(モバイル/タブレット/デスクトップ/ワイド)を一通り確認します。各ビューポートのスクリーンショットを比較し、レイアウトの崩れ、切り抜き、要素の欠落がないか確認します。
  • 劣化した環境条件: simulateSlowNetwork(例:500ms のレイテンシ)と blockResources(画像やフォントをブロック)でテストし、適切に機能が縮退することを確認します。機能にオフライン処理がある場合は、simulateOffline もテストします。これらのヘルパーは route.fallback() を介した page.route() のモックと組み合わせて使用できます。
  • ダイアログの処理: 遷移前に handleDialogs を使用して、アラート、確認、プロンプトを自動的に承認または閉じます。その後、captured.dialogs を調べ、適切なダイアログが表示されたことを確認します。テストフロー中の操作を妨げる Cookie バナーや同意ポップアップを自動的に閉じるには、dismissOverlays を使用します。
  • ページ構造の把握: getPageStructure を使用すると、推奨セレクター付きのアクセシビリティツリーを取得できます。ARIA ロールや要素の見つけやすさの確認、見慣れないページでのセレクターの作成に役立ちます。操作可能な要素に絞り込むには、{ interactiveOnly: true } を渡します。
  • トレース: startTracing/stopTracing を使用して、失敗したフローの Playwright トレース(.zip)全体を取得します。DOM スナップショット、スクリーンショット、ネットワーク、コンソールのアクティビティが含まれます。npx playwright show-trace で表示できます。
  • PDF とダウンロードの検証: generatePdf を使用して、PDF エクスポート機能を検証します。ファイルのダウンロードフローをテストするには waitForDownload を使用します。ダウンロード操作を実行し、確認用にファイルを保存します。

macOS デスクトップ自動化を利用する場合:

  • 関連する場合は、ファイルダイアログ、クリップボード、複数アプリにまたがるワークフローなど、OS レベルの操作をテストします。
  • 視覚的な検証用にスクリーンショットを撮影します。

シェル/CLI を利用する場合(常に利用可能):

  • curl で API エンドポイントを呼び出します。ステータスコード、レスポンスの構造、エラーレスポンスを検証します。
  • API コントラクトの検証: コードベースの型定義またはスキーマを読み、実際の API レスポンスが宣言された型と一致することを確認します。フィールドと型が正しいこと、余分なプロパティや欠落したプロパティがないことを検証します。これにより、型と実行時の動作の不整合を検出できます。
  • 有効な入力と無効な入力で CLI コマンドをテストします。
  • ファイルの出力、ログ、プロセスの動作を検証します。
  • 空の文字列、非常に長い文字列、特殊文字、Unicode などの境界値でテストします。
  • 関連する場合は、並行処理をテストします。2つのリクエストが競合する可能性はありますか?

状態変更の検証(変更、遷移、UI の状態遷移の後):

  • 操作の前に、何が変わるべきか、つまり操作後に変化するはずの具体的な状態を記録します。
  • UI または API を使って操作を実行します。
  • 操作後に、実際に状態が変わったことを検証します。正しい値が書き込まれていること、正しいページ/ビューが読み込まれていること、関連データに意図しない副作用がないこと、タイムスタンプ/監査フィールドが更新されていることを確認します。
  • 該当する場合は、存在しないことも確認します。 削除後はリストから項目がなくなっていること、モーダルを閉じた後はページ構造に表示されなくなっていること、ログアウト後は認証が必要なコンテンツにアクセスできないことを確認します。
  • こうした検証により、成功したように見える操作(200 OK、UI の更新)でも、誤った値を書き込む、フィールドを更新し忘れる、古い状態が残る、本来削除すべきものを削除できないといった問題を検出できます。 サーバー側のオブザーバビリティ(利用できる場合): 変更の影響は、ユーザーから見える範囲を超えてシステムの広い範囲に及びます。ユーザー向けのフローを実行した後、ブラウザーや API レスポンスには現れない問題がないか、サーバー側のシグナルを確認してください。
  • アプリケーション/サーバーログ: テストフローの実行中に、サーバーログでエラー、警告、予期しない動作を確認してください。ブラウザーテストや API テストを実行しながら、ログを追跡してください。
  • テレメトリ/OpenTelemetry: システムがテレメトリや OTEL トレースを出力する場合は、テストフローの実行後に確認してください。期待される操作のトレースが出力されていること、スパンに正しい属性が設定されていること、成功が期待される箇所にエラースパンがないことを検証してください。
  • データベースの状態: データベースに直接クエリを実行して、変更が正しい値を書き込んだことを確認してください。API や UI が成功を報告していても、実際の永続化結果が異なる可能性がある場合は特に重要です。
  • バックグラウンドジョブ/キュー: 機能が非同期処理(キュー、cron、ウェブフック)を起動する場合は、ジョブがキューに登録され、正しく完了したことを確認してください。

一般的なテストの進め方:

  1. クリーンな状態(キャッシュデータなし、新しいセッション)から始めます。
  2. まず、仕様どおりのエンドツーエンドの正常系を一通り実行します。
  3. 次に、特定したすべての失敗パターンを試します。
  4. 続いて、境界条件、予期しない入力、同時アクセスで負荷をかけます。
  5. 最後に、見た目の正しさ、使いやすさ、そして「しっくりくるか」を確認します。

アサーションの深さ — 状態の変化を観察するだけでなく、証明する:

ページが読み込まれたことや、操作が完了したことを確認するだけでは不十分です。状態の変化を伴う各検証(変更、ナビゲーション、フォーム送信、モーダルの開閉)で、次の原則を適用してください。

  • 各アサーションにつき、独立したシグナルを2つ確認します。 状態の変化を確認するため、少なくとも2つの独立したシグナルをチェックしてください。例:URL が変化し、新しいコンテンツが表示された。項目がリストに追加され、件数が更新された。フォームが送信され、テスト用受信トレイに確認メールが届いた。シグナルが1つだけだと偶然に左右されやすくなります。2つあれば、誤検知の可能性を大幅に減らせます。
  • 目視確認より、構造化された証拠を優先します。 ブラウザー自動化を使用する場合は、スクリーンショットを目視で確認するより、Playwright の呼び出しから構造化された証拠を返す方法を優先してください。
    // Good — structured, auditable, machine-parseable
    return { url: page.url(), title: await page.title(), itemCount: await page.locator('.item').count(), visible: await page.locator('.success-toast').isVisible() };
    
    // Weak for assertions — requires vision processing, not auditable
    // (Screenshots are still valuable as PR evidence in Step 6b — this is about pass/fail verification)
    await page.screenshot({ path: '/tmp/check.png' });
    
    構造化された証拠は、より速く(視覚処理が不要)、より低コストで(画像トークンが不要)、qa-progress.json のメモに監査可能な結果を残せます。

これらの原則は状態変化の検証に適用されます。「ページが読み込まれた」「要素が存在する」といった単純なチェックには適用されません。

ブラウザーシナリオの自己修復(ヒーラーループ)

ブラウザースクリプトが失敗した場合は、対処する前に失敗の種類を分類します。

失敗の種類シグナル対処
セレクターのずれ要素の待機中に発生した TimeoutError、要素が見つからない、誤った要素をクリックしたgetPageStructure() で再調査し、セレクターを修正して再試行します(最大 2 回)
タイミングの問題競合状態、要素がまだ表示されていない、ネットワークが安定していないwaitForSelector / waitForLoadState('domcontentloaded') を追加して再試行します
アプリのバグ要素は存在するが内容が誤っている、ステータスコードが誤っている、コンソールエラー、予期しないリダイレクト再試行しないでください。証拠を添えて失敗を報告します
環境の問題接続拒否、DNS エラー、認証の期限切れfailed ではなく blocked として報告します

ヒーラーループ(最大 2 回の反復):

  1. スクリプトが失敗したら、エラーメッセージを読みます
  2. セレクター/タイミングの問題、アプリのバグ、環境の問題のいずれかに分類します
  3. セレクター/タイミングの問題の場合: a. 現在のページ状態で getPageStructure(page, { interactiveOnly: true }) を実行します b. 観測された要素と、スクリプトが想定していた要素を比較します c. セレクターを修正して、失敗した部分のスクリプトを書き直します d. スクリプトを再実行します e. 同じ種類のエラーで再度失敗した場合は、「Healer: 2 回再試行しましたが、セレクター/タイミングの問題が解消しません。アプリのバグの可能性があります」という注記を添えて failed として報告します
  4. アプリのバグの場合:証拠(コンソールエラー、ネットワーク障害、スクリーンショット)を添えて、直ちに報告します。再試行しないでください
  5. 環境の問題の場合:具体的なエラーを添えて blocked として報告します

重要な原則: アプリのバグを再試行すると時間を浪費し、本当の問題を見えにくくします。再試行するのは テストスクリプト が誤っている場合だけであり、アプリ が誤っている場合は再試行しないでください。

証拠に基づく再試行: 再試行するたびに、新たな証拠に基づく理由が必要です。たとえば、異なる要素が示された新しいページ構造、修正したセレクター、変化したページ状態などです。異なる結果を期待して、同じ失敗した操作を変更せずに再実行してはいけません。

ステップ 6b:スクリーンショットの証拠

テスト後、コード変更の影響を受けた各 UI 画面のスクリーンショットを撮影します。必要に応じてディレクトリ(mkdir -p tmp/ship/screenshots)を作成し、Playwright の page.screenshot({ path: ..., fullPage: true }) を使って tmp/ship/screenshots/<descriptive-slug>.png に保存します。

以前にスクリーンショットを撮影した画面が変わるバグを修正した場合は、同じファイルを上書きしてスクリーンショットを撮り直します。スクリーンショットには、中間状態ではなく、コードの最終状態を反映させる必要があります。

これらのスクリーンショットは、テストした状態を示す証拠です。開発者が PR を作成する際、/pr によって PR の本文に含められます。

/debug サブプロセスでブロックされたシナリオを再検討する

シナリオを blocked として確定する前に、新たな視点からその判断を検証してください。ネストした Claude Code インスタンスを(/nest-claude サブプロセスのパターンを使って)起動し、--headless を指定して /debug を読み込ませ、そのシナリオが本当にテスト不可能かを独立して調査します。

ハードコードされたショートサーキット — /debug でのチャレンジより先に実行してください

ブロック理由の候補に「browser」、「Playwright」、「headless」、「needs dev server」、「requires UI」、「unrunnable in headless」のいずれかが含まれる場合、そのシナリオはブロック対象ではありません。これらは /browser の主なユースケースと、開発サーバーを起動する手順を示しています。blocked と判断する前に、次のいずれかを実行してください。

  1. /browser が読み込まれていない場合: 今すぐ読み込み、シナリオを再実行してください。
  2. 開発サーバーが起動していない場合: (npm run dev、または package.json の scripts/CLAUDE.md/Makefile に記載された同等のコマンドで) 起動し、シナリオを再実行してください。
  3. 両方を確認した後に限り(/browser が読み込まれ、開発サーバーが応答している状態)、それでもシナリオを検証できない場合は、以下の /debug チャレンジに進んでください。

blocked ステータスが本当に妥当なシナリオ:認証の強固な壁(hCaptcha、SMS MFA、WebAuthn)、ローカルの代替手段もサンドボックスモードもない外部サービス、または /browser が正常に読み込まれているにもかかわらず、この環境で Chromium を起動できない実行時エラーです。該当するケースは限られています。ブロックする前に、そのいずれかに当てはまることを確認してください。

チャレンジを行うタイミング: 上記のショートサーキット後に blocked と判断されるすべてのシナリオです。例外はありません。コスト(シナリオあたり約2~5分)は、ブロック対象となるシナリオの数に比例します。その数は少ないはずです。誤ってブロックされたシナリオは、後で人が手動で検証することになり、はるかに大きなコストがかかります。

サブプロセスの手順:

  1. ネストされた Claude サブプロセスを起動します。
  2. サブプロセスで --headless を指定して /debug を読み込みます。
  3. 次の情報を渡します。
    • シナリオ(id、name、userOutcome、given/when/then)
    • シナリオがブロックされていると考える理由
    • プロジェクトのルートパス
  4. サブプロセスは独立して調査します。これまでの想定に影響されず、最初の原則から調査を開始します。
    • シナリオがブロックされている理由について、あらゆる想定に異議を唱える
    • プロジェクトのテストフレームワークの機能(spy/mock、統合テストの設定)、利用可能な API キー(現在の環境、.env ファイル)、およびこのプロジェクトとエコシステムに関連するその他の機能を調査する
    • テストの作成と実行を試みるか、別の検証方法を探す
    • テストを妨げるバグが見つかった場合は修正する
  5. サブプロセスの結果を解析します。
    • シナリオを検証する方法が見つかった場合:debug 調査で得た証拠を添えて、シナリオを validated に更新します。調査による解決を記録するため、notes に "resolvedBy": "debug-challenge" を設定します。
    • シナリオが実際にブロックされていると確認された場合:調査の分析を notes の証拠として添えて、blocked のままにします。調査の記録によって、あらゆる手段を尽くしたことが示されます。後続の利用者は、単にブロックされているという事実だけでなく、なぜブロックされているのかを確認できます。

インラインで調査するのではなく、サブプロセスを使う理由: /qa エージェントは、シナリオがブロックされている理由について、すでに先入観を持っています。新しいコンテキスト(会話履歴のないクリーンな子プロセス)を使うことで、調査を最初から始める必要が生じます。/debug の体系的な方法論(トリアージ → 再現 → 調査 → 分類 → 報告)により、先入観を裏付けるだけではなく、徹底的な調査を行えます。


ステップ 7:結果を記録する

tmp/ship/ が存在する場合: 各シナリオ(またはバッチ)の後に、qa-progress.json でシナリオの status、verifiedVia、notes、evidence を更新します。verifiedVia には、シナリオを実際に実行した方法を示す、ステップ 6 の忠実度レベル(browser、api、shell)を設定します。複数のレベルを使用した場合(例:ブラウザーのフローとデータベースの状態確認)は、最も高いレベルを記録します。PR の本文は変更しないでください。後続の利用者が内容を生成します。

証拠の記録(検証済み/失敗したすべてのシナリオで必須): 何を確認し、何が観測されたかを示す、少なくとも1つの構造化された証拠項目を evidence[] に入力します。証拠の種類は検証方法に合わせてください。

  • ブラウザーのシナリオ: Bunny Stream のアップロードによる {type: "video", url: "..."}、および/または CDN またはローカルパスによる {type: "screenshot", url: "..."}
  • API/シェルのシナリオ: {type: "assertion", check: "file_exists", expected: "plugins/shared/skills/audit/SKILL.md", actual: "exists", pass: true} または {type: "command", cmd: "readlink plugins/eng/skills/audit", stdout: "../../shared/skills/audit", expected: "../../shared/skills/audit", pass: true}
  • 複合シナリオ: 複数の証拠項目を含めます(例:アサーションとスクリーンショット)

証拠があれば、結果を監査できます。後続のエージェントや人間が、再実行せずに主張を検証できます。構造化されたアサーションは(チェックをすでに実行しているため)低コストで作成でき、機械で解析できます。validated または failed のシナリオで evidence[] が空の場合は不備です。

tmp/ship/ が存在しない場合: Step 5 と同じ読み取り → 変更 → 書き込みの手順で、PR 本文の ## Verification セクションを直接更新します。チェックリスト項目に忠実度レベル(例:[browser]、[api])を含めてください。

バグを見つけた場合:

--report-only が有効な場合: status: "failed" とし、バグの詳細なメモ(症状、推定される根本原因、影響箇所、再現手順)を添えて、qa-progress.json に調査結果を記録します。ただし、ソースファイルの編集、/debug の読み込み、修正ループへの移行は行わないでください。予定されたシナリオ以外でバグを見つけた場合は、次の連番 ID を使って scenarios[] に新しいシナリオを追加し、説明的なメモを添えて failed にします。

--report-only が有効でない場合:

まず、根本原因がわかるのか、それとも症状しかわからないのかを判断します。

  • 根本原因が明らか(コード上で変数の誤り、クラスの欠落、オフバイワンが確認できる)— 直接修正します。検証し、記録します。

    回帰テスト:

    • 次の条件を満たす場合は作成します。 バグが既存テストの近くにあるアプリケーションコードにあり、小さなテストで修正前は確実に失敗し、修正後は成功すると見込める場合。まず /tdd を読み込み、テスト設計ルール(バグ修正では失敗するテストを先にコミットすること、境界でモックすること、モックの循環論法を防ぐこと、不安定さに対処すること)を確認してください。
    • 次の場合は省略します(シナリオのメモにカバレッジの不足を記録します)。 バグが UI の見た目だけに関するもの(QA シナリオ自体が回帰チェックになります)、影響箇所に既存テストの前例がない、または根本原因がサードパーティーの依存関係、設定ファイル、ビルドパイプラインにある場合。
  • 根本原因が不明(予期しない挙動で、症状から原因がわからない)— 修正に着手する前に /debug スキルを読み込み、根本原因を体系的に調査します。QA がヘッドレスモードで実行中の場合は、アクションごとの権限確認なしで自由に反復できるよう、/debug に --headless を渡してください。/debug は構造化された調査結果(根本原因、推奨される修正、影響範囲)を返します。その調査結果に基づいて修正を適用し、QA を再開します。

バグを修正したら、その内容を記録します。シナリオの status を validated に更新し、バグの説明と修正内容を notes に記載します(例:"古いキャッシュを確認。ログアウト時にキャッシュを無効化する処理を追加")。予定されたシナリオ以外(テスト間の移動中や探索的な確認中)にバグを見つけて修正した場合は、次の連番 ID を使って scenarios[] に新しいシナリオを追加し、発見した内容と修正内容を記述して、修正内容を notes に記載したうえで validated にします。

修正ループの自己調整(累積リスクスコア):

--report-only が有効な場合、このセクション全体を省略します。 修正がなければ、リスクの追跡も不要です。

QA セッションで行ったすべての修正(バグ修正および Step 5b で修正可能な不足箇所の修正)の累積リスクスコアを追跡します。リスク状態は qa-progress.json に保持します — 各修正の前に読み取り、後に書き込みます。

{
  "fixLoopState": {
    "riskScore": 15,
    "fixCount": 12,
    "reverts": 0
  }
}

リスクの加算:

Start at 0%
Each revert:                +15%  (strongest signal — you undid your own work)
Each fix touching >3 files: +5%   (blast radius growing)
Touching unrelated files:   +10%  (scope creep)
After fix 15:               +1% per additional fix (fatigue ramp)

Threshold: STOP fixing at ≥30%
Hard cap: 50 fixes per QA session
  • 各修正の前に、qa-progress.json から fixLoopState を読み込みます。各修正の後に、riskScore と fixCount を更新して書き戻します。
  • しきい値に達したら、修正を停止します。qa-progress.json に残りの問題を記録します(ステータスを "failed" に設定し、リスクスコアにより修正を打ち切ったことを説明するメモを記載します)。
  • 回帰テストのコミットはこのヒューリスティックの対象外です。修正のテストを作成しても、リスクスコアは増加しません。
  • 修正上限に達した後も、残りのテストシナリオの実行(読み取り専用の確認)を続けます。問題を発見して記録することはできますが、修正はできません。

テストスイートの不足箇所の発見:

--report-only が有効な場合は、このセクションをスキップしてください。 report-only モードではテストを作成せず、代わりにシナリオの notes に不足箇所を記録します(例:"session invalidation のユニットテストが不足 — カバレッジの追加を推奨")。

実行中に、正式なテストカバレッジが必要なのに不足している動作を見つけることがあります。ユニットテストのないエッジケース、インテグレーションテストのない動作経路、テストされていない統合ポイントなどです。原則として、不足箇所はカバレッジに関する推奨事項としてシナリオの notes に記録します(例:"session invalidation のユニットテストが不足 — カバレッジの追加を推奨")。QA の主な役割はシナリオの検証であり、カバレッジの追求ではありません。不足箇所を明らかにすることには価値があり、対応がスコープ外であっても、記録された不足箇所はフォローアップ項目として /pr に引き継がれます。

例外 — 次のすべてに当てはまる場合に限り、テストを作成します。

  • 不足箇所が、直前に修正したバグに直接関連している(テストを修正とセットにする)。
  • 既存の近接するテストと同じレイヤーでテストを作成できる(新たなテスト基盤は不要)。
  • 作成にかかる時間が 5 分未満である。

例外に基づいてテストを作成する場合は、テスト設計のルール(レイヤーの選択、モックの方針、不安定なテストへの対処、モックのトートロジーの防止、テスト成果物の保護、仕様に基づいたテスト作成)を確認するために /tdd を読み込みます。バグ修正のメモと併せて、そのテストをシナリオの notes に記録します(例:"session invalidation のユニットテストも作成 — 既存のカバレッジなし")。

ステップ 8:報告と後片付け

tmp/ship/ が存在する場合: 報告の直前に、最後の作業として次を行います。

  1. 現在の HEAD コミットハッシュ(git rev-parse HEAD)を使って、qa-progress.json に qaCompletedAtCommit を書き込みます。これは、古さを検出するための QA と QA 後の変更の境界を示します。

  2. executionSummary を計算し、planMetadata に書き込みます。

    "executionSummary": {
      "validated": 12,
      "failed": 1,
      "blocked": 2,
      "planned": 0
    }
    

    ステータス別にシナリオ数を数えます。これにより、後続のすべてのコンシューマーがシナリオ配列全体を走査せずに済みます。

  3. qa-progress.json のトップレベルに verdict を計算して書き込みます。判定の重大度は、プランナーが割り当てた優先度ラベルではなく、シナリオのプロパティ(category、source)から導きます。失敗がある場合、クリーンな "go" になることはありません。

    • source: "journey" のシナリオが failed または blocked の場合 → "no-go"(複合的なユーザーパスが機能していない — 統合部分に問題があります)
    • コアユーザージャーニーに関連する category: "ux-flow" のシナリオが failed または blocked の場合 → "no-go"(正常なユーザーパスが機能していません)
    • データ損失やセキュリティ上重要なパスに関わるシナリオが failed または blocked の場合 → "no-go"(安全性に関わる重大な失敗です)
    • その他のシナリオが failed または blocked の場合 → "conditional"(機能は動作しますが、文書化された問題があります — 続行するかどうかは人間が判断します)
    • すべてが validated の場合 → "go"

    判定の根拠となった入力(判定の要因となったシナリオとその理由)と一緒に判定を書き込み、コンシューマーが事前計算された判定を利用し、その計算を検証できるようにします。

    JSON ファイルが報告書になります。後続のコンシューマーが PR 本文にこれを表示します。呼び出し元に完了を報告します。

tmp/ship/ が存在せず、PR がある場合: PR 本文の ## Verification セクションが報告書になります。すべての結果を反映して最新の状態にします。別途 PR コメントを追加しないでください。

PR がない場合: 次の内容をユーザーに直接報告します。

  • テストしたシナリオの合計数、成功数、失敗数、ブロックされた数
  • 発見して修正したバグ(それぞれの簡潔な説明を添えます)
  • 未実施項目 — ツールの制限や環境上の制約によりテストできなかった内容
  • 判断 — この機能は人間によるレビューに進める状態か、率直に評価します

このスキルの役割は、対応できる問題を修正し、発見した内容を記録し、状況を明確にして引き継ぐことです。解決できない問題や未実施項目は記録し、黙って見過ごしません。ただし、それらによって作業の進行を妨げることはありません。残りの項目への対応は呼び出し元が判断します。

後片付け(必須): 報告後、ステップ 2 で起動したものをすべて終了します。開発サーバーを停止し、Docker コンテナを停止し(docker compose down -v)、フィクスチャデータを削除し、tmp/ 内の一時ファイルを削除します。起動した順序の逆順で後片付けを行います。必要な作業の全リストは bootstrapResult.teardownRequired を確認してください。環境を元の状態に戻します。


QA の実行範囲

唯一の厳格な境界は、クラウド/外部システムに変更を加えないことです。 それ以外は、ローカルであればすべて実行できます。検証不能と判断する前に、ローカルで可能な選択肢をすべて試してください。

実行可能 — 以下をすべて試してください(ローカルで利用できる手段をすべて使います):

  • ブラウザー自動化(/browser 経由の Playwright)— 移動、クリック、フォーム入力、コンソール/ネットワークの調査、動画の記録、アクセシビリティの監査、レスポンシブレイアウトのテスト
  • Docker コンテナー — docker compose up -d を使って、データベース、キャッシュ、キュー、モックサービスを起動します。完了したら停止してください。
  • ローカル開発サーバー — 依存関係をインストールし、サーバーを起動し、データベースにシードデータを投入し、ワーカーを起動します
  • シェルスクリプト、REPL セッション、利用者の視点からのインポートスクリプト
  • ローカルで実行中のエンドポイントへの API 呼び出し(curl localhost:...)
  • tmp/ 内での臨時検証スクリプト — 作成し、実行し、削除します
  • 一時テストサーバー、フィクスチャーファイル、シードデータ
  • 環境変数の操作、フィーチャーフラグの切り替え
  • プロジェクト独自のテストスイート、リンター、型チェッカーの実行
  • 変更の正しさを検証するためのデータベースクエリ
  • テストフロー中のログ/テレメトリーの調査
  • 外部サービスの応答をローカルでシミュレート(MSW、nock、VCR、HTTP のインターセプト)
  • localhost にシミュレートしたペイロードを送信して、Webhook ハンドラーをテスト
  • アウトバウンド HTTP 呼び出しが正しく構成されていることを検証(送信せずにインターセプトしてアサート)

実行不可(厳格な境界):

  • 本番環境の URL、ステージング環境、または実際のサードパーティ API へのリクエスト
  • 課金、使用量計測、またはクォータ消費を引き起こす操作
  • 実際のメール、Slack メッセージ、外部サービスへの Webhook の送信
  • 本番データベースまたは顧客データへのアクセス
  • 外部/クラウドシステムへの変更(localhost 以外への POST/PUT/DELETE)

シナリオで外部サービスが必要な場合:

  1. まずローカルの代替手段があるか確認します。Docker イメージ、ローカルエミュレーター(例:AWS 用の LocalStack、Webhook 用の Stripe CLI)、モックサーバー、またはシミュレートしたペイロードなどです。
  2. ローカルの代替手段がある場合は、それを使用します。これは実際の検証として扱われます。
  3. ローカルの代替手段がない場合は、ローカルで可能な限り検証します(例:シミュレートしたペイロードに対して Webhook ハンドラーが正しく応答することを確認します)。そのうえで、ローカルで検証した内容と、ステージング/本番環境で人が確認する必要のある内容を記載し、シナリオを status: "blocked" としてマークします。
  4. blocked のシナリオは /pr に未完了の人手による検証項目として引き継がれます。黙って除外されることはありません。

blocked は安全策であり、最初の手段ではありません。 Docker、ローカルエミュレーター、シミュレートしたペイロード、インターセプトしたリクエストをすべて試した後に限り、シナリオを blocked にしてください。シナリオの 80%をローカルで検証でき、最後の外部への引き渡しだけ人による確認が必要な場合は、検証した 80%と人が確認する必要のある 20%を記載してください。すべての blocked シナリオには、試した内容を必ず記載してください。

深度の調整

深度は qa-progress.json の計画に基づきます。そこに含まれるすべてのシナリオを実行してください。この計画は可能な限り意欲的に作成されています。すべてのシナリオを、達成可能な最高の忠実度で検証してください。

テストの範囲は、影響を受ける箇所に応じて広げます。 qa-progress.json がない状態で単独で作業する場合は、変更の範囲に基づいてテストするシナリオ数を調整してください。単一ファイルのバグ修正なら、対象を絞ったシナリオを1〜2件と回帰チェックを実施します。複数の箇所に影響する複数ファイルの機能なら、影響を受ける各箇所のシナリオに加え、エッジケースやエラーパスもテストします。固定の数を適用せず、影響を受ける箇所の数に応じて決めてください。

テスト不足の例(以下の失敗を避けてください):

  • ユーザー向けの画面がある機能について、ユニットテストだけで確信が得られたと判断する
  • テストがサービス境界をモックしているのに、シナリオは「テストでカバー済み」と主張する
  • 機能に UI があるのにブラウザーを一度も開かない。/browser は常に読み込み可能で、デフォルトでヘッドレスの Playwright を実行します
  • エラーパスのテストを省略する
  • 新しいコードと既存コードの連携をテストしない
  • 変更後のデータベースの状態を確認しない
  • docker-compose.yml が存在し、実データベースを利用できるのに Docker を起動しない
  • /browser を読み込む、開発サーバーを起動する、Docker を起動する、ローカルエミュレーターやシミュレートしたペイロード、アドホックなスクリプトを試す前に、シナリオを blocked にする

アンチパターン

  • QA をチェックボックスとして扱う。 具体的な内容がなければ、「テストしました」と言っても何の意味もありません。各シナリオには、具体的な操作と期待される結果が必要です。
  • 正常系だけをテストする。 実際のユーザーはエラー、エッジケース、予期しない状態に遭遇します。それらもテストしてください。
  • 見えない抜け漏れ。 テストできないものがあれば、明示してください。記録されていない抜け漏れは、記録された抜け漏れよりも問題です。
  • オーケストレーションのヘッドレスモードと、ブラウザーが利用できないことを混同する。 Ship の --headless フラグとコンテナー検出は、オーケストレーションの自律モードに切り替わります。ユーザーによるゲートや交渉のチェックポイントはありません。これは「環境でブラウザーを実行できない」という意味ではありません。/browser の Playwright エンジンはデフォルトでヘッドレス Chromium を実行します。これは、--headless の Ship 実行で必要なものそのものです。/browser を読み込み、シナリオを実行してください。
  • 「ブラウザーが必要」「Playwright が必要」「開発サーバーが必要」「UI が必要」「ヘッドレスでは実行不可」を理由に、シナリオを blocked にする。 これらは /browser と Step 2 のブートストラップの主要なユースケースであり、妥当なブロック理由ではありません。これらをブロック理由に書いた場合は、作業を止めてください。まだ /browser の読み込みや開発サーバーの起動を実際に試していません。まずそれを実行してから、改めて評価してください。
  • ウェブテストに Peekaboo や Claude-in-Chrome を使う。 mcp__peekaboo__* と mcp__claude-in-chrome__* ツールは、QA のウェブページテストには使いません。/browser(Playwright)を使用してください。Peekaboo は OS レベルの macOS 自動化専用です。Chrome 拡張機能は、QA 以外でユーザーの指示に基づいて行うアドホックなブラウザー作業用です。

コメント