| name | bug_fix_protocol |
| description | バグ修正時のリグレッションテスト作成義務と、グローバル状態共有の禁止ルール。 |
バグ修正プロトコル
[!CAUTION]
最重要ルール: テストの Source of Truth は「現在のコード」ではなく「Blueprint(要件仕様)」である。
0. テストの自己正当化(トートロジー)の防止(最重要)
問題の本質
AIが「現在のコードの挙動」を正解としてテストを書くと、バグを保護するテストが出来上がる。
これは通常のバグより遥かに危険で、「テストがパスしている=正しい」という誤った安心感を与え、バグの発見を困難にする。
発生パターン
1. AIが仕様にない挙動を勝手に実装する(例: 全IDにデモデータを返す)
2. テスト作成時、AIが「コードがこう動いているから正しい」と判断
3. テストが「バグの挙動」を期待値として検証するコードになる
4. テストがパスするのでバグが固定化される
絶対ルール
-
テストのアサーションは blueprint.md / README.md の仕様から導出する
- コードを読んで「こう動いているからこう期待する」は禁止
- 仕様が不明確な場合は、テストを書く前にユーザーに確認する
-
仕様が定義されていない挙動を実装する場合
- 実装前にユーザーに「こういう仕様でよいか」を確認する
- 確認後、まず仕様をblueprint.mdに追記してからテスト・実装する
-
既存テストを修正する場合
- 「テストを新仕様に合わせる」前に、元のテストが検証していた仕様が本当に変わったのか確認する
- テストが落ちた=仕様が間違っている可能性と、コードが間違っている可能性の両方を検討する
事例: トートロジー・バグの仕様化(2026-03-13)
- 何が起きたか:
getCreatorData が全creatorIdにデモデータを返す実装に対し、data-flow.test.ts が「デモデータが返ること」をアサーションとして記述。テストがパスしたためバグが長期間放置された。
- 直接原因: 「非デモIDは空データで開始」という仕様がblueprint.mdに書かれておらず、AIがコードの現状を"仕様"とみなしてテストを書いた。
- プロセスの根本原因: Architect(仕様策定者)と Documenter が連携し、ユーザーと仕様を合意するチーム開発プロセスを怠った。 仕様が未定義のデータフロー(「getCreatorDataは各creatorIdに対して何を返すべきか」)について、AIが勝手に判断して実装・テストまで一気に進めてしまった。本来は:
- Architect が
getCreatorData の仕様(IDごとの分岐ルール)を blueprint.md に起案
- Documenter がテストシナリオを策定
- ユーザーに仕様レビューを依頼し合意を取る
- 合意後にテスト→実装の順で進める
という手順を踏むべきだった。
- 教訓: 仕様の空白地帯を見つけたら、AIの裁量で埋めず、必ずユーザーと合意を取る。特にデータフロー・ID分岐・初期状態のような、UIに直結する挙動は仕様合意が必須。
1. リグレッションテストファースト(絶対ルール)
バグを発見・修正する際、以下の順序を必ず守る:
ステップ1: バグを再現するテストを先に書く
- 修正前のコードで確実に失敗するテストを書く
- テスト名にバグの内容を明記する(例:
regression: was returning demo data for ALL IDs)
- テストを実行して失敗を確認する
ステップ2: コードを修正する
ステップ3: 他のテストへの影響を確認する
npm run test で全テスト実行し、既存テストが壊れていないか確認する
- 壊れたテストがあれば、修正前の仕様を前提としていたテスト→新仕様に更新
[!CAUTION]
「修正してからテストを書く」は禁止。 修正後にテストを書くと、テストが本当にバグを検出できるか保証できない。
2. グローバル状態共有の禁止
アンチパターン: モジュールスコープのグローバル変数
let mockStats = { totalRevenue: 500 };
let mockSupportersMap: Record<string, any> = {};
正しいパターン: エンティティIDごとの分離
let creatorDataStore: Record<string, CreatorInMemoryData> = {};
function getCreatorInMemory(creatorId: string): CreatorInMemoryData {
if (!creatorDataStore[creatorId]) {
creatorDataStore[creatorId] = { supportersMap: {}, stats: createInitialStats() };
}
return creatorDataStore[creatorId];
}
チェックリスト
3. テストで検証すべきデータフローの観点
マルチテナント(複数のエンティティIDが存在する)システムでは、以下を必ずテストする:
| 観点 | テスト内容 |
|---|
| データ分離 | entityAへの操作がentityBのデータに影響しないこと |
| 初期状態 | 新規entityは空(またはデフォルト)のデータで開始すること |
| 永続化の整合性 | writeしたデータがreadで正しく返ること |
| リセット | resetが全entityのデータをクリアすること |
| 特殊IDの分岐 | デモ用IDなどの特殊分岐が正しく動作すること |
4. 発生事例と教訓
事例: MockDBClient の creatorId 間データ共有バグ(2026-03-13)
- 症状: ダッシュボードにLP用のデモ支援者31人が表示された。creatorAへの支援追加でcreatorBのstatsも変わった。
- 原因:
mockSupportersMap と mockStats がモジュールスコープのグローバル変数で、全creatorIdで共有されていた。
- 対策:
Record<creatorId, CreatorInMemoryData> 構造に変更し、creatorIdごとに完全分離。
- テスト:
addSupportEvent for creatorA must NOT affect creatorB stats — 修正前は totalRevenue: 500 → 50500 で失敗。