[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6JTSDE2YABDXEC1M12T3MMS":3,"skill-same:01M6JTSDE2YABDXEC1M12T3MMS":89},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":53,"linkOnly":54,"markdownContent":55,"markdownBody":56,"frontMatter":57,"refName":59,"commitSha":60,"skillDirectory":61,"forksCount":62,"repositoryHtmlUrl":63,"repositoryHomepageUrl":64,"ownerHtmlUrl":65,"ownerBlogUrl":66,"ownerDescription":67,"updatedAt":68,"install":69,"resources":82},"01M6JTSDE2YABDXEC1M12T3MMS","ai-regression-testing",null,"Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code.","hashgraph-online\u002Fawesome-codex-plugins","hashgraph-online","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F160371962?v=4","01M6CNB6NRJVNNGN14TR01Q6D3","HOL (Hashgraph Online)","01M6JT1HSKKG9V68KQAQGBA7XP",1559,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FColin4k1024\u002Ftsp\u002Fskills\u002Fai-regression-testing\u002FSKILL.md",[18,23,26],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52],"regression testing","ai regression testing","regression","testing","api testing","catch","for","mode","reviews","testing strategies","strategies","patterns","spots","bug","model","api","database","code","development","workflows","sandbox","2026-11-10 10:12:30",false,"---\nname: ai-regression-testing\ndescription: Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code.\norigin: ECC\n---\n\n# AI Regression Testing\n\nTesting patterns specifically designed for AI-assisted development, where the same model writes code and reviews it — creating systematic blind spots that only automated tests can catch.\n\n## When to Activate\n\n- AI agent (Claude Code, Cursor, Codex) has modified API routes or backend logic\n- A bug was found and fixed — need to prevent re-introduction\n- Project has a sandbox\u002Fmock mode that can be leveraged for DB-free testing\n- Running `\u002Fbug-check` or similar review commands after code changes\n- Multiple code paths exist (sandbox vs production, feature flags, etc.)\n\n## The Core Problem\n\nWhen an AI writes code and then reviews its own work, it carries the same assumptions into both steps. This creates a predictable failure pattern:\n\n```\nAI writes fix → AI reviews fix → AI says \"looks correct\" → Bug still exists\n```\n\n**Real-world example** (observed in production):\n\n```\nFix 1: Added notification_settings to API response\n  → Forgot to add it to the SELECT query\n  → AI reviewed and missed it (same blind spot)\n\nFix 2: Added it to SELECT query\n  → TypeScript build error (column not in generated types)\n  → AI reviewed Fix 1 but didn't catch the SELECT issue\n\nFix 3: Changed to SELECT *\n  → Fixed production path, forgot sandbox path\n  → AI reviewed and missed it AGAIN (4th occurrence)\n\nFix 4: Test caught it instantly on first run PASS:\n```\n\nThe pattern: **sandbox\u002Fproduction path inconsistency** is the #1 AI-introduced regression.\n\n## Sandbox-Mode API Testing\n\nMost projects with AI-friendly architecture have a sandbox\u002Fmock mode. This is the key to fast, DB-free API testing.\n\n### Setup (Vitest + Next.js App Router)\n\n```typescript\n\u002F\u002F vitest.config.ts\nimport { defineConfig } from \"vitest\u002Fconfig\";\nimport path from \"path\";\n\nexport default defineConfig({\n  test: {\n    environment: \"node\",\n    globals: true,\n    include: [\"__tests__\u002F**\u002F*.test.ts\"],\n    setupFiles: [\"__tests__\u002Fsetup.ts\"],\n  },\n  resolve: {\n    alias: {\n      \"@\": path.resolve(__dirname, \".\"),\n    },\n  },\n});\n```\n\n```typescript\n\u002F\u002F __tests__\u002Fsetup.ts\n\u002F\u002F Force sandbox mode — no database needed\nprocess.env.SANDBOX_MODE = \"true\";\nprocess.env.NEXT_PUBLIC_SUPABASE_URL = \"\";\nprocess.env.NEXT_PUBLIC_SUPABASE_ANON_KEY = \"\";\n```\n\n### Test Helper for Next.js API Routes\n\n```typescript\n\u002F\u002F __tests__\u002Fhelpers.ts\nimport { NextRequest } from \"next\u002Fserver\";\n\nexport function createTestRequest(\n  url: string,\n  options?: {\n    method?: string;\n    body?: Record\u003Cstring, unknown>;\n    headers?: Record\u003Cstring, string>;\n    sandboxUserId?: string;\n  },\n): NextRequest {\n  const { method = \"GET\", body, headers = {}, sandboxUserId } = options || {};\n  const fullUrl = url.startsWith(\"http\") ? url : `http:\u002F\u002Flocalhost:3000${url}`;\n  const reqHeaders: Record\u003Cstring, string> = { ...headers };\n\n  if (sandboxUserId) {\n    reqHeaders[\"x-sandbox-user-id\"] = sandboxUserId;\n  }\n\n  const init: { method: string; headers: Record\u003Cstring, string>; body?: string } = {\n    method,\n    headers: reqHeaders,\n  };\n\n  if (body) {\n    init.body = JSON.stringify(body);\n    reqHeaders[\"content-type\"] = \"application\u002Fjson\";\n  }\n\n  return new NextRequest(fullUrl, init);\n}\n\nexport async function parseResponse(response: Response) {\n  const json = await response.json();\n  return { status: response.status, json };\n}\n```\n\n### Writing Regression Tests\n\nThe key principle: **write tests for bugs that were found, not for code that works**.\n\n```typescript\n\u002F\u002F __tests__\u002Fapi\u002Fuser\u002Fprofile.test.ts\nimport { describe, it, expect } from \"vitest\";\nimport { createTestRequest, parseResponse } from \"..\u002F..\u002Fhelpers\";\nimport { GET, PATCH } from \"@\u002Fapp\u002Fapi\u002Fuser\u002Fprofile\u002Froute\";\n\n\u002F\u002F Define the contract — what fields MUST be in the response\nconst REQUIRED_FIELDS = [\n  \"id\",\n  \"email\",\n  \"full_name\",\n  \"phone\",\n  \"role\",\n  \"created_at\",\n  \"avatar_url\",\n  \"notification_settings\",  \u002F\u002F ← Added after bug found it missing\n];\n\ndescribe(\"GET \u002Fapi\u002Fuser\u002Fprofile\", () => {\n  it(\"returns all required fields\", async () => {\n    const req = createTestRequest(\"\u002Fapi\u002Fuser\u002Fprofile\");\n    const res = await GET(req);\n    const { status, json } = await parseResponse(res);\n\n    expect(status).toBe(200);\n    for (const field of REQUIRED_FIELDS) {\n      expect(json.data).toHaveProperty(field);\n    }\n  });\n\n  \u002F\u002F Regression test — this exact bug was introduced by AI 4 times\n  it(\"notification_settings is not undefined (BUG-R1 regression)\", async () => {\n    const req = createTestRequest(\"\u002Fapi\u002Fuser\u002Fprofile\");\n    const res = await GET(req);\n    const { json } = await parseResponse(res);\n\n    expect(\"notification_settings\" in json.data).toBe(true);\n    const ns = json.data.notification_settings;\n    expect(ns === null || typeof ns === \"object\").toBe(true);\n  });\n});\n```\n\n### Testing Sandbox\u002FProduction Parity\n\nThe most common AI regression: fixing production path but forgetting sandbox path (or vice versa).\n\n```typescript\n\u002F\u002F Test that sandbox responses match the expected contract\ndescribe(\"GET \u002Fapi\u002Fuser\u002Fmessages (conversation list)\", () => {\n  it(\"includes partner_name in sandbox mode\", async () => {\n    const req = createTestRequest(\"\u002Fapi\u002Fuser\u002Fmessages\", {\n      sandboxUserId: \"user-001\",\n    });\n    const res = await GET(req);\n    const { json } = await parseResponse(res);\n\n    \u002F\u002F This caught a bug where partner_name was added\n    \u002F\u002F to production path but not sandbox path\n    if (json.data.length > 0) {\n      for (const conv of json.data) {\n        expect(\"partner_name\" in conv).toBe(true);\n      }\n    }\n  });\n});\n```\n\n## Integrating Tests into Bug-Check Workflow\n\n### Custom Command Definition\n\n```markdown\n\u003C!-- .claude\u002Fcommands\u002Fbug-check.md -->\n# Bug Check\n\n## Step 1: Automated Tests (mandatory, cannot skip)\n\nRun these commands FIRST before any code review:\n\n    npm run test       # Vitest test suite\n    npm run build      # TypeScript type check + build\n\n- If tests fail → report as highest priority bug\n- If build fails → report type errors as highest priority\n- Only proceed to Step 2 if both pass\n\n## Step 2: Code Review (AI review)\n\n1. Sandbox \u002F production path consistency\n2. API response shape matches frontend expectations\n3. SELECT clause completeness\n4. Error handling with rollback\n5. Optimistic update race conditions\n\n## Step 3: For each bug fixed, propose a regression test\n```\n\n### The Workflow\n\n```\nUser: \"バグチェックして\" (or \"\u002Fbug-check\")\n  │\n  ├─ Step 1: npm run test\n  │   ├─ FAIL → Bug found mechanically (no AI judgment needed)\n  │   └─ PASS → Continue\n  │\n  ├─ Step 2: npm run build\n  │   ├─ FAIL → Type error found mechanically\n  │   └─ PASS → Continue\n  │\n  ├─ Step 3: AI code review (with known blind spots in mind)\n  │   └─ Findings reported\n  │\n  └─ Step 4: For each fix, write a regression test\n      └─ Next bug-check catches if fix breaks\n```\n\n## Common AI Regression Patterns\n\n### Pattern 1: Sandbox\u002FProduction Path Mismatch\n\n**Frequency**: Most common (observed in 3 out of 4 regressions)\n\n```typescript\n\u002F\u002F FAIL: AI adds field to production path only\nif (isSandboxMode()) {\n  return { data: { id, email, name } };  \u002F\u002F Missing new field\n}\n\u002F\u002F Production path\nreturn { data: { id, email, name, notification_settings } };\n\n\u002F\u002F PASS: Both paths must return the same shape\nif (isSandboxMode()) {\n  return { data: { id, email, name, notification_settings: null } };\n}\nreturn { data: { id, email, name, notification_settings } };\n```\n\n**Test to catch it**:\n\n```typescript\nit(\"sandbox and production return same fields\", async () => {\n  \u002F\u002F In test env, sandbox mode is forced ON\n  const res = await GET(createTestRequest(\"\u002Fapi\u002Fuser\u002Fprofile\"));\n  const { json } = await parseResponse(res);\n\n  for (const field of REQUIRED_FIELDS) {\n    expect(json.data).toHaveProperty(field);\n  }\n});\n```\n\n### Pattern 2: SELECT Clause Omission\n\n**Frequency**: Common with Supabase\u002FPrisma when adding new columns\n\n```typescript\n\u002F\u002F FAIL: New column added to response but not to SELECT\nconst { data } = await supabase\n  .from(\"users\")\n  .select(\"id, email, name\")  \u002F\u002F notification_settings not here\n  .single();\n\nreturn { data: { ...data, notification_settings: data.notification_settings } };\n\u002F\u002F → notification_settings is always undefined\n\n\u002F\u002F PASS: Use SELECT * or explicitly include new columns\nconst { data } = await supabase\n  .from(\"users\")\n  .select(\"*\")\n  .single();\n```\n\n### Pattern 3: Error State Leakage\n\n**Frequency**: Moderate — when adding error handling to existing components\n\n```typescript\n\u002F\u002F FAIL: Error state set but old data not cleared\ncatch (err) {\n  setError(\"Failed to load\");\n  \u002F\u002F reservations still shows data from previous tab!\n}\n\n\u002F\u002F PASS: Clear related state on error\ncatch (err) {\n  setReservations([]);  \u002F\u002F Clear stale data\n  setError(\"Failed to load\");\n}\n```\n\n### Pattern 4: Optimistic Update Without Proper Rollback\n\n```typescript\n\u002F\u002F FAIL: No rollback on failure\nconst handleRemove = async (id: string) => {\n  setItems(prev => prev.filter(i => i.id !== id));\n  await fetch(`\u002Fapi\u002Fitems\u002F${id}`, { method: \"DELETE\" });\n  \u002F\u002F If API fails, item is gone from UI but still in DB\n};\n\n\u002F\u002F PASS: Capture previous state and rollback on failure\nconst handleRemove = async (id: string) => {\n  const prevItems = [...items];\n  setItems(prev => prev.filter(i => i.id !== id));\n  try {\n    const res = await fetch(`\u002Fapi\u002Fitems\u002F${id}`, { method: \"DELETE\" });\n    if (!res.ok) throw new Error(\"API error\");\n  } catch {\n    setItems(prevItems);  \u002F\u002F Rollback\n    alert(\"削除に失敗しました\");\n  }\n};\n```\n\n## Strategy: Test Where Bugs Were Found\n\nDon't aim for 100% coverage. Instead:\n\n```\nBug found in \u002Fapi\u002Fuser\u002Fprofile     → Write test for profile API\nBug found in \u002Fapi\u002Fuser\u002Fmessages    → Write test for messages API\nBug found in \u002Fapi\u002Fuser\u002Ffavorites   → Write test for favorites API\nNo bug in \u002Fapi\u002Fuser\u002Fnotifications  → Don't write test (yet)\n```\n\n**Why this works with AI development:**\n\n1. AI tends to make the **same category of mistake** repeatedly\n2. Bugs cluster in complex areas (auth, multi-path logic, state management)\n3. Once tested, that exact regression **cannot happen again**\n4. Test count grows organically with bug fixes — no wasted effort\n\n## Quick Reference\n\n| AI Regression Pattern | Test Strategy | Priority |\n|---|---|---|\n| Sandbox\u002Fproduction mismatch | Assert same response shape in sandbox mode |  High |\n| SELECT clause omission | Assert all required fields in response |  High |\n| Error state leakage | Assert state cleanup on error |  Medium |\n| Missing rollback | Assert state restored on API failure |  Medium |\n| Type cast masking null | Assert field is not undefined |  Medium |\n\n## DO \u002F DON'T\n\n**DO:**\n- Write tests immediately after finding a bug (before fixing it if possible)\n- Test the API response shape, not the implementation\n- Run tests as the first step of every bug-check\n- Keep tests fast (\u003C 1 second total with sandbox mode)\n- Name tests after the bug they prevent (e.g., \"BUG-R1 regression\")\n\n**DON'T:**\n- Write tests for code that has never had a bug\n- Trust AI self-review as a substitute for automated tests\n- Skip sandbox path testing because \"it's just mock data\"\n- Write integration tests when unit tests suffice\n- Aim for coverage percentage — aim for regression prevention\n","# AI Regression Testing\n\nTesting patterns specifically designed for AI-assisted development, where the same model writes code and reviews it — creating systematic blind spots that only automated tests can catch.\n\n## When to Activate\n\n- AI agent (Claude Code, Cursor, Codex) has modified API routes or backend logic\n- A bug was found and fixed — need to prevent re-introduction\n- Project has a sandbox\u002Fmock mode that can be leveraged for DB-free testing\n- Running `\u002Fbug-check` or similar review commands after code changes\n- Multiple code paths exist (sandbox vs production, feature flags, etc.)\n\n## The Core Problem\n\nWhen an AI writes code and then reviews its own work, it carries the same assumptions into both steps. This creates a predictable failure pattern:\n\n```\nAI writes fix → AI reviews fix → AI says \"looks correct\" → Bug still exists\n```\n\n**Real-world example** (observed in production):\n\n```\nFix 1: Added notification_settings to API response\n  → Forgot to add it to the SELECT query\n  → AI reviewed and missed it (same blind spot)\n\nFix 2: Added it to SELECT query\n  → TypeScript build error (column not in generated types)\n  → AI reviewed Fix 1 but didn't catch the SELECT issue\n\nFix 3: Changed to SELECT *\n  → Fixed production path, forgot sandbox path\n  → AI reviewed and missed it AGAIN (4th occurrence)\n\nFix 4: Test caught it instantly on first run PASS:\n```\n\nThe pattern: **sandbox\u002Fproduction path inconsistency** is the #1 AI-introduced regression.\n\n## Sandbox-Mode API Testing\n\nMost projects with AI-friendly architecture have a sandbox\u002Fmock mode. This is the key to fast, DB-free API testing.\n\n### Setup (Vitest + Next.js App Router)\n\n```typescript\n\u002F\u002F vitest.config.ts\nimport { defineConfig } from \"vitest\u002Fconfig\";\nimport path from \"path\";\n\nexport default defineConfig({\n  test: {\n    environment: \"node\",\n    globals: true,\n    include: [\"__tests__\u002F**\u002F*.test.ts\"],\n    setupFiles: [\"__tests__\u002Fsetup.ts\"],\n  },\n  resolve: {\n    alias: {\n      \"@\": path.resolve(__dirname, \".\"),\n    },\n  },\n});\n```\n\n```typescript\n\u002F\u002F __tests__\u002Fsetup.ts\n\u002F\u002F Force sandbox mode — no database needed\nprocess.env.SANDBOX_MODE = \"true\";\nprocess.env.NEXT_PUBLIC_SUPABASE_URL = \"\";\nprocess.env.NEXT_PUBLIC_SUPABASE_ANON_KEY = \"\";\n```\n\n### Test Helper for Next.js API Routes\n\n```typescript\n\u002F\u002F __tests__\u002Fhelpers.ts\nimport { NextRequest } from \"next\u002Fserver\";\n\nexport function createTestRequest(\n  url: string,\n  options?: {\n    method?: string;\n    body?: Record\u003Cstring, unknown>;\n    headers?: Record\u003Cstring, string>;\n    sandboxUserId?: string;\n  },\n): NextRequest {\n  const { method = \"GET\", body, headers = {}, sandboxUserId } = options || {};\n  const fullUrl = url.startsWith(\"http\") ? url : `http:\u002F\u002Flocalhost:3000${url}`;\n  const reqHeaders: Record\u003Cstring, string> = { ...headers };\n\n  if (sandboxUserId) {\n    reqHeaders[\"x-sandbox-user-id\"] = sandboxUserId;\n  }\n\n  const init: { method: string; headers: Record\u003Cstring, string>; body?: string } = {\n    method,\n    headers: reqHeaders,\n  };\n\n  if (body) {\n    init.body = JSON.stringify(body);\n    reqHeaders[\"content-type\"] = \"application\u002Fjson\";\n  }\n\n  return new NextRequest(fullUrl, init);\n}\n\nexport async function parseResponse(response: Response) {\n  const json = await response.json();\n  return { status: response.status, json };\n}\n```\n\n### Writing Regression Tests\n\nThe key principle: **write tests for bugs that were found, not for code that works**.\n\n```typescript\n\u002F\u002F __tests__\u002Fapi\u002Fuser\u002Fprofile.test.ts\nimport { describe, it, expect } from \"vitest\";\nimport { createTestRequest, parseResponse } from \"..\u002F..\u002Fhelpers\";\nimport { GET, PATCH } from \"@\u002Fapp\u002Fapi\u002Fuser\u002Fprofile\u002Froute\";\n\n\u002F\u002F Define the contract — what fields MUST be in the response\nconst REQUIRED_FIELDS = [\n  \"id\",\n  \"email\",\n  \"full_name\",\n  \"phone\",\n  \"role\",\n  \"created_at\",\n  \"avatar_url\",\n  \"notification_settings\",  \u002F\u002F ← Added after bug found it missing\n];\n\ndescribe(\"GET \u002Fapi\u002Fuser\u002Fprofile\", () => {\n  it(\"returns all required fields\", async () => {\n    const req = createTestRequest(\"\u002Fapi\u002Fuser\u002Fprofile\");\n    const res = await GET(req);\n    const { status, json } = await parseResponse(res);\n\n    expect(status).toBe(200);\n    for (const field of REQUIRED_FIELDS) {\n      expect(json.data).toHaveProperty(field);\n    }\n  });\n\n  \u002F\u002F Regression test — this exact bug was introduced by AI 4 times\n  it(\"notification_settings is not undefined (BUG-R1 regression)\", async () => {\n    const req = createTestRequest(\"\u002Fapi\u002Fuser\u002Fprofile\");\n    const res = await GET(req);\n    const { json } = await parseResponse(res);\n\n    expect(\"notification_settings\" in json.data).toBe(true);\n    const ns = json.data.notification_settings;\n    expect(ns === null || typeof ns === \"object\").toBe(true);\n  });\n});\n```\n\n### Testing Sandbox\u002FProduction Parity\n\nThe most common AI regression: fixing production path but forgetting sandbox path (or vice versa).\n\n```typescript\n\u002F\u002F Test that sandbox responses match the expected contract\ndescribe(\"GET \u002Fapi\u002Fuser\u002Fmessages (conversation list)\", () => {\n  it(\"includes partner_name in sandbox mode\", async () => {\n    const req = createTestRequest(\"\u002Fapi\u002Fuser\u002Fmessages\", {\n      sandboxUserId: \"user-001\",\n    });\n    const res = await GET(req);\n    const { json } = await parseResponse(res);\n\n    \u002F\u002F This caught a bug where partner_name was added\n    \u002F\u002F to production path but not sandbox path\n    if (json.data.length > 0) {\n      for (const conv of json.data) {\n        expect(\"partner_name\" in conv).toBe(true);\n      }\n    }\n  });\n});\n```\n\n## Integrating Tests into Bug-Check Workflow\n\n### Custom Command Definition\n\n```markdown\n\u003C!-- .claude\u002Fcommands\u002Fbug-check.md -->\n# Bug Check\n\n## Step 1: Automated Tests (mandatory, cannot skip)\n\nRun these commands FIRST before any code review:\n\n    npm run test       # Vitest test suite\n    npm run build      # TypeScript type check + build\n\n- If tests fail → report as highest priority bug\n- If build fails → report type errors as highest priority\n- Only proceed to Step 2 if both pass\n\n## Step 2: Code Review (AI review)\n\n1. Sandbox \u002F production path consistency\n2. API response shape matches frontend expectations\n3. SELECT clause completeness\n4. Error handling with rollback\n5. Optimistic update race conditions\n\n## Step 3: For each bug fixed, propose a regression test\n```\n\n### The Workflow\n\n```\nUser: \"バグチェックして\" (or \"\u002Fbug-check\")\n  │\n  ├─ Step 1: npm run test\n  │   ├─ FAIL → Bug found mechanically (no AI judgment needed)\n  │   └─ PASS → Continue\n  │\n  ├─ Step 2: npm run build\n  │   ├─ FAIL → Type error found mechanically\n  │   └─ PASS → Continue\n  │\n  ├─ Step 3: AI code review (with known blind spots in mind)\n  │   └─ Findings reported\n  │\n  └─ Step 4: For each fix, write a regression test\n      └─ Next bug-check catches if fix breaks\n```\n\n## Common AI Regression Patterns\n\n### Pattern 1: Sandbox\u002FProduction Path Mismatch\n\n**Frequency**: Most common (observed in 3 out of 4 regressions)\n\n```typescript\n\u002F\u002F FAIL: AI adds field to production path only\nif (isSandboxMode()) {\n  return { data: { id, email, name } };  \u002F\u002F Missing new field\n}\n\u002F\u002F Production path\nreturn { data: { id, email, name, notification_settings } };\n\n\u002F\u002F PASS: Both paths must return the same shape\nif (isSandboxMode()) {\n  return { data: { id, email, name, notification_settings: null } };\n}\nreturn { data: { id, email, name, notification_settings } };\n```\n\n**Test to catch it**:\n\n```typescript\nit(\"sandbox and production return same fields\", async () => {\n  \u002F\u002F In test env, sandbox mode is forced ON\n  const res = await GET(createTestRequest(\"\u002Fapi\u002Fuser\u002Fprofile\"));\n  const { json } = await parseResponse(res);\n\n  for (const field of REQUIRED_FIELDS) {\n    expect(json.data).toHaveProperty(field);\n  }\n});\n```\n\n### Pattern 2: SELECT Clause Omission\n\n**Frequency**: Common with Supabase\u002FPrisma when adding new columns\n\n```typescript\n\u002F\u002F FAIL: New column added to response but not to SELECT\nconst { data } = await supabase\n  .from(\"users\")\n  .select(\"id, email, name\")  \u002F\u002F notification_settings not here\n  .single();\n\nreturn { data: { ...data, notification_settings: data.notification_settings } };\n\u002F\u002F → notification_settings is always undefined\n\n\u002F\u002F PASS: Use SELECT * or explicitly include new columns\nconst { data } = await supabase\n  .from(\"users\")\n  .select(\"*\")\n  .single();\n```\n\n### Pattern 3: Error State Leakage\n\n**Frequency**: Moderate — when adding error handling to existing components\n\n```typescript\n\u002F\u002F FAIL: Error state set but old data not cleared\ncatch (err) {\n  setError(\"Failed to load\");\n  \u002F\u002F reservations still shows data from previous tab!\n}\n\n\u002F\u002F PASS: Clear related state on error\ncatch (err) {\n  setReservations([]);  \u002F\u002F Clear stale data\n  setError(\"Failed to load\");\n}\n```\n\n### Pattern 4: Optimistic Update Without Proper Rollback\n\n```typescript\n\u002F\u002F FAIL: No rollback on failure\nconst handleRemove = async (id: string) => {\n  setItems(prev => prev.filter(i => i.id !== id));\n  await fetch(`\u002Fapi\u002Fitems\u002F${id}`, { method: \"DELETE\" });\n  \u002F\u002F If API fails, item is gone from UI but still in DB\n};\n\n\u002F\u002F PASS: Capture previous state and rollback on failure\nconst handleRemove = async (id: string) => {\n  const prevItems = [...items];\n  setItems(prev => prev.filter(i => i.id !== id));\n  try {\n    const res = await fetch(`\u002Fapi\u002Fitems\u002F${id}`, { method: \"DELETE\" });\n    if (!res.ok) throw new Error(\"API error\");\n  } catch {\n    setItems(prevItems);  \u002F\u002F Rollback\n    alert(\"削除に失敗しました\");\n  }\n};\n```\n\n## Strategy: Test Where Bugs Were Found\n\nDon't aim for 100% coverage. Instead:\n\n```\nBug found in \u002Fapi\u002Fuser\u002Fprofile     → Write test for profile API\nBug found in \u002Fapi\u002Fuser\u002Fmessages    → Write test for messages API\nBug found in \u002Fapi\u002Fuser\u002Ffavorites   → Write test for favorites API\nNo bug in \u002Fapi\u002Fuser\u002Fnotifications  → Don't write test (yet)\n```\n\n**Why this works with AI development:**\n\n1. AI tends to make the **same category of mistake** repeatedly\n2. Bugs cluster in complex areas (auth, multi-path logic, state management)\n3. Once tested, that exact regression **cannot happen again**\n4. Test count grows organically with bug fixes — no wasted effort\n\n## Quick Reference\n\n| AI Regression Pattern | Test Strategy | Priority |\n|---|---|---|\n| Sandbox\u002Fproduction mismatch | Assert same response shape in sandbox mode |  High |\n| SELECT clause omission | Assert all required fields in response |  High |\n| Error state leakage | Assert state cleanup on error |  Medium |\n| Missing rollback | Assert state restored on API failure |  Medium |\n| Type cast masking null | Assert field is not undefined |  Medium |\n\n## DO \u002F DON'T\n\n**DO:**\n- Write tests immediately after finding a bug (before fixing it if possible)\n- Test the API response shape, not the implementation\n- Run tests as the first step of every bug-check\n- Keep tests fast (\u003C 1 second total with sandbox mode)\n- Name tests after the bug they prevent (e.g., \"BUG-R1 regression\")\n\n**DON'T:**\n- Write tests for code that has never had a bug\n- Trust AI self-review as a substitute for automated tests\n- Skip sandbox path testing because \"it's just mock data\"\n- Write integration tests when unit tests suffice\n- Aim for coverage percentage — aim for regression prevention\n",{"name":5,"origin":58,"description":7},"ECC","main","b0f0a87593c578a7898eccaf1b363f7f87c1f99b","plugins\u002FColin4k1024\u002Ftsp\u002Fskills\u002Fai-regression-testing",474,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins","https:\u002F\u002Fhol.org\u002Fplugins\u002Fbest-codex-plugins","https:\u002F\u002Fgithub.com\u002Fhashgraph-online","https:\u002F\u002Fhol.org","Open-source standards and developer tools for interoperable AI agents: discovery, identity, communication, payments, privacy and security.","2026-11-11 14:40:14",{"source":8,"skillName":5,"commands":70,"prompt":80,"zipAvailable":81},[71,74,77],{"tool":72,"command":73},"npx","npx skills add hashgraph-online\u002Fawesome-codex-plugins --skill ai-regression-testing",{"tool":75,"command":76},"bunx","bunx skills add hashgraph-online\u002Fawesome-codex-plugins --skill ai-regression-testing",{"tool":78,"command":79},"pnpm","pnpm dlx skills add hashgraph-online\u002Fawesome-codex-plugins --skill ai-regression-testing","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FColin4k1024\u002Ftsp\u002Fskills\u002Fai-regression-testing\u002FSKILL.md",true,[83],{"path":84,"resourceType":85,"resourceTypeDesc":86,"sizeBytes":87,"sourceHtmlUrl":88},"agents\u002Fopenai.yaml","REFERENCE","参考文档",297,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FColin4k1024\u002Ftsp\u002Fskills\u002Fai-regression-testing\u002Fagents\u002Fopenai.yaml",[90,98,105,112,139,164],{"skillNo":91,"name":92,"nameZh":6,"description":93,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":96,"publishedAt":97},"01M746ZWACVKMZ1BJXJZHYJSSX","migrate-to-e2e","Moves an existing Playwright, Cypress, Selenium, Appium, Detox, Maestro, or TesterArmy suite to e2e one slice at a time, with the old suite running beside the new one until each ported test is proven. Keeps a MIGRATION.md progress file so any later session resumes where the last stopped. Optionally plants a defect to show both suites catch it. Use for \u002Fmigrate-to-e2e, \"migrate our tests to e2e\", \"port these Maestro flows\", \"move our TesterArmy tests\", or when a project has an e2e config and an older suite still running.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Ftester-army\u002Fe2e\u002Fskills\u002Fmigrate-to-e2e\u002FSKILL.md",[],[],"2026-11-11 15:11:14",{"skillNo":99,"name":100,"nameZh":6,"description":101,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":102,"categories":103,"keywords":104,"publishedAt":97},"01M746ZPTAX1Q0FBKAB1CYND7E","e2e","Writes, runs, and debugs end-to-end tests for web and mobile apps with e2e, the agentic test runner, which mixes agent.act goals with exact locator assertions on a Playwright browser or an iOS or Android device. Also drives a project's running app live over the e2e MCP server to look at a screen, check a UI change, take a screenshot or record a video, and try a locator; and runs bug bashes, parallel e2e explore runs with each bug proven by a repro test. Use when a project depends on e2e or has an e2e.config.ts, when asked for end-to-end, browser, mobile, or agentic UI tests, to check a change in the running app, to QA or bug bash an app or branch, or when an e2e run fails.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Ftester-army\u002Fe2e\u002Fskills\u002Fe2e\u002FSKILL.md",[],[],{"skillNo":106,"name":107,"nameZh":6,"description":108,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":111,"publishedAt":97},"01M746ZJN784HVHMDP9MQGCSGG","create-verification-skill","Generate a project-local verify-\u003Capp> skill on top of e2e, so any coding agent can launch the app, check it is worth driving, exercise a feature the way a user does, keep evidence, and bug bash it. Writes the skill, a feature map with one explore charter per feature, and proves it once. Use for \u002Fcreate-verification-skill, \"make a verification skill for this repo\", or when a project has no scripted way to prove UI behavior.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Ftester-army\u002Fe2e\u002Fskills\u002Fcreate-verification-skill\u002FSKILL.md",[],[],{"skillNo":113,"name":114,"nameZh":6,"description":115,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":116,"categories":117,"keywords":118,"publishedAt":53},"01M716A6ETNB9B1SQ3GXZC75VR","deja-search","deja-vu memory — search the user's past AI coding sessions with the deja CLI. Holds what they already settled and never wrote into the repo (naming rules, banned or already-tried tools, required checks before merge, preferred values, who owns what). Use before your first edit in a task, before you call a change done or ready to merge, before you recommend a tool, library, design or reviewer, before re-debugging an error that may already be solved, when they say 'didn't we fix this before', 'what did we decide about X' or 'I already have that', and before telling them something on this machine does not exist.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fvshulcz\u002Fdeja-vu\u002Fskills\u002Fdeja-search\u002FSKILL.md",[],[119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138],"search","deja search","never","error","ready","memory","re","decide","fix","design","debugging","when","you","done","reviewer","io","change","cli","merge","past",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":145,"publishedAt":53},"01M716A3J2W5SENSE9VGMXB375","deja-reflect","End-of-session reflection and memory curation with deja-vu. Review what was decided, what commands broke and what repaired them, and record durable project rules or decisions with deja remember so the next session starts with them.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Fvshulcz\u002Fdeja-vu\u002Fskills\u002Fdeja-reflect\u002FSKILL.md",[],[146,147,148,134,149,150,151,152,153,154,155,156,157,158,124,159,160,161,162,163],"deja reflect","reflect","review","with","record","github","next","https","node","Rules","decisions","brew","remember","project rules","project","session","end","reflection",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":177,"publishedAt":53},"01M715T3RR4BAYSR57HPPTJ0PF","revid","Make, edit, export and post AI videos with Revid (revid.ai) through the Revid MCP server. Use whenever the user wants a short-form or long-form video made (from an idea, a script, a URL, an article, a PDF, a tweet, a product page, their own clips, or a song), wants to find what is going viral on TikTok, YouTube, Instagram or X before making something, wants to edit or re-export an existing Revid project, generate a standalone AI image or clip, make a series episode, or publish and schedule a finished video to connected social accounts. Covers setup (hosted MCP with OAuth, or an API key), the 36 tools, credits, polling and the rules for publishing. Routes to the more specific revid-* skills when one fits.","https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002Ftmakersas\u002Frevid-skills\u002Fskills\u002Frevid\u002FSKILL.md",[170,173,176],{"categoryNo":171,"categoryName":172,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":174,"categoryName":175,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[166,178,179,180,181,182,183,160,184,125,185,186,187,188,130,189,190,191,47,192],"URL","Video","short-form","standalone","PDF","viral","tiktok","short","social","MCP","song","image","mcp server","schedule","publish"]