# FWAuto 架構簡化：移除未使用欄位實施計劃

## Overview

基於架構簡化研究（`.ai/rpi/research/2025-10-11-architecture-simplification-opportunities.md`），本計劃旨在移除 FWAuto 中三個完全未使用的欄位：

1. **`project_number`** - FirmwareState 中的遺留欄位，總是設為 `None`
2. **`project_name`** - 僅用於單一顯示，可改用目錄名稱
3. **`project.description`** - config.toml 中完全未使用的欄位

**預期收益**：
- 簡化 FirmwareState schema（移除冗餘欄位）
- 減少使用者輸入負擔（不再詢問 project_name）
- 精簡配置檔案（移除未使用配置項）
- 提升程式碼可維護性

**風險評估**：🟢 低風險 - 所有欄位均無功能性依賴

## Current State Analysis

### 1. project_number 使用情況

**定義位置**：
- `src/fwauto/state.py:39` - FirmwareState TypedDict 欄位

**初始化位置**（總是設為 `None`）：
- `src/fwauto/cli.py:79` - build 命令
- `src/fwauto/cli.py:117` - flash 命令
- `src/fwauto/cli.py:155` - run 命令
- `src/fwauto/cli.py:205` - log 命令

**測試使用**：
- `tests/nodes/test_build_makefile.py:17, 29`
- `tests/nodes/test_flash_makefile.py:17`
- `tests/integration/test_build_integration.py:14, 26`
- `tests/integration/test_flash_integration.py:15`
- `tests/test_story_004_log_analysis_node.py:65`
- `tests/test_story_006_error_handling.py:35, 71, 119`

**發現**：
- ❌ 無任何 node 讀取此欄位
- ❌ 無任何 routing 邏輯依賴
- ✅ 可安全移除

### 2. project_name 使用情況

**配置定義**：
- `src/fwauto/config.py:72-73` - ProjectConfig.project_name property
- `src/fwauto/config.py:67` - 配置驗證檢查
- `src/fwauto/config.py:141` - create_default_config 寫入

**使用位置**：
- `src/fwauto/nodes/init.py:38` - **唯一使用**：`print(f"📦 Project: {config.project_name}")`
- `src/fwauto/cli_commands/init.py:74` - 互動式詢問

**發現**：
- 🟡 僅用於單一顯示目的
- ✅ 可改用 `Path(project_root).name` 顯示目錄名稱
- ✅ 移除後可減少使用者輸入

### 3. project.description 使用情況

**配置定義**：
- `src/fwauto/config.py:142` - create_default_config 寫入

**發現**：
- ❌ **完全未使用** - 無任何程式碼讀取此欄位
- ✅ 可直接移除

### Key Discoveries

- **FirmwareState schema 冗餘**：`project_number` 欄位定義但從未被讀取
- **不必要的使用者輸入**：`project_name` 只為了一行 print 語句
- **配置檔案膨脹**：`project.description` 從未被使用
- **測試 fixtures 遺留**：所有測試中的 `project_number` 僅為滿足 TypedDict schema
- **向後相容性無虞**：現有專案的 config.toml 即使包含這些欄位也不影響運作（會被忽略）

## Desired End State

### 簡化後的 FirmwareState

```python
class FirmwareState(TypedDict):
    user_prompt: str
    project_root: str
    # project_number 已移除 ✓
    project_initialized: bool

    build_status: Literal["success", "error", "pending"]
    build_errors: list[str]
    build_log: str
    # ... 其他欄位保持不變
```

### 簡化後的 config.toml

```toml
# 空白配置檔案 - 所有設定使用預設值
# build 和 flash 路徑由 ProjectConfig 屬性提供預設值
```

**或者（如果需要自訂路徑）**：

```toml
[build]
makefile = ".fwauto/custom-build/Makefile"

[flash]
makefile = ".fwauto/custom-flash/Makefile"
```

### 簡化後的 init 流程

```python
def run_init_wizard(project_root: Path | None = None) -> bool:
    # 不再詢問 project_name
    # 直接建立目錄和檔案

    fwauto_dir.mkdir(exist_ok=True)
    create_default_config(project_root)  # 不需要 project_name 參數
    # ...
```

### 簡化後的顯示

```python
# nodes/init.py
print(f"✅ Found project root: {project_root}")
print(f"📦 Project: {Path(project_root).name}")  # 使用目錄名稱
```

### 驗證方式

**Automated Verification**：
- [ ] 所有單元測試通過：`pytest tests/nodes/`
- [ ] 所有整合測試通過：`pytest tests/integration/`
- [ ] 型別檢查通過：`mypy src/fwauto/`
- [ ] 程式碼風格檢查通過：`ruff check src/`

**Manual Verification**：
- [ ] 執行 `fwauto init` 不再詢問 project_name
- [ ] 執行 `fwauto build` 正常顯示專案名稱（目錄名）
- [ ] 現有專案的 config.toml 仍可正常運作（忽略舊欄位）
- [ ] 新建專案的 config.toml 不包含 name 和 description

## What We're NOT Doing

- ❌ **不實作 config.toml 遷移工具** - 舊欄位會被忽略，無需主動遷移
- ❌ **不移除 config.toml 檔案本身** - 仍需要用於指定 Makefile 路徑
- ❌ **不修改 Makefile templates** - 工具路徑配置不受影響
- ❌ **不改變 .fwauto/ 目錄結構** - 只改變 config.toml 內容
- ❌ **不修改 workflow routing 邏輯** - 這些欄位本來就沒被使用

## Implementation Approach

採用**一次性批量修改**策略：

1. **核心程式碼優先**：先修改 state.py、config.py、nodes/init.py
2. **CLI 與測試同步**：同時更新 CLI 命令和所有測試
3. **單次測試驗證**：所有修改完成後執行完整測試套件
4. **向後相容處理**：確保舊 config.toml 不會導致錯誤

**優點**：
- 避免多次測試執行
- 減少中間不一致狀態
- 一次性解決所有相關問題

## Phase 1: 移除所有未使用欄位

### Overview

一次性移除 `project_number`、`project_name`、`project.description` 三個欄位，並更新所有相關檔案。

### Changes Required

#### 1. State Schema 簡化

**File**: `src/fwauto/state.py`

**Changes**: 移除 `project_number` 欄位定義及文檔

```python
# 移除第 39 行
- project_number: Annotated[str | None, "Project identifier (optional in Phase 2+, e.g., '04' for 實例04)"]

# 更新文檔（第 16 行附近）
- project_number: Project identifier (e.g., "04" for 實例04)
```

#### 2. Config 模組簡化

**File**: `src/fwauto/config.py`

**Changes**:
1. 移除 `project_name` property
2. 移除配置驗證中的 `project.name` 檢查
3. 簡化 `create_default_config` 函數

```python
# 移除 property（第 72-73 行）
- @property
- def project_name(self) -> str:
-     return self.data["project"]["name"]

# 移除驗證（第 64-67 行）
- # 驗證必要欄位
- project = self.data["project"]
- if "name" not in project:
-     raise ConfigError("Missing project.name")

# 簡化 _validate 方法
def _validate(self) -> None:
    """Validate configuration schema."""
-   # 驗證必要 section
-   if "project" not in self.data:
-       raise ConfigError("Missing [project] section")
-
-   # 驗證必要欄位
-   project = self.data["project"]
-   if "name" not in project:
-       raise ConfigError("Missing project.name")
-
-   # build 和 flash section 是可選的，有預設值
+   # Config 所有欄位都是可選的，使用預設值
+   pass

# 修改 create_default_config 簽名和實作（第 130-149 行）
- def create_default_config(project_root: Path, project_name: str) -> None:
+ def create_default_config(project_root: Path) -> None:
    """Create default .fwauto/config.toml.

-   最小化配置，只包含必要的 project 資訊。
-   build 和 flash 使用預設值，不需要在 config 中指定。
+   空白配置，所有設定使用預設值。
+   build 和 flash 路徑由 ProjectConfig 屬性提供。
    """
    config_dir = project_root / ".fwauto"
    config_dir.mkdir(exist_ok=True)

-   config_data = {
-       "project": {
-           "name": project_name,
-           "description": "STM32 Firmware Project",
-       },
-   }
+   # 空白配置 - 所有設定使用預設值
+   config_data = {}

    config_path = config_dir / "config.toml"
    with open(config_path, "wb") as f:
        tomli_w.dump(config_data, f)
```

#### 3. Init Project Node 更新

**File**: `src/fwauto/nodes/init.py`

**Changes**: 使用目錄名稱顯示專案資訊

```python
# 修改第 35-38 行
try:
    # Initialize logging with project directory
    init_project_logging(project_root)

-   # Load project configuration
-   config = load_project_config(project_root)
    print(f"✅ Found project root: {project_root}")
-   print(f"📦 Project: {config.project_name}")
+   print(f"📦 Project: {project_root.name}")

+   # Load project configuration (驗證 config.toml 存在)
+   load_project_config(project_root)

    return {
```

#### 4. Init Wizard 簡化

**File**: `src/fwauto/cli_commands/init.py`

**Changes**: 移除 project_name 互動詢問

```python
# 修改 run_init_wizard 函數（第 52-120 行）
def run_init_wizard(project_root: Path | None = None) -> bool:
    """
    Run simplified initialization wizard.

-   只詢問 project name，使用 minimal template 作為預設。
+   自動建立配置，無需詢問任何資訊。

    Returns:
        True if initialization succeeded, False otherwise
    """
    if project_root is None:
        project_root = Path.cwd()

    console.print("\n[cyan]🚀 FWAuto Project Initialization[/cyan]\n")

    # 檢查是否已存在 .fwauto/
    fwauto_dir = project_root / ".fwauto"
    if fwauto_dir.exists():
        if not Confirm.ask("[yellow].fwauto/ directory already exists. Overwrite?[/yellow]", default=False):
            console.print("[yellow]Initialization cancelled.[/yellow]")
            return False

-   # 只詢問專案名稱
-   project_name = Prompt.ask("Project name", default=project_root.name)

    console.print("\n[bold]Creating project files...[/bold]")

    try:
        # 建立 .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
-       create_default_config(project_root, project_name)
+       create_default_config(project_root)
        console.print("[green]✓ Created .fwauto/config.toml[/green]")

        # ... 其餘保持不變
```

#### 5. CLI 命令更新

**File**: `src/fwauto/cli.py`

**Changes**: 移除所有 CLI 命令中的 `"project_number": None` 初始化

```python
# 修改 build 命令（第 76-97 行）
state: FirmwareState = {
    "user_prompt": "build",
    "project_root": "",
-   "project_number": None,
    "project_initialized": False,
    # ... 其餘保持不變
}

# 修改 flash 命令（第 114-135 行）
state: FirmwareState = {
    "user_prompt": "flash",
    "project_root": "",
-   "project_number": None,
    "project_initialized": False,
    # ... 其餘保持不變
}

# 修改 run 命令（第 152-173 行）
state: FirmwareState = {
    "user_prompt": "run",
    "project_root": "",
-   "project_number": None,
    "project_initialized": False,
    # ... 其餘保持不變
}

# 修改 log 命令（第 202-220 行）
state: FirmwareState = {
    "user_prompt": prompt,
    "project_root": "",
-   "project_number": None,
    "project_initialized": False,
    # ... 其餘保持不變
}
```

#### 6. 測試檔案更新

**Files**:
- `tests/nodes/test_build_makefile.py`
- `tests/nodes/test_flash_makefile.py`
- `tests/integration/test_build_integration.py`
- `tests/integration/test_flash_integration.py`
- `tests/test_story_004_log_analysis_node.py`
- `tests/test_story_006_error_handling.py`

**Changes**: 移除所有 test fixtures 中的 `project_number` 欄位

**範例** (`tests/nodes/test_build_makefile.py`):

```python
@pytest.fixture
def base_state() -> FirmwareState:
    return {
        "user_prompt": "build",
        "project_root": "",
-       "project_number": "04",
        "project_initialized": False,
        "build_status": "pending",
        "build_errors": [],
        "build_log": "",
        "flash_status": "pending",
        "flash_errors": [],
        "flash_log": "",
        "iteration": 0,
        "max_retries": 3,
        "execution_mode": "build",
        "command": "build",
-       "command_args": {"project_number": "04"},
+       "command_args": {},
        "mode_metadata": None,
        "command_error": None,
        "log_file_path": None,
        "log_analysis_result": None,
        "firmware_path": None,
    }
```

**重複相同的修改模式於所有測試檔案**。

#### 7. 整合測試 Config Fixture 更新

**File**: `tests/integration/conftest.py`

**Changes**: 移除測試配置中的 `project.name` 欄位

```python
# 修改 tmp_project fixture（約第 47 行）
config_content = """
- [project]
- name = "test_project"
"""
+ # 空白配置 - 使用預設值
+ """
+ """
```

### Success Criteria

#### Automated Verification

- [x] **型別檢查通過**: `mypy src/fwauto/` - 確認 FirmwareState 變更無型別錯誤
- [x] **單元測試通過**: `pytest tests/nodes/ -v` - 驗證 nodes 邏輯正確
- [x] **整合測試通過**: `pytest tests/integration/ -v` - 驗證端到端流程
- [x] **Story 測試通過**: `pytest tests/test_story*.py -v` - 驗證使用情境
- [x] **程式碼風格檢查**: `ruff check src/ tests/` - 確保程式碼品質
- [x] **Config 可選驗證**: 測試空白 config.toml 可正常載入

#### Manual Verification

- [ ] **Init 流程簡化**: 執行 `fwauto init`，確認不再詢問 project_name
- [ ] **專案名稱顯示**: 執行 `fwauto build`，確認顯示目錄名稱而非 config 中的名稱
- [ ] **Config 產生**: 檢查 `.fwauto/config.toml`，確認為空白檔案或只包含自訂設定
- [ ] **舊專案相容**: 使用包含 `project.name` 的舊 config.toml，確認仍可正常運作（被忽略）
- [ ] **無回歸**: 執行 build、flash、run 命令，確認功能正常

**Implementation Note**: 所有自動化驗證完成後，執行手動驗證確認使用者體驗符合預期。

---

## Testing Strategy

### Unit Tests

測試重點：
- **State schema 完整性**: 確認移除 `project_number` 後所有必要欄位仍存在
- **Config 載入**: 測試空白 config.toml 和包含舊欄位的 config.toml 都能正常載入
- **專案名稱顯示**: 驗證使用 `Path.name` 取得正確的目錄名稱

### Integration Tests

測試重點：
- **完整 workflow**: build → flash 流程在簡化後的 state 下運作正常
- **Init wizard**: 新建專案流程無需輸入即可完成
- **錨點查找**: `find_project_root()` 功能不受影響

### Manual Testing Steps

1. **測試新專案初始化**:
   ```bash
   mkdir test-project
   cd test-project
   fwauto init
   # 確認：不詢問 project_name
   # 確認：.fwauto/config.toml 為空白或極簡
   ```

2. **測試專案名稱顯示**:
   ```bash
   fwauto build
   # 確認：顯示 "📦 Project: test-project"（目錄名）
   ```

3. **測試舊專案相容性**:
   ```bash
   # 手動編輯 .fwauto/config.toml 加入舊欄位
   echo '[project]
   name = "old-name"
   description = "old description"' > .fwauto/config.toml

   fwauto build
   # 確認：正常運作，顯示目錄名稱（不是 old-name）
   ```

4. **測試 CLI 命令完整性**:
   ```bash
   fwauto build    # 測試 build
   fwauto flash    # 測試 flash
   fwauto run      # 測試 build + flash
   fwauto log "test" --log-path logs/test.log  # 測試 log
   # 確認：所有命令正常執行
   ```

## Performance Considerations

**無效能影響**：
- 移除欄位不影響執行速度
- Config 檔案更小，載入更快（微乎其微）
- 減少互動輸入，init 流程更快

## Migration Notes

### 對現有專案的影響

**向後相容策略**：
- ✅ 舊的 config.toml 包含 `project.name` 和 `description` 不會導致錯誤
- ✅ 這些欄位會被忽略（不讀取）
- ✅ 使用者無需手動修改現有專案
- ℹ️ 建議：新專案使用簡化的 config，舊專案可選擇性清理

### 給使用者的遷移指引

**不需要遷移**，但如果想清理舊專案的 config.toml：

```bash
# 選項 1: 刪除並重新初始化
rm -rf .fwauto/
fwauto init

# 選項 2: 手動清理 config.toml
# 移除 [project] section 或整個檔案內容
echo "" > .fwauto/config.toml
```

### 文件更新

需要更新的文檔：
- `README.md` - 更新 init 流程說明（移除 project_name 輸入提示）
- `docs/*.md` - 更新 config.toml 範例（移除 project section）

## References

- **原始研究**: `.ai/rpi/research/2025-10-11-architecture-simplification-opportunities.md`
- **相關研究**: `.ai/rpi/research/2025-10-11-init-project-name-usage.md`
- **Config 模組**: `src/fwauto/config.py:40-149`
- **State 定義**: `src/fwauto/state.py:6-73`
- **Init Node**: `src/fwauto/nodes/init.py:10-55`
- **Init Wizard**: `src/fwauto/cli_commands/init.py:52-120`

---

## 計劃核對清單

### 計劃完成前確認

- [x] ✅ 遵守 KISS 原則 - 採用最簡單直接的方式移除未使用欄位
- [x] ✅ 深思熟慮 - 分析所有影響範圍，確保無遺漏
- [x] ✅ 詳細規劃 - 提供明確的修改步驟和程式碼範例
- [x] ✅ 無未解決問題 - 所有決策已確認（一次性修改、向後相容、測試策略）
- [x] ✅ 在 Plan Mode - 僅制定計劃，不進行實作

### 實施前確認事項

- [ ] 使用者確認計劃內容正確無誤
- [ ] 確認測試環境可用
- [ ] 確認有備份或在 git 分支上操作

**⚠️ 重要提醒**：本計劃已遵守所有規範，等待您的確認後即可執行 `/rpi:implement` 開始實施。
