Communitygithub.com

AI回帰テスト

AI支援開発のための回帰テスト戦略。データベース依存のないサンドボックスモードAPIテスト、自動バグチェックワークフロー、同じモデルがコードを書きレビューする際のAIの盲点を捉えるパターン。AI支援コードに回帰テストを追加する場合や、同じモデルが変更の記述とレビューの両方を行った場合に使用します。

AI回帰テスト とは?

AI回帰テストは、AI支援開発において、同じAIモデルがコードの記述とレビューの両方を行うことで生じる系統的な盲点(バグ)を自動テストで検出するためのパターン集です。このスキルは、Claude Code、Cursor、CodexなどのAIエージェントがAPIルートやバックエンドロジックを変更した後、またはバグ修正後に特に有効です。主な特徴として、サンドボックスモード(データベース不要)を利用した高速なAPI回帰テストの実装方法、バグ発見後に即座にテストを書く「テストファースト」戦略、そして「サンドボックス/プロダクションパスの不一致」や「SELECT句の欠落」など、AIが犯しやすい具体的な回帰パターンとそのテスト手法を提供します。テストはVitest + Next.js App Router環境で動作し、カスタムバグチェックコマンド(`/bug-check`)に統合することで、AIレビューの前に機械的にバグを検出するワークフローを実現します。このスキルの核心理念は「バグが見つかった場所にテストを書く」ことで、無駄のない効率的な回帰テストを構築し、同じ種類のバグの再発を防ぎます。

対応✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/ai-regression-testing

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

AI回帰テスト は何をしますか?

AI支援開発向けに特別に設計されたテストパターン。同じモデルがコードを書き、レビューすることで、自動テストだけが捕捉できる系統的な盲点が生じます。

アクティベーションのタイミング

  • AIエージェント(Claude Code、Cursor、Codex)がAPIルートまたはバックエンドロジックを変更した場合
  • バグを発見・修正した後で、再発を防止したい場合
  • データベース不要のテストに活用できるサンドボックス/モックモードがプロジェクトにある場合
  • コード変更後に/bug-checkまたは同様のレビューコマンドを実行する場合
  • 複数のコードパスが存在する場合(サンドボックス vs プロダクション、フィーチャーフラグなど)

核心的な問題

AIがコードを書き、その自分のコードをレビューするとき、両方のステップで同じ前提を持ち込みます。これにより、予測可能な障害パターンが発生します。

AIが修正を書く → AIが修正をレビューする → AIは「正しい」と言う → バグは依然として存在する

実際の例(本番環境で観測):

修正1: notification_settingsをAPIレスポンスに追加
  → SELECTクエリに追加し忘れた
  → AIがレビューしたが見逃した(同じ盲点)

修正2: SELECTクエリに追加
  → TypeScriptビルドエラー(生成された型にカラムがない)
  → AIは修正1をレビューしたが、SELECTの問題に気づかなかった

修正3: SELECT * に変更
  → プロダクションパスは修正したが、サンドボックスパスを忘れた
  → AIが再びレビューしたが見逃した(4回目)

修正4: テストが初回実行で即座に捕捉 PASS:

パターン: サンドボックス/プロダクションパスの不一致 は、AIが引き起こす回帰(リグレッション)の第1位です。

サンドボックスモードAPIテスト

AIフレンドリーなアーキテクチャを持つほとんどのプロジェクトには、サンドボックス/モックモードがあります。これがデータベース不要の高速APIテストの鍵です。

セットアップ(Vitest + Next.js App Router)

// vitest.config.ts
import { defineConfig } from "vitest/config";
import path from "path";

export default defineConfig({
  test: {
    environment: "node",
    globals: true,
    include: ["__tests__/**/*.test.ts"],
    setupFiles: ["__tests__/setup.ts"],
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "."),
    },
  },
});
// __tests__/setup.ts
// サンドボックスモードを強制 — データベース不要
process.env.SANDBOX_MODE = "true";
process.env.NEXT_PUBLIC_SUPABASE_URL = "";
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY = "";

Next.js APIルート用テストヘルパー

// __tests__/helpers.ts
import { NextRequest } from "next/server";

export function createTestRequest(
  url: string,
  options?: {
    method?: string;
    body?: Record<string, unknown>;
    headers?: Record<string, string>;
    sandboxUserId?: string;
  },
): NextRequest {
  const { method = "GET", body, headers = {}, sandboxUserId } = options || {};
  const fullUrl = url.startsWith("http") ? url : `http://localhost:3000${url}`;
  const reqHeaders: Record<string, string> = { ...headers };

  if (sandboxUserId) {
    reqHeaders["x-sandbox-user-id"] = sandboxUserId;
  }

  const init: { method: string; headers: Record<string, string>; body?: string } = {
    method,
    headers: reqHeaders,
  };

  if (body) {
    init.body = JSON.stringify(body);
    reqHeaders["content-type"] = "application/json";
  }

  return new NextRequest(fullUrl, init);
}

export async function parseResponse(response: Response) {
  const json = await response.json();
  return { status: response.status, json };
}

回帰テストの記述

重要な原則: 動作しているコードではなく、見つかったバグに対してテストを書く。

// __tests__/api/user/profile.test.ts
import { describe, it, expect } from "vitest";
import { createTestRequest, parseResponse } from "../../helpers";
import { GET, PATCH } from "@/app/api/user/profile/route";

// コントラクトを定義 — レスポンスに必須のフィールド
const REQUIRED_FIELDS = [
  "id",
  "email",
  "full_name",
  "phone",
  "role",
  "created_at",
  "avatar_url",
  "notification_settings",  // ← バグで欠落していたため追加
];

describe("GET /api/user/profile", () => {
  it("必須フィールドをすべて返す", async () => {
    const req = createTestRequest("/api/user/profile");
    const res = await GET(req);
    const { status, json } = await parseResponse(res);

    expect(status).toBe(200);
    for (const field of REQUIRED_FIELDS) {
      expect(json.data).toHaveProperty(field);
    }
  });

  // 回帰テスト — このバグはAIによって4回も導入された
  it("notification_settingsがundefinedでないこと(BUG-R1回帰)", async () => {
    const req = createTestRequest("/api/user/profile");
    const res = await GET(req);
    const { json } = await parseResponse(res);

    expect("notification_settings" in json.data).toBe(true);
    const ns = json.data.notification_settings;
    expect(ns === null || typeof ns === "object").toBe(true);
  });
});

サンドボックス/プロダクションの同等性テスト

最も一般的なAI回帰: プロダクションパスを修正したがサンドボックスパスを忘れる(またはその逆)。

// サンドボックスレスポンスが期待されるコントラクトと一致することをテスト
describe("GET /api/user/messages(会話リスト)", () => {
  it("サンドボックスモードでpartner_nameを含むこと", async () => {
    const req = createTestRequest("/api/user/messages", {
      sandboxUserId: "user-001",
    });
    const res = await GET(req);
    const { json } = await parseResponse(res);

    // これにより、partner_nameがプロダクションパスに追加されたが
    // サンドボックスパスには追加されなかったバグを捕捉
    if (json.data.length > 0) {
      for (const conv of json.data) {
        expect("partner_name" in conv).toBe(true);
      }
    }
  });
});

バグチェックワークフローへのテスト統合

カスタムコマンド定義

<!-- .claude/commands/bug-check.md -->
# バグチェック

## ステップ1: 自動テスト(必須、スキップ不可)

コードレビューを行う前に、まず以下のコマンドを実行してください:

    npm run test       # Vitestテストスイート
    npm run build      # TypeScript型チェック + ビルド

- テストが失敗した場合 → 最優先のバグとして報告
- ビルドが失敗した場合 → 型エラーを最優先として報告
- 両方が成功した場合のみ、ステップ2に進む

## ステップ2: コードレビュー(AIレビュー)

1. サンドボックス/プロダクションパスの一貫性
2. APIレスポンスの形状がフロントエンドの期待と一致しているか
3. SELECT句の完全性
4. ロールバックを含むエラーハンドリング
5. 楽観的更新のレースコンディション

## ステップ3: 修正された各バグについて、回帰テストを提案

ワークフロー

ユーザー: "バグチェックして" (または "/bug-check")
  │
  ├─ ステップ1: npm run test
  │   ├─ FAIL → バグを機械的に検出(AIの判断不要)
  │   └─ PASS → 続行
  │
  ├─ ステップ2: npm run build
  │   ├─ FAIL → 型エラーを機械的に検出
  │   └─ PASS → 続行
  │
  ├─ ステップ3: AIコードレビュー(既知の盲点に注意)
  │   └─ 結果を報告
  │
  └─ ステップ4: 各修正に対して回帰テストを記述
      └─ 次回のバグチェックで修正の破損を検出

一般的なAI回帰パターン

パターン1: サンドボックス/プロダクションパスの不一致

頻度: 最も多い(4件中3件の回帰で観測)

// 失敗: AIがプロダクションパスにのみフィールドを追加
if (isSandboxMode()) {
  return { data: { id, email, name } };  // 新しいフィールドが欠落
}
// プロダクションパス
return { data: { id, email, name, notification_settings } };

// 成功: 両方のパスが同じ形状を返すこと
if (isSandboxMode()) {
  return { data: { id, email, name, notification_settings: null } };
}
return { data: { id, email, name, notification_settings } };

それを捕捉するテスト:

it("サンドボックスとプロダクションが同じフィールドを返すこと", async () => {
  // テスト環境では、サンドボックスモードが強制ON
  const res = await GET(createTestRequest("/api/user/profile"));
  const { json } = await parseResponse(res);

  for (const field of REQUIRED_FIELDS) {
    expect(json.data).toHaveProperty(field);
  }
});

パターン2: SELECT句の欠落

頻度: Supabase/Prismaで新しいカラム追加時に多い

// 失敗: 新しいカラムがレスポンスに追加されたが、SELECTには含まれていない
const { data } = await supabase
  .from("users")
  .select("id, email, name")  // notification_settingsがここにない
  .single();

return { data: { ...data, notification_settings: data.notification_settings } };
// → notification_settingsは常にundefined

// 成功: SELECT * を使用するか、新しいカラムを明示的に含める
const { data } = await supabase
  .from("users")
  .select("*")
  .single();

パターン3: エラー状態のリーク

頻度: 中程度 — 既存コンポーネントにエラーハンドリングを追加する場合

// 失敗: エラー状態は設定されたが、古いデータがクリアされていない
catch (err) {
  setError("読み込みに失敗しました");
  // reservationsには前のタブのデータがまだ表示されている!
}

// 成功: エラー時に関連する状態をクリア
catch (err) {
  setReservations([]);  // 古いデータをクリア
  setError("読み込みに失敗しました");
}

パターン4: 適切なロールバックのない楽観的更新

// 失敗: 失敗時のロールバックなし
const handleRemove = async (id: string) => {
  setItems(prev => prev.filter(i => i.id !== id));
  await fetch(`/api/items/${id}`, { method: "DELETE" });
  // APIが失敗した場合、アイテムはUIから消えるがDBには残る
};

// 成功: 以前の状態をキャプチャし、失敗時にロールバック
const handleRemove = async (id: string) => {
  const prevItems = [...items];
  setItems(prev => prev.filter(i => i.id !== id));
  try {
    const res = await fetch(`/api/items/${id}`, { method: "DELETE" });
    if (!res.ok) throw new Error("APIエラー");
  } catch {
    setItems(prevItems);  // ロールバック
    alert("削除に失敗しました");
  }
};

戦略: バグが見つかった場所にテストを書く

100%カバレッジを目指さないでください。代わりに:

/api/user/profile でバグが見つかった → profile APIのテストを書く
/api/user/messages でバグが見つかった → messages APIのテストを書く
/api/user/favorites でバグが見つかった → favorites APIのテストを書く
/api/user/notifications ではバグなし → テストを書かない(まだ)

これがAI開発で有効な理由:

  1. AIは同じ種類のミスを繰り返す傾向がある
  2. バグは複雑な領域(認証、マルチパスロジック、状態管理)に集中する
  3. 一度テストされれば、その正確な回帰は二度と発生しない
  4. テスト数はバグ修正とともに有機的に増加 — 無駄な労力なし

クイックリファレンス

AI回帰パターンテスト戦略優先度
サンドボックス/プロダクションの不一致サンドボックスモードで同じレスポンス形状をアサート高
SELECT句の欠落レスポンス内のすべての必須フィールドをアサート高
エラー状態のリークエラー時の状態クリアをアサート中
ロールバックの欠落API失敗時の状態復元をアサート中
型キャストによるnullのマスキングフィールドがundefinedでないことをアサート中

すべきこと / すべきでないこと

すべきこと:

  • バグを見つけたらすぐにテストを書く(可能なら修正する前に)
  • 実装ではなく、APIレスポンスの形状をテストする
  • すべてのバグチェックの最初のステップとしてテストを実行する
  • テストを高速に保つ(サンドボックスモードで合計1秒未満)
  • テスト名を、それが防ぐバグにちなんで命名する(例: "BUG-R1回帰")

すべきでないこと:

  • 一度もバグが発生したことのないコードにテストを書く
  • AIの自己レビューを自動テストの代わりとして信頼する
  • 「単なるモックデータだから」とサンドボックスパスのテストをスキップする
  • 単体テストで十分な場合に結合テストを書く
  • カバレッジ率を目指す — 回帰防止を目指す

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

api-connector-builder

Build a new API connector or provider by matching the target repo

関連スキル