# AI Brain 回歸測試機制實施計劃 - Phase 3

**父計劃**: `.ai/rpi/plans/2025-10-13-ai-brain-regression-testing.md`
**狀態**: Phase 1+2 已完成，Phase 3 待實施
**版本**: 2.0
**最後更新**: 2025-10-13

---

## Phase 3: 統計測試框架（AI 行為回歸測試）

### Overview

建立統計測試框架，透過重複執行真實 AI 修復流程，量化 AI Brain Node 在各種編譯錯誤情境下的修正能力，並建立效能基準線。

**目標**：
- 驗證 AI 實際修復能力（呼叫真實 Claude Code SDK）
- 量化成功率（70% 基準線）
- 建立可重複執行的測試環境
- 為 Prompt 改進提供量化依據

**核心挑戰**：
- AI 行為不確定（同樣錯誤有時成功有時失敗）
- 需要完整 STM32 專案環境（包含真實編譯器）
- 測試時間長（每次測試需真實編譯）

**預估時間**：7-10 天

---

### Current State Analysis

**Phase 1+2 已完成的基礎**：
- ✅ 平台配置系統（支援參數化測試）
- ✅ AI Brain Node 單元測試（96% 覆蓋率）
- ✅ Mock 測試模式（快速驗證邏輯）

**Phase 3 新增的挑戰**：
- ⚠️ 需要真實 Keil 編譯環境（Windows 11 + Keil uVision 5）
- ⚠️ 需要完整 STM32 專案複製機制（214 個檔案）
- ⚠️ 需要錯誤製造工具（動態修改 C 程式碼）
- ⚠️ 需要統計分析工具（成功率計算、信賴區間）
- ⚠️ 測試執行時間長（預估 10 錯誤類型 × 10 次 × 30 秒 = 50 分鐘）

**STM32 實例1 專案資訊**（研究推薦的測試專案）：
- **位置**: `C:\STM32F407\examples\實例1 跑馬燈實例`
- **檔案數量**: 214 個
- **專案大小**: 約 8.5 MB
- **編譯時間**: 約 10-15 秒
- **主程式**: `USER/main.c`（LED 閃爍邏輯）

---

### Desired End State

**Phase 3 完成後的成果**：

1. **測試環境隔離**
   - `tests/integration/fixtures/stm32_project_template/` 存放 STM32 實例1 模板
   - `tests/integration/test_ai_regression.py` 統計測試檔案
   - 每次測試使用獨立的 `tmp_path` 專案副本

2. **錯誤製造工具**
   - `tests/integration/error_injector.py` 模組
   - 支援 10+ 種編譯錯誤類型注入
   - 可逆轉錯誤（恢復原始檔案）

3. **統計測試執行**
   - 每個錯誤類型重複執行 10 次
   - 記錄成功/失敗、執行時間、AI 修改內容
   - 輸出統計報告（成功率、平均執行時間）

4. **效能基準線**
   - `tests/integration/baseline_results.json` 記錄基準線數據
   - 整體成功率 ≥ 70%
   - 每種錯誤類型的成功率分布

---

### What We're NOT Doing

明確排除以下範圍（Phase 4 或更後期）：

1. ❌ **Prompt A/B 測試框架**
   - 不實作不同 Prompt 版本的比較機制
   - 不實作統計顯著性檢驗

2. ❌ **多平台統計測試**
   - 只測試 `stm32_keil` 平台
   - 不建立 ESP32/Nordic 測試環境

3. ❌ **自動化 Prompt 優化**
   - 不實作基於測試結果自動調整 Prompt
   - 不實作機器學習驅動的 Prompt 優化

4. ❌ **長期效能追蹤系統**
   - 不建立歷史數據資料庫
   - 不實作趨勢分析儀表板

5. ❌ **CI/CD 整合**
   - 不自動在 GitHub Actions 執行統計測試
   - 不實作自動化報告生成

---

### Implementation Approach

**高層策略**：

1. **漸進式複雜度**
   - Step 1: 建立專案複製與隔離機制（最基礎）
   - Step 2: 實作錯誤注入工具（可控制測試場景）
   - Step 3: 單次真實 AI 測試（驗證整合）
   - Step 4: 統計測試框架（重複執行）
   - Step 5: 結果分析與報告（量化成果）

2. **保持可控性**
   - 每個錯誤類型獨立測試（失敗不影響其他）
   - 測試失敗時保留現場（不清理 tmp_path）
   - 詳細日誌記錄（AI 修改內容、編譯輸出）

3. **KISS 原則**
   - 使用現有工具（`shutil.copytree`, `pytest.mark.parametrize`）
   - 避免複雜的統計模型（簡單的成功率計算）
   - 手動分析結果（不自動化決策）

4. **為未來擴展預留空間**
   - 結果格式支援版本演進（JSON schema）
   - 錯誤注入工具支援新錯誤類型擴展
   - 測試參數化設計支援多平台

---

### Changes Required

#### 1. 建立 STM32 專案模板 Fixture

**File**: `tests/integration/conftest.py`
**Changes**: 新增 `stm32_project_template` 和 `isolated_stm32_project` fixture

```python
import shutil
from pathlib import Path

import pytest


@pytest.fixture(scope="session")
def stm32_project_template() -> Path:
    """
    STM32 實例1（跑馬燈）專案模板路徑（只讀）。

    Scope: session（整個測試會話共用，避免重複驗證）
    """
    template_path = Path("C:\STM32F407\examples\實例1 跑馬燈實例")

    # 驗證模板存在
    if not template_path.exists():
        pytest.skip(f"STM32 project template not found: {template_path}")

    # 驗證關鍵檔案
    required_files = [
        template_path / "USER" / "main.c",
        template_path / "USER" / "stm32f4xx_it.c",
        template_path / "HARDWARE" / "LED" / "led.c",
    ]
    for file in required_files:
        if not file.exists():
            pytest.skip(f"Required file not found: {file}")

    return template_path


@pytest.fixture
def isolated_stm32_project(tmp_path, stm32_project_template):
    """
    隔離的 STM32 專案環境（每次測試獨立副本）。

    - 複製完整專案到臨時目錄
    - 建立 .fwauto/ 結構
    - 測試完成後自動清理（pytest 自動處理）

    Returns:
        Path: 隔離專案的根目錄
    """
    # 複製專案到臨時目錄
    project_root = tmp_path / "stm32_test_project"
    shutil.copytree(stm32_project_template, project_root, symlinks=False)

    # 建立 .fwauto/ 結構
    fwauto_dir = project_root / ".fwauto"
    fwauto_dir.mkdir(exist_ok=True)
    (fwauto_dir / "build").mkdir(exist_ok=True)
    (fwauto_dir / "flash").mkdir(exist_ok=True)
    (fwauto_dir / "logs").mkdir(exist_ok=True)

    # 建立 config.toml（使用 Keil 編譯器）
    config_toml = fwauto_dir / "config.toml"
    config_toml.write_text(
        """
[build]
tool = "keil"
uvprojx_path = "USER/*.uvprojx"

[flash]
tool = "stlink"
"""
    )

    return project_root
```

**設計考量**：
- `stm32_project_template` 使用 `scope="session"`（整個測試會話共用）
- `isolated_stm32_project` 每次測試獨立副本（`tmp_path` 自動清理）
- 驗證關鍵檔案存在，缺失時跳過測試（`pytest.skip`）

---

#### 2. 實作錯誤注入工具

**File**: `tests/integration/error_injector.py` (新建檔案)
**Changes**: 定義錯誤類型與注入邏輯

```python
"""Error injection utilities for AI regression testing."""

from pathlib import Path
from typing import Literal

ErrorType = Literal[
    "function_name_typo",
    "missing_include",
    "missing_semicolon",
    "undefined_variable",
    "type_mismatch",
    "wrong_parameter_count",
    "bracket_mismatch",
    "comment_syntax_error",
    "duplicate_definition",
    "case_sensitive_error",
]


class ErrorInjector:
    """Inject compilation errors into STM32 project for testing."""

    def __init__(self, project_root: Path):
        """
        Initialize error injector.

        Args:
            project_root: Root directory of the STM32 project
        """
        self.project_root = project_root
        self.main_c = project_root / "USER" / "main.c"
        self.original_content: str | None = None

    def inject_error(self, error_type: ErrorType) -> str:
        """
        Inject specific error type into main.c.

        Args:
            error_type: Type of error to inject

        Returns:
            Expected error message substring

        Raises:
            ValueError: If error_type is not supported
        """
        if not self.main_c.exists():
            raise FileNotFoundError(f"main.c not found: {self.main_c}")

        # Backup original content
        self.original_content = self.main_c.read_text(encoding="utf-8")
        content = self.original_content

        # Inject error based on type
        if error_type == "function_name_typo":
            # delay_ms → Delay_ms (函數名稱拼寫錯誤)
            content = content.replace("delay_ms(", "Delay_ms(")
            expected_error = "'Delay_ms' undeclared"

        elif error_type == "missing_include":
            # 移除 #include "delay.h"
            content = content.replace('#include "delay.h"', "")
            expected_error = "'delay_ms' undeclared"

        elif error_type == "missing_semicolon":
            # 移除第一個 delay_ms 後的分號
            content = content.replace("delay_ms(500);", "delay_ms(500)", 1)
            expected_error = "expected ';'"

        elif error_type == "undefined_variable":
            # 使用未定義的變數
            content = content.replace(
                "while(1)",
                "uint8_t undefined_var = some_undefined_var;\n    while(1)",
            )
            expected_error = "'some_undefined_var' undeclared"

        elif error_type == "type_mismatch":
            # uint32_t → uint8_t (型別不匹配導致範圍錯誤)
            content = content.replace(
                "HAL_Delay(500);", "HAL_Delay((uint8_t)99999);"
            )
            expected_error = "conversion"

        elif error_type == "wrong_parameter_count":
            # 參數數量錯誤
            content = content.replace(
                "delay_ms(500);", "delay_ms(500, 100);"
            )
            expected_error = "too many arguments"

        elif error_type == "bracket_mismatch":
            # 括號不匹配
            content = content.replace("while(1) {", "while(1) {{")
            expected_error = "expected"

        elif error_type == "comment_syntax_error":
            # 註解語法錯誤
            content = content.replace("/* ", "/* Comment \n")
            expected_error = "unterminated comment"

        elif error_type == "duplicate_definition":
            # 重複定義變數
            content = content.replace(
                "int main(void)",
                "int main(void)\n{\n    int i = 0;\n    int i = 1;",
            )
            expected_error = "redefinition"

        elif error_type == "case_sensitive_error":
            # GPIO_PIN_RESET → gpio_pin_reset
            content = content.replace("GPIO_PIN_RESET", "gpio_pin_reset")
            expected_error = "'gpio_pin_reset' undeclared"

        else:
            raise ValueError(f"Unsupported error type: {error_type}")

        # Write modified content
        self.main_c.write_text(content, encoding="utf-8")

        return expected_error

    def restore(self):
        """Restore original main.c content."""
        if self.original_content is not None:
            self.main_c.write_text(self.original_content, encoding="utf-8")
            self.original_content = None

    def get_error_description(self, error_type: ErrorType) -> str:
        """Get human-readable description of error type."""
        descriptions = {
            "function_name_typo": "函數名稱拼寫錯誤（大小寫）",
            "missing_include": "缺少標頭檔案引入",
            "missing_semicolon": "缺少分號",
            "undefined_variable": "使用未定義的變數",
            "type_mismatch": "型別不匹配",
            "wrong_parameter_count": "函數參數數量錯誤",
            "bracket_mismatch": "括號不匹配",
            "comment_syntax_error": "註解語法錯誤",
            "duplicate_definition": "重複定義變數",
            "case_sensitive_error": "大小寫敏感錯誤（常數名稱）",
        }
        return descriptions.get(error_type, "未知錯誤類型")
```

**設計考量**：
- 使用 `Literal` 型別限制錯誤類型（型別安全）
- 每個錯誤類型返回預期的錯誤訊息（驗證編譯失敗）
- 支援恢復原始內容（可逆操作）
- 錯誤描述方便報告生成

---

#### 3. 建立統計測試檔案

**File**: `tests/integration/test_ai_regression.py` (新建檔案)
**Changes**: 實作統計測試框架

```python
"""AI Brain regression tests with real STM32 projects."""

import json
import time
from pathlib import Path

import pytest

from fwauto.nodes.ai_brain import ai_brain_node
from fwauto.nodes.build import build_node
from fwauto.state import FirmwareState
from tests.integration.error_injector import ErrorInjector, ErrorType

# 定義測試的錯誤類型
ERROR_TYPES: list[ErrorType] = [
    "function_name_typo",
    "missing_include",
    "missing_semicolon",
    "undefined_variable",
    "type_mismatch",
    "wrong_parameter_count",
    "bracket_mismatch",
    "comment_syntax_error",
    "duplicate_definition",
    "case_sensitive_error",
]

# 每個錯誤類型重複執行次數
REPETITIONS = 10


@pytest.fixture
def create_test_state(isolated_stm32_project):
    """Create FirmwareState for testing."""

    def _create_state(**overrides) -> FirmwareState:
        base_state: FirmwareState = {
            "user_prompt": "Fix compilation errors",
            "project_root": str(isolated_stm32_project),
            "project_initialized": True,
            "build_status": "pending",
            "build_errors": [],
            "build_log": "",
            "flash_status": "pending",
            "flash_errors": [],
            "flash_log": "",
            "iteration": 0,
            "max_retries": 3,
            "execution_mode": None,
            "command": None,
            "command_args": {},
            "mode_metadata": None,
            "command_error": None,
            "log_file_path": None,
            "log_analysis_result": None,
            "firmware_path": None,
            "platform": "stm32_keil",
        }
        base_state.update(overrides)
        return base_state

    return _create_state


@pytest.mark.slow
@pytest.mark.parametrize("error_type", ERROR_TYPES)
@pytest.mark.parametrize("run_number", range(REPETITIONS))
def test_ai_fixes_error_statistical(
    error_type: ErrorType,
    run_number: int,
    isolated_stm32_project: Path,
    create_test_state,
    tmp_path: Path,
):
    """
    統計測試：AI 修復特定錯誤類型（重複執行以量化成功率）。

    注意：此測試需要：
    1. Windows 11 + Keil uVision 5 環境
    2. 真實 Claude Code SDK 執行（不 Mock）
    3. 完整 STM32 專案結構

    執行時間：約 30 秒/次（10 錯誤 × 10 次 = 100 次，總計約 50 分鐘）
    """
    # 記錄測試開始時間
    start_time = time.time()

    # Step 1: 注入錯誤
    injector = ErrorInjector(isolated_stm32_project)
    expected_error = injector.inject_error(error_type)

    try:
        # Step 2: 初始化 State 並執行編譯（驗證錯誤存在）
        state = create_test_state()
        build_result = build_node(state)

        # 驗證編譯確實失敗
        assert build_result["build_status"] == "error", (
            f"Expected build to fail after injecting {error_type}, "
            f"but it succeeded"
        )
        assert expected_error.lower() in " ".join(build_result["build_errors"]).lower(), (
            f"Expected error '{expected_error}' not found in build errors"
        )

        # Step 3: 執行 AI Brain（真實 SDK 呼叫）
        ai_result = ai_brain_node(build_result)

        # Step 4: 重新編譯驗證修復結果
        final_build = build_node(ai_result)

        # Step 5: 記錄結果
        success = final_build["build_status"] == "success"
        execution_time = time.time() - start_time

        # 保存詳細結果到 JSON
        result_data = {
            "error_type": error_type,
            "run_number": run_number,
            "success": success,
            "execution_time": execution_time,
            "ai_responses": ai_result.get("responses", []),
            "final_build_errors": final_build.get("build_errors", []),
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
        }

        # 寫入結果檔案
        results_dir = tmp_path / "regression_results"
        results_dir.mkdir(exist_ok=True)
        result_file = results_dir / f"{error_type}_run{run_number}.json"
        result_file.write_text(json.dumps(result_data, indent=2, ensure_ascii=False))

        # 斷言：不直接失敗，而是記錄（統計測試）
        # 最終成功率由 test_overall_success_rate() 驗證

    finally:
        # 恢復原始檔案（無論測試成功或失敗）
        injector.restore()


@pytest.mark.slow
def test_overall_success_rate(tmp_path: Path):
    """
    驗證整體成功率 >= 70%（基準線）。

    此測試應在所有統計測試完成後執行。
    """
    results_dir = tmp_path / "regression_results"

    # 如果沒有結果檔案，跳過測試
    if not results_dir.exists():
        pytest.skip("No regression test results found")

    # 載入所有結果
    results = []
    for result_file in results_dir.glob("*.json"):
        results.append(json.loads(result_file.read_text()))

    if not results:
        pytest.skip("No regression test results found")

    # 計算整體成功率
    total_tests = len(results)
    successful_tests = sum(1 for r in results if r["success"])
    success_rate = successful_tests / total_tests

    # 計算每個錯誤類型的成功率
    error_type_stats = {}
    for result in results:
        error_type = result["error_type"]
        if error_type not in error_type_stats:
            error_type_stats[error_type] = {"total": 0, "success": 0}
        error_type_stats[error_type]["total"] += 1
        if result["success"]:
            error_type_stats[error_type]["success"] += 1

    # 生成報告
    print("\n" + "=" * 60)
    print("AI Brain Regression Test Report")
    print("=" * 60)
    print(f"Total Tests: {total_tests}")
    print(f"Successful: {successful_tests}")
    print(f"Failed: {total_tests - successful_tests}")
    print(f"Overall Success Rate: {success_rate:.1%}")
    print("\nPer Error Type:")
    print("-" * 60)
    for error_type, stats in sorted(error_type_stats.items()):
        rate = stats["success"] / stats["total"]
        print(f"  {error_type:30s} {stats['success']:2d}/{stats['total']:2d} ({rate:.1%})")
    print("=" * 60)

    # 斷言：整體成功率 >= 70%
    assert success_rate >= 0.70, (
        f"Overall success rate {success_rate:.1%} is below 70% baseline. "
        f"This indicates the AI Brain needs prompt improvements."
    )
```

**設計考量**：
- 使用 `@pytest.mark.slow` 標記長時間測試
- `@pytest.mark.parametrize` 實現參數化測試（10 錯誤 × 10 次 = 100 個測試）
- 結果保存為 JSON（結構化數據，易於分析）
- 獨立的成功率驗證測試（`test_overall_success_rate`）

---

#### 4. 建立測試執行腳本

**File**: `scripts/run_regression_tests.sh` (新建檔案)
**Changes**: 簡化測試執行流程

```bash
#!/bin/bash
# Run AI Brain regression tests

set -e

echo "====================================="
echo "AI Brain Regression Tests"
echo "====================================="
echo ""

# 檢查環境
echo "Checking environment..."
if ! command -v pytest &> /dev/null; then
    echo "❌ pytest not found. Please install: pip install pytest pytest-cov"
    exit 1
fi

if [ ! -d "C:\STM32F407\examples\實例1 跑馬燈實例" ]; then
    echo "❌ STM32 project template not found"
    exit 1
fi

echo "✓ Environment OK"
echo ""

# 執行測試
echo "Running regression tests (this will take ~50 minutes)..."
echo ""

pytest tests/integration/test_ai_regression.py \
    -v \
    -m slow \
    --tb=short \
    --maxfail=5 \
    | tee regression_test_output.log

echo ""
echo "====================================="
echo "Test completed. Check regression_test_output.log for details."
echo "====================================="
```

**使用方式**：
```bash
chmod +x scripts/run_regression_tests.sh
./scripts/run_regression_tests.sh
```

---

### Success Criteria

#### Automated Verification

- [ ] STM32 專案模板複製成功: `pytest tests/integration/test_ai_regression.py::test_ai_fixes_error_statistical[function_name_typo-0] -v`
- [ ] 錯誤注入工具正常運作: 手動執行 `ErrorInjector` 並驗證編譯失敗
- [ ] 單次 AI 修復測試通過: 執行單一參數化測試確認流程
- [ ] 統計測試完整執行: `pytest tests/integration/test_ai_regression.py -m slow -v`
- [ ] 整體成功率 >= 70%: `test_overall_success_rate` 測試通過

#### Manual Verification

- [ ] 檢查測試執行時間（預估 50 分鐘）是否合理
- [ ] 檢查 JSON 結果檔案格式正確（`tmp_path/regression_results/*.json`）
- [ ] 檢查統計報告輸出清晰易讀
- [ ] 測試失敗時，檢查保留的專案副本（除錯用）
- [ ] 驗證 Keil 編譯器正常運作（真實編譯）

**Implementation Note**: 完成 Phase 3 所有自動驗證與手動驗證後，分析成功率數據並向用戶報告。如果成功率低於 70%，需要調整 Prompt 或錯誤類型。

---

### Testing Strategy

**測試分層**：

```
Phase 3 統計測試（真實 AI + 真實編譯）
    ↓
Phase 2 單元測試（Mock AI + Mock 編譯）
    ↓
Phase 1 平台配置（純邏輯測試）
```

**執行策略**：

1. **開發階段**：只執行 Phase 2 單元測試（快速回饋）
2. **本地驗證**：執行少量 Phase 3 測試（1-2 個錯誤類型）
3. **完整驗證**：執行全部 Phase 3 測試（Prompt 變更前後）

**結果解讀**：

| 成功率 | 判斷 | 行動 |
|-------|------|------|
| >= 80% | 優秀 | Prompt 無需調整 |
| 70-80% | 合格 | 持續監控，可選調整 |
| 60-70% | 警告 | 需要調整 Prompt |
| < 60% | 不合格 | 必須調整 Prompt 或停止條件 |

---

### Performance Considerations

**測試執行時間估算**：

| 項目 | 時間 | 說明 |
|------|------|------|
| 錯誤注入 | 0.1 秒 | 檔案修改 |
| 編譯驗證 | 10 秒 | Keil 編譯 |
| AI 修復 | 15 秒 | Claude Code SDK 呼叫 |
| 重新編譯 | 10 秒 | 驗證修復結果 |
| **單次測試總計** | **35 秒** | |
| **全部測試** | **58 分鐘** | 100 次 × 35 秒 |

**優化策略**：

1. **並行執行**（需要評估）：
   - 使用 `pytest-xdist`: `pytest -n 4`
   - 風險：Keil 編譯器可能不支援並行（需驗證）

2. **部分測試**（開發階段）：
   - 只執行 P0 錯誤類型（5 個）
   - 減少重複次數（10 次 → 5 次）

3. **快取機制**（Phase 4）：
   - 記錄 Prompt 版本 hash
   - 相同 Prompt 跳過測試

---

### Migration Notes

**新增依賴**：

```bash
# 無新增 Python 依賴（使用標準庫）
# 但需要確保環境：
# 1. Windows 11 + WSL（如果在 Linux 執行測試）
# 2. Keil uVision 5（c:\Keil_v5\UV4\uv4.exe）
# 3. STM32 專案模板（C:\STM32F407\examples\實例1 跑馬燈實例）
```

**pytest 配置**：

在 `pyproject.toml` 或 `pytest.ini` 中新增：

```ini
[pytest]
markers =
    slow: marks tests as slow (deselect with '-m "not slow"')
```

**跳過統計測試**（開發階段）：

```bash
# 只執行快速測試（跳過 Phase 3）
pytest -m "not slow"
```

---

### Open Questions

1. **Keil 編譯器授權**
   - CI/CD 環境是否有 Keil 授權？
   - 是否需要替代方案（ARM GCC）？

2. **測試環境隔離**
   - 並行執行是否安全？（Keil 編譯器鎖）
   - 是否需要 Docker 容器隔離？

3. **結果數據管理**
   - JSON 檔案是否需要版本控制？
   - 還是使用 SQLite 資料庫？

4. **失敗案例分析**
   - 需要人工檢視每個失敗案例嗎？
   - 還是只看整體統計？

5. **Prompt 版本追蹤**
   - 如何關聯測試結果與 Prompt 版本？
   - 需要在結果 JSON 中記錄 Prompt hash 嗎？

---

### 實施檢查清單

#### Phase 3: 統計測試框架

- [ ] **Step 3.1**: 修改 `tests/integration/conftest.py` 新增 `stm32_project_template` 和 `isolated_stm32_project` fixture
- [ ] **Step 3.2**: 建立 `tests/integration/error_injector.py` 並實作 10 種錯誤類型
- [ ] **Step 3.3**: 驗證錯誤注入工具：手動測試每種錯誤類型能正確觸發編譯失敗
- [ ] **Step 3.4**: 建立 `tests/integration/test_ai_regression.py` 統計測試框架
- [ ] **Step 3.5**: 執行單次測試驗證流程: `pytest tests/integration/test_ai_regression.py::test_ai_fixes_error_statistical[function_name_typo-0] -v`
- [ ] **Step 3.6**: 執行小規模測試（2 錯誤 × 3 次）驗證統計邏輯
- [ ] **Step 3.7**: 執行完整統計測試（10 錯誤 × 10 次）
- [ ] **Step 3.8**: 分析成功率報告，記錄基準線數據
- [ ] **Step 3.9**: 建立 `scripts/run_regression_tests.sh` 簡化執行流程
- [ ] **Step 3.10**: 更新 `pytest.ini` 新增 `slow` marker
- [ ] **Step 3.11**: 提交 Phase 3 變更

---

## References

- **父計劃**: `.ai/rpi/plans/2025-10-13-ai-brain-regression-testing.md`
- **原始研究文檔**: `.ai/rpi/research/2025-10-13-ai-behavior-regression-testing.md`
- **STM32 專案位置**: `C:\STM32F407\examples\實例1 跑馬燈實例`
- **Keil 編譯器**: `c:\Keil_v5\UV4\uv4.exe`

---

**Phase 3 預估工作量**: 7-10 天
**Phase 3 測試執行時間**: 約 58 分鐘（全部測試）
**下一步**: 等待用戶確認 Phase 3 計劃後，開始執行實施
