---
date: 2025-11-12T12:42:10+08:00
researcher: Claude (Sonnet 4.5)
git_commit: 38350423462bcfcac3b6b823571b82d8f86574b2
branch: deploy
repository: FWAuto
topic: "Flash Node 重新設計為 Deploy Node 的可行性研究"
tags: [research, codebase, flash_node, deploy_node, am62x, architecture, decision_record]
status: complete
last_updated: 2025-11-12T13:00:00+08:00
last_updated_by: Claude (Sonnet 4.5)
last_updated_note: "Added Decision Record section with all strategic decisions"
---

# Research: Flash Node 重新設計為 Deploy Node 的可行性研究

**Date**: 2025-11-12T12:42:10+08:00
**Researcher**: Claude (Sonnet 4.5)
**Git Commit**: 38350423462bcfcac3b6b823571b82d8f86574b2
**Branch**: deploy
**Repository**: FWAuto

## Research Question

FWAuto 的 `flash_node` 原本設計用於將韌體燒錄到 STM32 開發板。但在 AM62x 開發流程中，開發板執行 Linux OS，執行方式是透過 SCP 複製程式到遠端，再透過 SSH 執行。這不再是傳統的「燒錄 (flash)」動作，而是「部署 (deploy)」。

**核心問題**：是否應該將 `flash_node` 重新命名為更通用的 `deploy_node`，以涵蓋：
- **STM32 平台**：傳統的韌體燒錄（JTAG/ST-LINK）
- **AM62x 平台**：SCP copy + SSH execute（部署）

本研究探索現有架構中與 flash 相關的所有面向，分析重新命名的影響範圍和技術可行性。

---

## Summary

經過全面的程式碼庫探索，發現以下關鍵事實：

### 核心發現

1. **Flash Node 已經支援兩種截然不同的操作**：
   - **STM32**：透過 Makefile 調用 PowerShell 執行 ST-LINK CLI 燒錄
   - **AM62x**：透過 Python SSH 模組執行 SCP + SSH 遠端部署

2. **命名與實作的語義鴻溝**：
   - 程式碼中已經使用 `deploy` 相關術語（`deploy_path`, `deploy_binary`）
   - Flash operations 模組的註解寫著 "SSH-based deployment logic"
   - 實際行為是「部署」而非「燒錄」

3. **影響範圍廣泛但結構清晰**：
   - **State 欄位**：`flash_status`, `flash_errors`, `flash_log`
   - **Graph Routing**：`route_after_flash`, `flash` node
   - **Config 屬性**：deployment_config 已經存在，但 flash_makefile 仍使用舊名
   - **測試檔案**：13+ 個單元測試使用 `flash` 命名

4. **歷史脈絡支持重構**：
   - 2025-11-06 實施的 AM62x deployment 系統已經奠定 "deploy" 概念基礎
   - Config 系統已經使用 `deployment_config` 命名
   - 最近的改進都圍繞「部署參數」而非「燒錄參數」

---

## Detailed Findings

### 1. Flash Node 的當前角色與責任

**檔案位置**：`src/fwauto/nodes/flash.py` (第 48-202 行)

#### 核心流程

```mermaid
graph TD
    A["flash_node(state)"] --> B["驗證專案初始化"]
    B --> C["載入 ProjectConfig"]
    C --> D{"平台類型"}
    D -->|AM62x| E["Python flash_operations"]
    D -->|STM32| F["Makefile + PowerShell"]
    E --> G["SCP 部署 + SSH 執行"]
    F --> H["ST-LINK CLI 燒錄"]
    G --> I["更新 State"]
    H --> I
    I --> J["返回結果"]
```

#### 關鍵發現

| 面向 | 發現 | 位置 |
|------|------|------|
| **函數名稱** | `flash_node` | flash.py:48 |
| **實際操作** | AM62x: `flash_firmware()` 執行 SCP+SSH<br>STM32: Makefile 執行 ST-LINK | flash.py:150, flash_operations.py:363 |
| **錯誤處理** | 使用 `flash_status`, `flash_errors`, `flash_log` | flash.py:165-182 |
| **配置來源** | `config.deployment_config` (已經使用 deploy 術語) | flash.py:86, config.py:109 |
| **參數驗證** | 驗證 `binary_args` 的 shell injection | flash.py:104-115 |
| **日誌持久化** | 將遠端日誌路徑寫回 config.toml | flash.py:156-162 |

**語義矛盾**：
- 函數名稱是 `flash_node`
- 實際行為是 `deploy_binary` + `execute_on_board`（flash_operations.py:177, 220）
- 註解寫著 "Flash firmware using pure Python operations"，但實作是 SSH deployment

---

### 2. FirmwareState 中的 Flash 相關欄位

**檔案位置**：`src/fwauto/state.py` (第 44-46 行)

#### State Schema

```python
class FirmwareState(TypedDict):
    # Flash 相關欄位
    flash_status: Literal["success", "error", "pending"]  # 第 44 行
    flash_errors: list[str]                              # 第 45 行
    flash_log: str                                       # 第 46 行
```

#### 使用位置

| 欄位 | 讀取位置 | 寫入位置 | 用途 |
|------|---------|---------|------|
| `flash_status` | graph.py:122 | flash.py:166, 179 | 決定 workflow routing |
| `flash_errors` | - | flash.py:167, 180 | 錯誤訊息列表 |
| `flash_log` | - | flash.py:168, 181 | 完整日誌輸出 |

**影響範圍**：
- `graph.py` 的 `route_after_flash` 函數（第 120-127 行）
- 所有測試檔案中的 mock state（`test_flash_makefile.py:11-34`）

---

### 3. Graph Routing 中的 Flash 路由

**檔案位置**：`src/fwauto/graph.py`

#### Routing Functions

```mermaid
graph LR
    A[START] -->|flash mode| B[flash node]
    C[build node] -->|run mode & success| B
    B -->|success| D[END]
    B -->|error| D
```

#### 關鍵路由邏輯

| 函數名稱 | 位置 | 路由決策 |
|---------|------|---------|
| `route_from_start` | 第 32-68 行 | `"flash": "flash"` (第 58 行) |
| `route_after_init` | 第 70-90 行 | `"flash": "flash"` (第 82 行) |
| `route_after_build` | 第 92-112 行 | `return "flash"` (第 98 行) |
| `route_after_flash` | 第 120-127 行 | 總是返回 `"end"` |

**命名發現**：
- Node 名稱：`"flash"` (第 28 行)
- Routing key：`"flash"` (多處)
- Routing 函數：`route_after_flash` (第 120 行)
- Edge definition：`workflow.add_conditional_edges("flash", ...)` (第 181 行)

**影響**：重新命名需要同步更新所有這些位置。

---

### 4. Config 系統中的命名矛盾

**檔案位置**：`src/fwauto/config.py`

#### 現有命名混用

```mermaid
graph TD
    A[ProjectConfig] --> B[deployment_config]
    A --> C[flash_makefile]
    A --> D[flash_target]
    B --> E["board_ip, deploy_path<br/>(使用 deploy 術語)"]
    C --> F[".fwauto/flash/Makefile<br/>(使用 flash 術語)"]
```

#### 詳細對照表

| 屬性名稱 | 位置 | 使用術語 | 實際用途 |
|---------|------|---------|---------|
| `deployment_config` | config.py:109 | **deploy** | AM62x 部署參數（board_ip, deploy_path） |
| `board_ip` | config.py:131 | deploy | SSH 連線 IP |
| `board_user` | config.py:136 | deploy | SSH 登入使用者 |
| `deploy_path` | config.py:141 | **deploy** | 遠端部署目錄 |
| `flash_makefile` | - | **flash** | Makefile 路徑（STM32 使用） |
| `flash_target` | - | **flash** | Makefile target 名稱 |

**矛盾點**：
- 同一個 config 物件混用 `deployment_config` 和 `flash_makefile`
- AM62x 使用 deployment 相關屬性
- STM32 使用 flash 相關屬性
- 實際上兩者都是「部署韌體到目標裝置」

---

### 5. Flash Operations 模組的語義分析

**檔案位置**：`src/fwauto/flash_operations.py` (第 1-422 行)

#### 模組註解分析

```python
"""
Flash operations module - Reusable SSH-based deployment logic.  # 第 2 行

This module provides cross-platform flash operations that can be used by:
1. flash_node (FWAuto workflow)                                 # 第 5 行
2. Standalone CLI script (manual execution)
3. Future flash implementations (JTAG, TFTP, etc.)

Design principles:
- Pure Python (no bash dependencies)                            # 第 9 行
- Cross-platform (Windows/Linux/macOS)
- Reusable functions with clear interfaces
- Proper error handling and logging
"""
```

**矛盾發現**：
- 模組註解第 2 行：**"SSH-based deployment logic"**（使用 deploy 術語）
- 模組名稱：`flash_operations.py`（使用 flash 術語）
- 第 5 行：預期用於 `flash_node`
- 第 7 行：未來擴展提到 "Future flash implementations"

#### 核心函數命名

| 函數名稱 | 位置 | 實際行為 | 語義 |
|---------|------|---------|------|
| `check_network_connectivity` | 68-126 | Ping + SSH port 檢查 | 中性 |
| `find_binary` | 134-169 | 尋找可執行檔 | 中性 |
| `deploy_binary` | 177-212 | **SCP 部署** | **deploy** ✅ |
| `execute_on_board` | 220-274 | SSH 遠端執行 | 中性 |
| `flash_firmware` | 363-421 | 完整部署流程 | **flash** ❌ |

**發現**：
- 已經有 `deploy_binary` 函數（第 177 行）
- 但頂層函數仍叫 `flash_firmware`（第 363 行）
- 註解寫著 "Deploy and Execute"（第 382 行）

---

### 6. 測試覆蓋範圍

**檔案位置**：`tests/nodes/test_flash_makefile.py`, `tests/integration/test_flash_integration.py`

#### 測試檔案命名

| 檔案名稱 | 測試數量 | 命名風格 |
|---------|---------|---------|
| `test_flash_makefile.py` | 13 個 | 使用 `flash` |
| `test_flash_integration.py` | 3 個 | 使用 `flash` |
| `test_cli.py` | 7 個 flash 相關 | 使用 `flash` |

#### 測試函數命名範例

```python
def test_flash_node_success()                    # 第 49 行
def test_flash_node_config_not_found()           # 第 70 行
def test_flash_node_with_binary_args()           # 第 171 行
def test_flash_integration_success()             # 第 35 行
```

**影響範圍**：
- 23+ 個測試函數需要重新命名
- 所有 mock state 中的 `flash_status`, `flash_errors`, `flash_log` 欄位

---

### 7. 平台差異與統一可能性

#### 兩種平台的實作差異

```mermaid
graph TD
    A[Flash Node] --> B{平台類型}
    B -->|STM32| C[Makefile]
    B -->|AM62x| D[flash_operations.py]

    C --> E[PowerShell Script]
    E --> F[ST-LINK CLI]
    F --> G[JTAG/SWD 燒錄]

    D --> H[check_connectivity]
    H --> I[deploy_binary SCP]
    I --> J[execute_on_board SSH]
    J --> K[遠端執行]

    style G fill:#ffcdd2
    style K fill:#c8e6c9
```

#### 差異對照表

| 面向 | STM32 + Keil | AM62x Linux |
|------|--------------|-------------|
| **實作方式** | PowerShell 包裝 | 純 Python SSH |
| **操作類型** | 硬體燒錄 (Flash) | 軟體部署 (Deploy) |
| **傳輸協議** | JTAG/SWD | SCP |
| **執行方式** | 本機韌體 | 遠端 SSH 執行 |
| **網路依賴** | 無 | 必須（SSH/SCP） |
| **配置欄位** | `flash_makefile` | `deployment_config` |

**統一可能性**：
- 兩者本質都是「將程式碼部署到目標裝置並執行」
- 差異在於「傳輸方式」和「執行環境」
- 使用 "deploy" 術語可以涵蓋兩者

---

## Code References

### 核心檔案位置

| 檔案路徑 | 行號 | 說明 |
|---------|------|------|
| `src/fwauto/nodes/flash.py` | 48-202 | Flash node 主要實作 |
| `src/fwauto/flash_operations.py` | 1-422 | SSH 部署核心邏輯 |
| `src/fwauto/state.py` | 44-46 | FirmwareState flash 相關欄位 |
| `src/fwauto/graph.py` | 28, 58, 82, 98, 120-127 | Graph routing 中的 flash 路由 |
| `src/fwauto/config.py` | 109-160 | deployment_config 屬性 |
| `tests/nodes/test_flash_makefile.py` | 全檔案 | 13 個單元測試 |

### 關鍵命名位置

| 類型 | 舊名稱 | 位置 | 影響範圍 |
|------|-------|------|---------|
| **Node 名稱** | `flash` | graph.py:28 | Graph definition |
| **Routing key** | `"flash"` | graph.py:58, 82 | CLI mode mapping |
| **Routing 函數** | `route_after_flash` | graph.py:120 | Workflow routing |
| **State 欄位** | `flash_status` | state.py:44 | TypedDict 定義 |
| **Config 屬性** | `flash_makefile` | 未發現實際使用 | STM32 特定 |
| **測試檔案** | `test_flash_*.py` | tests/ | 測試命名 |

---

## Architecture Insights

### 現有架構的設計模式

#### 1. Maketool 抽象層

**發現**：FWAuto 使用 Makefile 作為工具鏈抽象層

```mermaid
graph TD
    A[Python Node] -->|調用| B[Makefile]
    B -->|Windows| C[PowerShell Script]
    B -->|Linux| D[Shell Script]
    C --> E[ST-LINK CLI]
    D --> F[SCP/SSH]

    style A fill:#e3f2fd
    style B fill:#fff9c4
```

**優點**：
- Python 程式碼不涉及工具鏈細節
- 新增平台只需修改 Makefile
- 平台特定邏輯封裝在 script 中

**現況**：
- AM62x 繞過 Makefile，直接使用 Python `flash_operations` 模組
- STM32 仍使用 Makefile 包裝 PowerShell

#### 2. 雙層配置繼承

**發現**：配置系統已經使用 "deployment" 術語

```
Template defaults
  → User Config (~/.fwauto/config.toml)
    → Project Config (.fwauto/config.toml)
```

**deployment_config 的繼承鏈**（config.py:109-128）：
1. 優先使用 Project Scope
2. 回退到 User Scope
3. 最後使用預設值

**命名現況**：
- Config 屬性：`deployment_config` ✅
- Config 屬性：`flash_makefile` ❌（混用）

#### 3. Node 純函數模式

**發現**：所有 node 遵循相同的函數簽名

```python
def node_name(state: FirmwareState) -> dict[str, Any]:
    """
    Pure function that takes state and returns updates.
    """
    return {
        "field1": value1,
        "field2": value2,
    }
```

**優點**：
- 測試容易（mock state 即可）
- 無副作用（除了 I/O）
- 可組合性高

**重新命名影響**：
- 函數簽名保持不變
- 只需更改函數名稱和內部邏輯

---

### 歷史演進的設計考量

根據 `.ai/prpi/research/2025-11-06-am62x-deployment-config.md`：

#### Timeline: Flash Node 的演進

```
2025-10-10: 基礎 flash_node 實作（Makefile 驅動）
2025-10-11: State/Config 簡化
2025-10-22: Makefile 管理系統
2025-11-06: AM62x 部署系統重構（三階段）
  → Phase 1: 連線配置化（deployment_config）
  → Phase 2: 參數傳遞（binary_args）
  → Phase 3: Scenarios 系統
2025-11-10: 遠端日誌持久化（進行中）
```

**關鍵轉折點**：
- **2025-11-06**：引入 `deployment_config`，開始使用 "deploy" 術語
- Config 系統已經承認這是「部署」而非「燒錄」
- 但 node 名稱、state 欄位仍使用 "flash"

---

## Technical Feasibility

### 重新命名的技術可行性分析

#### 影響範圍矩陣

| 層級 | 項目 | 數量 | 複雜度 | 風險 |
|------|------|------|--------|------|
| **State** | `flash_status`, `flash_errors`, `flash_log` | 3 欄位 | 低 | 低 |
| **Graph** | Node 名稱, routing keys, 函數名稱 | ~10 處 | 中 | 中 |
| **Config** | `flash_makefile` → `deploy_makefile` | 1 屬性 | 低 | 低 |
| **Modules** | `flash_operations.py` → `deploy_operations.py` | 1 檔案 | 中 | 中 |
| **Nodes** | `flash.py` → `deploy.py` | 1 檔案 | 低 | 低 |
| **Tests** | 測試函數名稱, mock state | 23+ 函數 | 高 | 高 |
| **Templates** | Makefile 路徑, script 名稱 | 2 平台 | 中 | 中 |

#### 向後相容性考量

**破壞性改動**：
- CLI 命令：`fwauto flash` → `fwauto deploy` ？
- Config 欄位：現有專案的 config.toml 需要遷移
- API：如果有外部使用者依賴 `flash_node` 函數

**可能的相容策略**：
- 保留 `flash` 作為 `deploy` 的 alias（CLI 層面）
- Config 欄位同時支援舊名和新名（deprecation 期間）
- Import path 保留舊名（內部重新導向）

---

### 重新命名的優勢與劣勢

#### 優勢

| 面向 | 說明 |
|------|------|
| **語義清晰** | "Deploy" 涵蓋燒錄和部署兩種行為 |
| **擴展性** | 更容易支援新平台（ESP32, nRF52） |
| **一致性** | Config 已使用 `deployment_config`，統一命名 |
| **可讀性** | 新開發者更容易理解 AM62x 的流程 |

#### 劣勢

| 面向 | 說明 |
|------|------|
| **改動範圍** | 23+ 個測試、10+ 個檔案需要修改 |
| **向後相容** | 現有專案需要遷移 config |
| **文件更新** | README, ROADMAP, 教學文件需同步 |
| **認知負擔** | STM32 使用者可能不習慣 "deploy" 術語 |

---

### 替代方案探索

#### 方案 A: 完全重新命名

**範圍**：
- State: `flash_*` → `deploy_*`
- Graph: `flash` node → `deploy` node
- CLI: `fwauto flash` → `fwauto deploy`
- Module: `flash_operations.py` → `deploy_operations.py`

**優點**：徹底統一，語義清晰
**缺點**：破壞性改動，遷移成本高

#### 方案 B: 保持 flash，內部使用 deploy

**範圍**：
- 外部 API 保持 `flash`
- 內部函數重新命名（`deploy_binary` 已經是這樣）
- Config 使用 `deployment_config`（已實現）

**優點**：最小化外部影響
**缺點**：內外命名不一致，仍有語義矛盾

#### 方案 C: 使用 provision 術語

**範圍**：
- 使用 DevOps 領域的 "provision" 術語
- `flash` → `provision`
- 涵蓋「配置 + 部署 + 執行」

**優點**：更專業的術語
**缺點**：對嵌入式開發者可能較陌生

#### 方案 D: 保留雙重命名

**範圍**：
- STM32 相關使用 `flash`
- AM62x 相關使用 `deploy`
- 共用 state 欄位使用中性術語

**優點**：平台特定，語義精確
**缺點**：增加複雜度，違反 KISS 原則

---

## Historical Context

根據 `.ai/prpi` 目錄中的歷史文件：

### 相關研究與實施

| 文件 | 日期 | 相關性 |
|------|------|--------|
| `research/2025-11-06-am62x-deployment-config.md` | 2025-11-06 | **高** - 引入 deployment_config 概念 |
| `implementations/2025-11-06-am62x-deployment-params.md` | 2025-11-06 | **高** - 實施部署參數系統 |
| `plans/2025-11-10-remote-log-persistence.md` | 2025-11-10 | 中 - 遠端日誌持久化（使用 deploy 術語） |
| `research/2025-10-22-makefile-management-system.md` | 2025-10-22 | 中 - Makefile 抽象層設計 |

### 關鍵歷史決策

#### 2025-11-06: 部署系統重構

**決策**：引入 `deployment_config` 配置層級

**理由**（來自研究文件）：
- AM62x 需要 SSH 連線參數（board_ip, board_user, deploy_path）
- 這些參數本質上是「部署配置」而非「燒錄配置」
- 使用 "deployment" 術語更符合實際行為

**影響**：
- Config 模組開始混用 `deployment_config` 和 `flash_makefile`
- 語義矛盾開始顯現

#### 2025-11-06: 參數傳遞系統

**決策**：支援 `--binary-args` 傳遞給遠端執行

**實施細節**（flash.py:76-94）：
```python
# Extract binary arguments
command_args = state.get("command_args") or {}
binary_args = command_args.get("binary_args", "")

# Security: Prevent shell injection
dangerous_chars = [";", "|", "&", "$", "`", "\n", "\r"]
if any(c in binary_args for c in dangerous_chars):
    return error_state
```

**發現**：
- 這是「部署參數」而非「燒錄參數」
- STM32 燒錄不需要 binary_args
- AM62x 遠端執行才需要

---

## Related Research

### 專案內部文件

- `.ai/prpi/research/2025-11-06-am62x-deployment-config.md` - AM62x 部署配置深度研究
- `.ai/prpi/implementations/2025-11-06-phase1-phase2-deployment-params.md` - 部署參數實施報告
- `.ai/prpi/plans/2025-11-10-remote-log-persistence.md` - 遠端日誌持久化計劃

### 外部參考

- LangGraph Best Practices - Node 命名慣例
- 嵌入式開發術語：Flash vs Deploy vs Provision
- DevOps 領域的部署模式

---

## Open Questions

### 技術問題

1. **CLI 命令相容性**：
   - 是否保留 `fwauto flash` 作為 alias？
   - 如何處理現有文件和教學？

2. **Config 遷移策略**：
   - 如何自動遷移現有專案的 config.toml？
   - 是否需要 deprecation warning？

3. **測試覆蓋**：
   - 重新命名後如何確保測試完整性？
   - 是否需要額外的整合測試？

4. **Makefile 路徑**：
   - `.fwauto/flash/Makefile` → `.fwauto/deploy/Makefile`？
   - 現有專案的 Makefile 如何處理？

### 設計問題

1. **術語選擇**：
   - `deploy` vs `provision` vs `flash`？
   - 不同平台是否使用統一術語？

2. **抽象層級**：
   - 是否需要更高層次的抽象（如 `provision_node`）？
   - Build → Deploy → Execute 是否應該分離？

3. **平台擴展**：
   - 未來支援 OTA 更新如何命名？
   - 雲端部署（Cloud Deploy）如何整合？

### 用戶影響

1. **學習曲線**：
   - STM32 使用者是否熟悉 "deploy" 術語？
   - 是否需要術語對照表？

2. **遷移成本**：
   - 現有專案遷移需要多少工作量？
   - 是否提供自動化遷移工具？

---

## 結論

經過全面的程式碼庫探索，發現 **FWAuto 的 flash_node 在語義和實作上已經體現了「部署」的概念**，特別是在 AM62x 平台上。Config 系統已經使用 `deployment_config` 命名，flash_operations 模組的註解也寫著 "SSH-based deployment logic"。

**核心發現**：
- 命名矛盾已經存在（`deployment_config` vs `flash_node`）
- AM62x 的實作完全是部署流程，而非燒錄
- 重新命名可以解決語義矛盾，提升架構一致性

**技術可行性**：
- 影響範圍清晰（State, Graph, Config, Tests）
- 架構支援重構（純函數 node 模式）
- 需要考慮向後相容策略

此研究提供了重新命名的完整脈絡和影響分析，後續可進入 `/prpi:plan` 階段設計具體的重構方案。

---

## Decision Record

**決策日期**: 2025-11-12T13:00:00+08:00
**決策者**: User (Project Owner)
**決策方式**: 逐一討論 Open Questions，選項式決策

### 核心決策：徹底重構策略 (Clean Slate)

基於專案尚未 release 的事實，採用徹底重構策略，完全消除 flash/deploy 語義矛盾。

---

### 技術決策

#### 1. CLI 命令相容性

**決策**: ✅ 完全移除 `fwauto flash`，只保留 `fwauto deploy`

**理由**:
- 專案還沒 release，無外部使用者需要維護相容性
- 徹底重構可完全消除語義矛盾
- 避免長期維護兩套命令的成本

**備選方案**:
- ❌ 保留 `flash` 作為 `deploy` 的 alias：增加維護成本
- ❌ 保留 `flash` 但加 deprecation warning：需要設定淘汰時間表
- ❌ 根本不改 CLI，只改內部實作：外部命名仍不準確

---

#### 2. 文件更新策略

**決策**: ✅ 全部同步更新為 deploy 術語

**理由**:
- 保持文件與代碼的一致性
- 避免混用術語造成混淆
- 一次性完成，避免遺留問題

**影響範圍**:
- README.md
- ROADMAP.md
- docs/ 目錄下的所有文件
- CLAUDE.md 專案指引

**備選方案**:
- ❌ 保留舊文件，加上「已更名」說明：內容可能過時
- ❌ 寫一個 Migration Guide：需要額外維護

---

#### 3. Config 遷移策略

**決策**: ✅ 還沒 release，不用管 legacy 問題

**關鍵事實**: 專案尚未正式發布，沒有外部使用者的 config 需要遷移

**影響**:
- 無需提供自動遷移工具
- 無需維護 runtime 相容代碼
- 可以直接使用新的 config schema

**Config 改動**:
```toml
# 舊名稱（將被移除）
[flash]
makefile = ".fwauto/flash/Makefile"
target = "flash"

# 新名稱（將採用）
[deploy]
makefile = ".fwauto/deploy/Makefile"
target = "deploy"
```

---

#### 4. Makefile 路徑命名

**決策**: ✅ 改名為 `.fwauto/deploy/`

**理由**:
- 與 deploy 術語保持一致
- 清晰的語意表達
- 符合目錄結構慣例

**改動**:
```
舊路徑: .fwauto/flash/
新路徑: .fwauto/deploy/

包含檔案:
  - Makefile
  - flash.sh → deploy.sh (AM62x)
  - flash.ps1 → deploy.ps1 (STM32)
  - flash.py → deploy.py (AM62x standalone)
```

**Template 目錄改動**:
```
templates/sdk_am62x_linux/flash/     → templates/sdk_am62x_linux/deploy/
templates/sdk_stm32_keil/flash/      → templates/sdk_stm32_keil/deploy/
```

---

### 設計決策

#### 5. 術語選擇

**決策**: ✅ 使用 **deploy** 術語

**理由**:
- DevOps 領域廣泛使用，直觀易懂
- 涵蓋「部署」的完整語意
- 既適用於 STM32 燒錄，也適用於 AM62x SSH 部署

**對照表**:
| 術語 | 優點 | 缺點 | 決策 |
|------|------|------|------|
| deploy | 直觀、廣泛使用 | STM32 燒錄不是傳統 deploy | ✅ 採用 |
| provision | 專業、完整 | 嵌入式開發者可能不熟悉 | ❌ |
| flash | MCU 傳統術語 | 無法涵蓋 AM62x 部署 | ❌ |
| transfer | 中性術語 | 缺少「執行」語意 | ❌ |

---

#### 6. 平台術語統一

**決策**: ✅ 所有平台統一使用 deploy

**理由**:
- 遵循 KISS 原則
- 減少概念複雜度
- 統一的使用者介面

**適用平台**:
- STM32 + Keil: `deploy` (燒錄到 flash 記憶體)
- AM62x Linux: `deploy` (SCP + SSH 部署)
- 未來平台 (ESP32, nRF52): `deploy`

**備選方案**:
- ❌ 區分命名 (flash_stm32, deploy_am62x)：增加複雜度，違反 KISS
- ❌ 抽象為 provision node：可能過於抽象

---

#### 7. 抽象層級

**決策**: ✅ 維持現狀 (deploy = 部署+執行)

**理由**:
- 符合 KISS 原則
- 現有架構已經足夠清晰
- 避免過度設計

**Deploy Node 職責**:
1. 將程式碼傳輸到目標裝置（SCP 或 JTAG）
2. 在目標裝置上執行（SSH 或 reset）

**備選方案**:
- ❌ 分離 deploy 和 execute node：增加 graph 複雜度
- ❌ 建立 provision node 包裝：可能過度設計

---

#### 8. 未來擴展

**決策**: ✅ 現在不考慮，等需求出現再評估

**理由**:
- 遵循 YAGNI (You Aren't Gonna Need It) 原則
- 避免過早抽象
- 保持代碼簡潔

**未來可能的擴展**:
- OTA 更新：屆時再評估是否需要獨立 node
- 雲端部署：可能使用 config 切換或新增 node
- 其他部署方式：依實際需求設計

---

### 測試決策

#### 9. 測試覆蓋策略

**決策**: ✅ 全部重新命名並確保通過

**理由**:
- 保持測試與代碼的一致性
- 避免混用術語造成混淆
- 確保重構後的測試覆蓋完整

**改動範圍**:
```python
# 測試檔案重新命名
tests/nodes/test_flash_makefile.py    → test_deploy_makefile.py
tests/integration/test_flash_integration.py → test_deploy_integration.py

# 測試函數重新命名 (23+ 個)
def test_flash_node_success()          → test_deploy_node_success()
def test_flash_node_config_not_found() → test_deploy_node_config_not_found()
...

# Mock state 欄位重新命名
"flash_status": "success"  → "deploy_status": "success"
"flash_errors": []         → "deploy_errors": []
"flash_log": ""            → "deploy_log": ""
```

**驗證標準**:
- ✅ 所有測試通過 (110/110)
- ✅ 測試覆蓋率維持或提升
- ✅ 命名一致性檢查

---

### 決策總結表

| 決策項目 | 選擇 | 策略屬性 |
|---------|------|---------|
| CLI 命令 | 完全移除 `flash`，只保留 `deploy` | 徹底重構 |
| 文件更新 | 全部同步更新為 deploy 術語 | 徹底重構 |
| Config 遷移 | 不用管 legacy (未 release) | 無負擔 |
| Makefile 路徑 | 改名為 `.fwauto/deploy/` | 徹底重構 |
| 術語選擇 | **deploy** | 統一術語 |
| 平台術語 | 所有平台統一使用 deploy | KISS 原則 |
| 抽象層級 | 維持現狀 (deploy = 部署+執行) | KISS 原則 |
| 未來擴展 | 現在不考慮 | YAGNI 原則 |
| 測試策略 | 全部重新命名並確保通過 | 徹底重構 |

---

### 重構策略特徵

**策略類型**: 徹底重構 (Clean Slate)

**核心原則**:
- ✅ KISS (Keep It Simple, Stupid)
- ✅ YAGNI (You Aren't Gonna Need It)
- ✅ 一致性優於相容性

**優勢**:
1. 完全消除語義矛盾
2. 架構一致性高
3. 沒有 legacy 包袱
4. 長期維護成本低
5. 符合軟體工程最佳實踐

**挑戰**:
1. 需要同步更新約 40+ 處
2. 23+ 個測試函數需要重新命名
3. 文件需要全面更新

**適用性**:
- ✅ 專案尚未 release
- ✅ 沒有外部使用者
- ✅ 團隊可以一次性完成重構

---

### 後續步驟

基於以上決策，建議執行 `/prpi:plan` 建立詳細實施計劃，包含：

1. **Phase 1: 核心模組重新命名**
   - State 欄位
   - Node 實作
   - Graph routing

2. **Phase 2: 配置與模板更新**
   - Config 屬性
   - Template 目錄
   - Makefile 路徑

3. **Phase 3: 測試完整更新**
   - 測試檔案重新命名
   - Mock state 更新
   - 驗證測試覆蓋

4. **Phase 4: 文件同步**
   - README.md
   - ROADMAP.md
   - CLAUDE.md
   - 其他文件

5. **Phase 5: 驗證與部署**
   - 完整測試驗證
   - 整合測試
   - Git 提交與部署

**預期成果**: 完全消除 flash/deploy 語義矛盾，建立清晰一致的架構。
