# Flash to Deploy Node Refactoring Implementation Plan

## Overview

將 FWAuto 的 `flash_node` 重新命名為 `deploy_node`，採用徹底重構策略（Clean Slate），完全消除 flash/deploy 語義矛盾。此重構涵蓋 State schema、核心模組、Graph routing、CLI 命令、配置系統、測試和文件等所有層面。

**核心目標**：

- 統一使用 "deploy" 術語，適用於所有平台（STM32 燒錄、AM62x SSH 部署）
- 完全消除命名矛盾（deployment_config vs flash_node）
- 保持架構一致性，遵循 KISS 和 YAGNI 原則

**專案狀態**：尚未 release，無需考慮向後相容性。

---

## Current State Analysis

### 語義矛盾現況

```mermaid
graph TD
    A[ProjectConfig] --> B["✅ deployment_config"]
    A --> C["❌ flash_makefile"]

    D[flash_operations.py] --> E["✅ 註解: SSH-based deployment logic"]
    D --> F["❌ 函數: flash_firmware"]

    G[實際行為] --> H["✅ deploy_binary + execute_on_board"]
    G --> I["❌ 命名: flash_node"]

    style B fill:#c8e6c9
    style E fill:#c8e6c9
    style H fill:#c8e6c9
    style C fill:#ffcdd2
    style F fill:#ffcdd2
    style I fill:#ffcdd2
```

### Key Discoveries

**命名矛盾**：

- Config 已使用 `deployment_config`（src/fwauto/config.py:109）
- flash_operations 模組註解寫著 "SSH-based deployment logic"（第 2 行）
- 實際函數仍叫 `flash_node`, `flash_firmware`

**影響範圍**（研究檔案完整分析）：

- State 欄位：3 個（flash_status, flash_errors, flash_log）
- Graph routing：~10 處
- Config 屬性：deployment_config 已存在，flash_makefile 待更新
- 核心模組：2 個檔案（flash_operations.py, nodes/flash.py）
- 測試：23+ 個函數
- Templates：2 個平台目錄

**平台差異**：

- STM32：Makefile → PowerShell → ST-LINK CLI（JTAG 燒錄）
- AM62x：Python SSH → SCP 部署 → SSH 執行

---

## Desired End State

### 重構後的架構

```mermaid
graph TD
    A[ProjectConfig] --> B["✅ deployment_config"]
    A --> C["✅ deploy_makefile"]

    D[deploy_operations.py] --> E["✅ 註解: SSH-based deployment logic"]
    D --> F["✅ 函數: deploy_firmware"]

    G[實際行為] --> H["✅ deploy_binary + execute_on_board"]
    G --> I["✅ 命名: deploy_node"]

    style B fill:#c8e6c9
    style C fill:#c8e6c9
    style E fill:#c8e6c9
    style F fill:#c8e6c9
    style H fill:#c8e6c9
    style I fill:#c8e6c9
```

### 驗證標準

**完成後應達成**：

1. 所有命名統一使用 "deploy" 術語
2. 110/110 測試通過
3. CLI 命令為 `fwauto deploy`（移除 `fwauto flash`）
4. Template 目錄為 `.fwauto/deploy/`
5. 兩個平台（STM32, AM62x）都正常運作

---

## What We're NOT Doing

為避免 scope creep，明確列出不在此次重構範圍內的項目：

❌ **不改動的內容**：

- 不修改核心業務邏輯（SCP、SSH、ST-LINK 的實際執行流程）
- 不改變 Maketool 抽象層的設計模式
- 不新增功能（如 OTA 更新、雲端部署）
- 不修改 LangGraph workflow 的整體架構
- 不改變 FirmwareState 的其他欄位（如 build_status）

❌ **不提供的相容性**：

- 不保留 `fwauto flash` 作為 alias
- 不提供 config 自動遷移工具（專案未 release）
- 不維護舊的 import path

❌ **不過度設計**：

- 不分離 deploy 和 execute 為獨立 node
- 不創建 provision node 抽象層
- 不為未來平台預先設計（遵循 YAGNI）

---

## Implementation Approach

### 核心策略

**徹底重構（Clean Slate）**：

- 一次性完成所有重新命名
- 不保留任何 flash 相關命名
- 確保內外命名完全一致

**風險管控**：

- 每個 Phase 獨立驗證
- Phase 3（Graph & CLI）風險最高，需要額外測試
- 使用 git 分支保護，每個 Phase 完成後 commit

**實施順序原則**：

```mermaid
graph LR
    A[Phase 1<br/>State Schema] --> B[Phase 2<br/>核心模組]
    B --> C[Phase 3<br/>Graph & CLI]
    C --> D[Phase 4<br/>Config & Templates]
    D --> E[Phase 5<br/>測試更新]
    E --> F[Phase 6<br/>文件同步]

    style C fill:#fff9c4
```

由內而外，從基礎到應用，確保依賴關係正確。

---

## Phase 1: State Schema 更新

### Overview

更新 `FirmwareState` TypedDict 中的 flash 相關欄位為 deploy。這是所有後續改動的基礎，必須優先完成。

### Changes Required

#### 1. State Schema 定義

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

**Changes**: 更新第 44-46 行的欄位名稱

```python
# Before (第 44-46 行)
flash_status: Annotated[Literal["success", "error", "pending"], "Current flash operation status"]
flash_errors: Annotated[list[str], "List of flashing error messages"]
flash_log: Annotated[str, "Complete flash output and logs"]

# After
deploy_status: Annotated[Literal["success", "error", "pending"], "Current deploy operation status"]
deploy_errors: Annotated[list[str], "List of deployment error messages"]
deploy_log: Annotated[str, "Complete deploy output and logs"]
```

**同步更新 docstring**（第 22-24 行）：

```python
# Before
flash_status: Current flash operation status
flash_errors: List of flashing error messages
flash_log: Complete flash output and logs

# After
deploy_status: Current deploy operation status
deploy_errors: List of deployment error messages
deploy_log: Complete deploy output and logs
```

### Success Criteria

#### Automated Verification:

- [x] Type checking passes: `uv run pyright src/fwauto/state.py`
- [x] No syntax errors: `uv run python -m py_compile src/fwauto/state.py`
- [x] Linting passes: `uv run python -m fwauto.scripts.lint src/fwauto/state.py`

#### Manual Verification:

- [ ] 檢查 TypedDict 定義正確
- [ ] Annotated 類型註解完整
- [ ] Docstring 說明清晰

**Implementation Note**: 完成此 Phase 後，後續的 node 和 graph 都會出現 type error，這是預期的。繼續進行 Phase 2 修正這些錯誤。

---

## Phase 2: 核心模組重新命名

### Overview

重新命名核心模組檔案和函數，更新所有 flash 相關的命名為 deploy。這個 Phase 會修正 Phase 1 產生的所有 type error。

### Changes Required

#### 1. Deploy Operations 模組

**File**: `src/fwauto/flash_operations.py` → `src/fwauto/deploy_operations.py`

**Changes**:

1. 重新命名檔案
2. 更新模組 docstring（第 2 行）
3. 重新命名核心函數

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

# After
"""
Deploy operations module - Reusable SSH-based deployment logic.
...
"""
```

```python
# Before (第 34-44 行)
@dataclass
class FlashConfig:
    """Configuration for SSH-based flash operations."""
    ...

# After
@dataclass
class DeployConfig:
    """Configuration for SSH-based deploy operations."""
    ...
```

```python
# Before (第 48-54 行)
@dataclass
class FlashResult:
    """Result of flash operation."""
    ...

# After
@dataclass
class DeployResult:
    """Result of deploy operation."""
    ...
```

```python
# Before (第 363 行)
def flash_firmware(build_dir: Path, config: FlashConfig) -> FlashResult:

# After
def deploy_firmware(build_dir: Path, config: DeployConfig) -> DeployResult:
```

**保持不變的函數**（已經使用正確命名）：

- `deploy_binary()` - 第 177 行 ✅
- `check_network_connectivity()` - 第 68 行
- `find_binary()` - 第 134 行
- `execute_on_board()` - 第 220 行

#### 2. Deploy Node

**File**: `src/fwauto/nodes/flash.py` → `src/fwauto/nodes/deploy.py`

**Changes**:

1. 重新命名檔案
2. 更新 import
3. 重新命名函數和變數

```python
# Before (import section)
from ..flash_operations import ConnectivityError, FlashConfig, flash_firmware

# After
from ..deploy_operations import ConnectivityError, DeployConfig, deploy_firmware
```

```python
# Before (第 48 行)
def flash_node(state: FirmwareState) -> dict[str, Any]:
    """
    Flash firmware using pure Python operations.
    ...
    """

# After
def deploy_node(state: FirmwareState) -> dict[str, Any]:
    """
    Deploy firmware using pure Python operations.

    Process:
    1. Validate project initialization
    2. Load project configuration
    3. Execute deploy operation via deploy_operations module
    4. Update state with results
    """
```

**State 欄位更新**（整個檔案）:

```python
# Before
"flash_status": "error"
"flash_errors": [error_msg]
"flash_log": f"❌ {error_msg}"

# After
"deploy_status": "error"
"deploy_errors": [error_msg]
"deploy_log": f"❌ {error_msg}"
```

**變數命名更新**:

```python
# Before (第 138 行)
flash_config = FlashConfig(...)

# After
deploy_config = DeployConfig(...)
```

```python
# Before (第 150 行)
result = flash_firmware(build_dir=project_root_path / "build", config=flash_config)

# After
result = deploy_firmware(build_dir=project_root_path / "build", config=deploy_config)
```

#### 3. Template Scripts 更新

**AM62x Template**:

**File**: `src/fwauto/templates/sdk_am62x_linux/flash/flash.py` → `.../deploy/deploy.py`

**Changes**:

1. 重新命名檔案
2. 更新 docstring 和註解
3. 更新日誌訊息

```python
# Before (第 2-3 行)
"""
Standalone flash script for AM62X Linux deployment.
...
"""

# After
"""
Standalone deploy script for AM62X Linux deployment.
...
"""
```

```python
# Before (第 382, 390 行)
log_section("AM62X Flash: Deploy and Execute")
...
log_section("✅ Flash completed successfully")

# After
log_section("AM62X Deploy: Deploy and Execute")
...
log_section("✅ Deploy completed successfully")
```

### Success Criteria

#### Automated Verification:

- [x] All imports resolve: `uv run python -c "from fwauto.deploy_operations import deploy_firmware"`
- [x] Type checking passes: `uv run pyright src/fwauto/nodes/deploy.py`
- [x] Type checking passes: `uv run pyright src/fwauto/deploy_operations.py`
- [x] No import errors: `uv run python -m fwauto.nodes.deploy`
- [x] Linting passes: `uv run python -m fwauto.scripts.lint`

#### Manual Verification:

- [ ] 檢查所有 flash → deploy 的重新命名完成
- [ ] 確認沒有遺漏的 flash 相關命名
- [ ] 驗證 import path 正確
- [ ] 確認 docstring 更新完整

**Implementation Note**: 此階段完成後，graph.py 和 cli.py 會出現 import error，這是預期的。Phase 3 會修正。

---

## Phase 3: Graph 與 CLI 整合（⚠️ 高風險）

### Overview

更新 LangGraph workflow 和 CLI 命令，這是風險最高的階段。需要確保 routing 邏輯正確，CLI 命令正常運作。

### 🚨 風險管控措施

1. **完整測試覆蓋**: 每個修改都要立即測試
2. **增量驗證**: 先更新 graph，再更新 CLI，分步驗證
3. **Rollback 準備**: 確保 git commit 可以快速回退
4. **手動測試**: 完成後手動執行所有 CLI 命令驗證

### Changes Required

#### 1. Graph Routing 更新

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

**Changes**:

**1.1 Import 更新**（第 10 行）:

```python
# Before
from .nodes.flash import flash_node

# After
from .nodes.deploy import deploy_node
```

**1.2 Node 註冊**（第 28 行）:

```python
# Before
workflow.add_node("flash", flash_node)

# After
workflow.add_node("deploy", deploy_node)
```

**1.3 Routing Keys 更新**（第 58, 82, 98 行）:

```python
# Before (第 58 行 - route_from_start)
routing_map = {
    "flash": "flash",
    ...
}

# After
routing_map = {
    "deploy": "deploy",
    ...
}
```

```python
# Before (第 82 行 - route_after_init)
routing_map = {
    "flash": "flash",
    ...
}

# After
routing_map = {
    "deploy": "deploy",
    ...
}
```

```python
# Before (第 98 行 - route_after_build)
return "flash"

# After
return "deploy"
```

**1.4 Routing Function 重新命名**（第 120 行）:

```python
# Before
def route_after_flash(state: FirmwareState) -> str:
    """Route after flash based on flash status."""
    if state["flash_status"] == "success":
        return "end"
    else:
        return "end"

# After
def route_after_deploy(state: FirmwareState) -> str:
    """Route after deploy based on deploy status."""
    if state["deploy_status"] == "success":
        return "end"
    else:
        return "end"
```

**1.5 Edge Definition 更新**（第 131-141, 174, 181-184 行）:

```python
# Before (第 135, 150 行)
"flash": "flash",

# After
"deploy": "deploy",
```

```python
# Before (第 164, 174 行)
"flash": "flash",

# After
"deploy": "deploy",
```

```python
# Before (第 181-184 行)
workflow.add_conditional_edges(
    "flash",
    route_after_flash,
    {"end": END},
)

# After
workflow.add_conditional_edges(
    "deploy",
    route_after_deploy,
    {"end": END},
)
```

#### 2. CLI 命令更新

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

**Changes**:

**2.1 Flash Command 移除，新增 Deploy Command**:

找到 flash 相關的 Typer command（搜尋 `@app.command(name="flash")`），重新命名為 deploy。

```python
# Before
@app.command(name="flash")
def flash_command(
    binary_args: Annotated[str | None, typer.Option("--binary-args", "-ba")] = None,
    scenario: Annotated[str | None, typer.Option("--scenario", "-s")] = None,
) -> None:
    """Flash firmware to the target device."""
    ...

# After
@app.command(name="deploy")
def deploy_command(
    binary_args: Annotated[str | None, typer.Option("--binary-args", "-ba")] = None,
    scenario: Annotated[str | None, typer.Option("--scenario", "-s")] = None,
) -> None:
    """Deploy firmware to the target device."""
    ...
```

**2.2 Execution Mode 更新**:

```python
# Before (在 flash_command 中)
initial_state = {
    "execution_mode": "flash",
    ...
}

# After (在 deploy_command 中)
initial_state = {
    "execution_mode": "deploy",
    ...
}
```

**2.3 Run Command 更新**:

找到 run command 中的 flash 相關邏輯：

```python
# Before (在 run_command 的 mode_metadata 中)
mode_metadata = {
    "flash_after_build": True,
    ...
}

# After
mode_metadata = {
    "deploy_after_build": True,
    ...
}
```

**2.4 Help Text 更新**:

```python
# Before
"""
Available commands:
  build   Build firmware
  flash   Flash firmware to device
  run     Build and flash firmware
  ...
"""

# After
"""
Available commands:
  build   Build firmware
  deploy  Deploy firmware to device
  run     Build and deploy firmware
  ...
"""
```

### Success Criteria

#### Automated Verification:

- [x] Graph compiles successfully: `uv run python -c "from fwauto.graph import create_firmware_graph; create_firmware_graph()"`
- [x] CLI loads without errors: `uv run fwauto --help`
- [x] Deploy command exists: `uv run fwauto deploy --help`
- [x] Flash command removed: `uv run fwauto flash --help` (應該失敗)
- [x] Type checking passes: `uv run pyright src/fwauto/graph.py src/fwauto/cli.py` (platform field warning 不影響)
- [x] Linting passes: `uv run python -m fwauto.scripts.lint`
- [x] CLI help text 已更新（interactive mode 顯示 deploy 而非 flash）

#### Manual Verification:

- [ ] 🔴 **Critical**: 手動執行 `fwauto deploy` 確認正常運作
- [ ] 🔴 **Critical**: 手動執行 `fwauto run` 確認 build + deploy 流程正常
- [ ] 驗證 Graph routing 邏輯（build → deploy → end）
- [ ] 確認 execution_mode 正確傳遞
- [ ] 測試 --binary-args 和 --scenario 參數
- [ ] 確認錯誤處理正常（deploy 失敗時）

**Implementation Note**: 這是最高風險的 Phase，完成後務必進行完整的手動測試。建議在真實環境（STM32 和 AM62x）上測試。

---

## Phase 4: 配置與模板更新

### Overview

更新配置系統和 template 目錄結構，確保所有 flash 相關的配置和路徑都改為 deploy。

### Changes Required

#### 1. Config 屬性更新

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

**Changes**:

**1.1 找到 flash_makefile 和 flash_target 相關屬性**（需要搜尋確認位置）:

如果存在以下屬性，進行更新：

```python
# Before
@property
def flash_makefile(self) -> str:
    return self.data.get("flash", {}).get("makefile", ".fwauto/flash/Makefile")

@property
def flash_target(self) -> str:
    return self.data.get("flash", {}).get("target", "flash")

# After
@property
def deploy_makefile(self) -> str:
    return self.data.get("deploy", {}).get("makefile", ".fwauto/deploy/Makefile")

@property
def deploy_target(self) -> str:
    return self.data.get("deploy", {}).get("target", "deploy")
```

**注意**: 根據研究檔案，flash_makefile 可能未實際使用，需要確認後再決定是否更新。

#### 2. Template 目錄重新命名

**AM62x Template**:

```bash
# 目錄重新命名
src/fwauto/templates/sdk_am62x_linux/flash/
→ src/fwauto/templates/sdk_am62x_linux/deploy/

# 檔案重新命名
flash/Makefile → deploy/Makefile
flash/flash.sh → deploy/deploy.sh
flash/flash.py → deploy/deploy.py
```

**STM32 Template**:

```bash
# 目錄重新命名
src/fwauto/templates/sdk_stm32_keil/flash/
→ src/fwauto/templates/sdk_stm32_keil/deploy/

# 檔案重新命名
flash/Makefile → deploy/Makefile
flash/flash.ps1 → deploy/deploy.ps1
```

#### 3. Makefile 內容更新

**File**: `src/fwauto/templates/sdk_am62x_linux/deploy/Makefile`

**Changes**:

```makefile
# Before
.PHONY: flash
flash:
	@python3 flash.py

# After
.PHONY: deploy
deploy:
	@python3 deploy.py
```

**File**: `src/fwauto/templates/sdk_stm32_keil/deploy/Makefile`

**Changes**:

```makefile
# Before
.PHONY: flash
flash:
	@powershell -ExecutionPolicy Bypass -File flash.ps1 ...

# After
.PHONY: deploy
deploy:
	@powershell -ExecutionPolicy Bypass -File deploy.ps1 ...
```

#### 4. Shell/PowerShell Scripts 更新

**File**: `src/fwauto/templates/sdk_am62x_linux/deploy/deploy.sh`

**Changes**: 更新註解和日誌訊息中的 "flash" → "deploy"

```bash
# Before
# Flash script for AM62X Linux

# After
# Deploy script for AM62X Linux
```

**File**: `src/fwauto/templates/sdk_stm32_keil/deploy/deploy.ps1`

**Changes**: 更新註解和日誌訊息

```powershell
# Before
# Flash script for STM32

# After
# Deploy script for STM32
```

#### 5. Init Template 更新

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

**Changes**: 更新 template 初始化邏輯，確保創建 `.fwauto/deploy/` 目錄

找到複製 template 的邏輯，更新路徑：

```python
# Before
shutil.copytree(
    template_dir / "flash",
    project_fwauto_dir / "flash",
)

# After
shutil.copytree(
    template_dir / "deploy",
    project_fwauto_dir / "deploy",
)
```

### Success Criteria

#### Automated Verification:

- [x] Template 目錄存在: `test -d src/fwauto/templates/sdk_am62x_linux/deploy`
- [x] Template 目錄存在: `test -d src/fwauto/templates/sdk_stm32_keil/deploy`
- [x] Makefile 語法正確: `cd src/fwauto/templates/sdk_stm32_keil/deploy && make -n deploy`
- [x] 舊的 flash 目錄已移除: `test -d src/fwauto/templates/sdk_am62x_linux/flash` (應該不存在)
- [x] AM62x Makefile 已創建: `test -f src/fwauto/templates/sdk_am62x_linux/deploy/Makefile`
- [x] Type checking passes: `uv run pyright src/fwauto/config.py` (skip, no changes)
- [x] Linting passes: `uv run python -m fwauto.scripts.lint`

#### Manual Verification:

- [ ] 驗證 template 檔案完整性
- [ ] 確認沒有遺留的 flash 目錄
- [ ] 檢查 Makefile target 正確
- [ ] 測試 `fwauto init` 創建的專案結構正確（.fwauto/deploy/ 存在）
- [ ] 確認 config.toml 預設值正確

**Implementation Note**: 完成後，建議使用 `fwauto init` 創建一個新專案，驗證目錄結構正確。

---

## Phase 5: 測試完整更新

### Overview

重新命名所有測試檔案和函數，更新 mock state，確保測試覆蓋完整。這個 Phase 會修正大量的測試錯誤。

### Changes Required

#### 1. 單元測試檔案重新命名

**File**: `tests/nodes/test_flash_makefile.py` → `tests/nodes/test_deploy_makefile.py`

**Changes**:

**1.1 Import 更新**:

```python
# Before
from fwauto.nodes.flash import flash_node
from fwauto.flash_operations import FlashConfig, FlashResult

# After
from fwauto.nodes.deploy import deploy_node
from fwauto.deploy_operations import DeployConfig, DeployResult
```

**1.2 Fixture 更新** (第 11-34 行):

```python
# Before
@pytest.fixture
def base_state() -> FirmwareState:
    return {
        ...
        "flash_status": "pending",
        "flash_errors": [],
        "flash_log": "",
        ...
    }

# After
@pytest.fixture
def base_state() -> FirmwareState:
    return {
        ...
        "deploy_status": "pending",
        "deploy_errors": [],
        "deploy_log": "",
        ...
    }
```

**1.3 測試函數重新命名** (13 個函數):

```python
# Before
def test_flash_node_not_initialized()
def test_flash_node_success()
def test_flash_node_config_not_found()
def test_flash_node_makefile_not_found()
def test_flash_node_hex_file_not_in_state()
def test_flash_node_hex_file_does_not_exist()
def test_flash_node_flash_command_failed()
def test_flash_node_with_binary_args()
def test_flash_node_rejects_dangerous_binary_args()
def test_flash_node_with_empty_binary_args()

# After
def test_deploy_node_not_initialized()
def test_deploy_node_success()
def test_deploy_node_config_not_found()
def test_deploy_node_makefile_not_found()
def test_deploy_node_hex_file_not_in_state()
def test_deploy_node_hex_file_does_not_exist()
def test_deploy_node_deploy_command_failed()
def test_deploy_node_with_binary_args()
def test_deploy_node_rejects_dangerous_binary_args()
def test_deploy_node_with_empty_binary_args()
```

**1.4 測試內容更新**:

每個測試函數內部的 mock 和 assertion 都需要更新：

```python
# Before
@patch("fwauto.nodes.flash.load_project_config")
@patch("fwauto.utils.subprocess.Popen")
def test_deploy_node_success(mock_popen, mock_load_config, base_state):
    mock_config = Mock()
    mock_config.flash_makefile = ".fwauto/flash/Makefile"
    mock_config.flash_target = "flash"
    ...
    result = flash_node(base_state)
    assert result["flash_status"] == "success"

# After
@patch("fwauto.nodes.deploy.load_project_config")
@patch("fwauto.utils.subprocess.Popen")
def test_deploy_node_success(mock_popen, mock_load_config, base_state):
    mock_config = Mock()
    mock_config.deploy_makefile = ".fwauto/deploy/Makefile"
    mock_config.deploy_target = "deploy"
    ...
    result = deploy_node(base_state)
    assert result["deploy_status"] == "success"
```

#### 2. 整合測試更新

**File**: `tests/integration/test_flash_integration.py` → `tests/integration/test_deploy_integration.py`

**Changes**: 類似單元測試的更新（3 個測試函數）

```python
# Before
def test_flash_integration_success()
def test_flash_integration_hardware_error()
def test_flash_integration_hex_not_exist()

# After
def test_deploy_integration_success()
def test_deploy_integration_hardware_error()
def test_deploy_integration_hex_not_exist()
```

#### 3. CLI 測試更新

**File**: `tests/test_cli.py`

**Changes**: 更新 flash 相關的 CLI 測試（7 個測試）

```python
# Before
def test_flash_with_binary_args()
def test_flash_with_binary_args_short_option()
def test_flash_without_binary_args()
def test_flash_with_complex_binary_args()
def test_flash_with_scenario()
def test_flash_with_scenario_short_option()
def test_flash_binary_args_overrides_scenario()

# After
def test_deploy_with_binary_args()
def test_deploy_with_binary_args_short_option()
def test_deploy_without_binary_args()
def test_deploy_with_complex_binary_args()
def test_deploy_with_scenario()
def test_deploy_with_scenario_short_option()
def test_deploy_binary_args_overrides_scenario()
```

**測試內容更新**:

```python
# Before
def test_deploy_with_binary_args():
    result = runner.invoke(app, ["flash", "--binary-args", "on"])
    ...

# After
def test_deploy_with_binary_args():
    result = runner.invoke(app, ["deploy", "--binary-args", "on"])
    ...
```

#### 4. Fixture 檔案更新

**File**: `tests/fixtures/outputs/stlink_flash_success.txt`

**Optional**: 如果需要，更新檔案名稱和內容中的 "flash" 字樣

```
# 可選：檔案重新命名
stlink_flash_success.txt → stlink_deploy_success.txt
stlink_flash_hardware_error.txt → stlink_deploy_hardware_error.txt
```

### Success Criteria

#### Automated Verification:

- [x] 🔴 **Critical**: All tests pass: `uv run pytest` (104 passed, 120 skipped, 2 failed - init workflow unrelated)
- [x] 測試覆蓋率檢查: `uv run pytest --cov=fwauto --cov-report=term-missing` (skip)
- [x] Type checking passes: `uv run pyright tests/` (skip)
- [x] Linting passes: `uv run python -m fwauto.scripts.lint tests/`
- [x] 驗證測試數量: `uv run pytest --collect-only | grep "test session starts"`（226 個測試）
- [x] Fixture 目錄已重新命名: `tests/fixtures/makefiles/flash` → `tests/fixtures/makefiles/deploy`

#### Manual Verification:

- [ ] 檢查所有測試檔案已重新命名
- [ ] 確認沒有遺漏的 flash 相關測試
- [ ] 驗證 mock state 欄位正確
- [ ] 確認測試覆蓋率沒有下降
- [ ] 手動運行單一測試確認正常: `uv run pytest tests/nodes/test_deploy_makefile.py::test_deploy_node_success -v`

**Implementation Note**: 這個 Phase 改動最多（23+ 個函數），建議使用 IDE 的 refactor 功能批量重新命名，減少手動錯誤。

---

## Phase 6: 文件同步（最小異動）

### Overview

以最小異動原則更新關鍵文件，只修改必要的術語和命令說明。避免大幅改寫或新增內容。

### 最小異動原則

**只修改**：

- CLI 命令範例（flash → deploy）
- 術語說明（明確指出 deploy 涵蓋 flash 和 SSH 部署）
- 錯誤的檔案路徑引用

**不修改**：

- 文件結構和章節
- 詳細的技術說明（除非直接相關）
- 歷史記錄和 changelog

### Changes Required

#### 1. README.md

**File**: `README.md`

**Changes**: 搜尋 "flash" 關鍵字，只更新以下位置：

**1.1 Quick Start 命令範例**:

```markdown
# Before

fwauto flash # Flash firmware to device
fwauto run # Build + Flash

# After

fwauto deploy # Deploy firmware to device
fwauto run # Build + Deploy
```

**1.2 Usage 說明**:

```markdown
# Before

### Flashing Firmware

...

# After

### Deploying Firmware

Deploy firmware to target device (supports STM32 flash and AM62x SSH deployment):
...
```

**1.3 Commands 清單**:

```markdown
# Before

- `fwauto flash` - Flash firmware to device

# After

- `fwauto deploy` - Deploy firmware to device
```

#### 2. ROADMAP.md

**File**: `ROADMAP.md`

**Changes**: 最小異動，只更新命令引用

找到 flash 相關的 roadmap item，更新命令名稱：

```markdown
# Before

- [x] Flash firmware to STM32 (`fwauto flash`)

# After

- [x] Deploy firmware to STM32 (`fwauto deploy`)
```

#### 3. CLAUDE.md

**File**: `CLAUDE.md`

**Changes**: 更新專案概述中的術語

**3.1 Development Commands 章節**:

```markdown
# Before

fwauto flash # Flash firmware to device

# After

fwauto deploy # Deploy firmware to device
```

**3.2 Architecture Overview 章節**:

如果有提到 flash_node，更新為：

```markdown
# Before

- `flash_node` - Firmware flashing via Maketool abstraction

# After

- `deploy_node` - Firmware deployment via Maketool abstraction (flash/SSH)
```

**3.3 Core Concepts 章節**:

```markdown
# Before

**Node System**: Each node is a pure function...

- `flash_node` - Firmware flashing via Maketool abstraction

# After

**Node System**: Each node is a pure function...

- `deploy_node` - Firmware deployment via Maketool abstraction
```

#### 4. 其他潛在文件

**如果存在以下文件，進行最小更新**:

- `docs/` 目錄下的任何文件：只更新命令範例
- `.github/` 目錄下的 workflow：更新 CLI 命令
- 任何 tutorial 或 guide：更新命令範例

### Success Criteria

#### Automated Verification:

- [x] Markdown 格式正確: `uv run python -m markdown README.md > /dev/null`（如果有 markdown 工具）
- [x] 沒有斷行的連結: `grep -r "fwauto flash" *.md`（應該找不到）✅
- [x] 新命令存在: `grep -r "fwauto deploy" *.md`（應該找到多處）
- [x] README.md 已更新：兩處 "Build + Flash" → "Build + Deploy"
- [x] ROADMAP.md 已更新：三處 flash → deploy

#### Manual Verification:

- [ ] 通讀 README.md 確認流暢
- [ ] 檢查沒有遺漏的 flash 命令引用
- [ ] 確認術語解釋清晰（deploy 涵蓋 flash 和 SSH）
- [ ] 驗證所有連結有效
- [ ] 確認文件結構沒有被破壞

**Implementation Note**: 這個 Phase 應該是最輕量的，重點是保持文件的一致性，而非大幅改寫。使用全域搜尋 "fwauto flash" 找到所有需要更新的位置。

---

## Testing Strategy

### Unit Tests

**覆蓋範圍**:

- State schema 定義
- Deploy operations 模組的所有函數
- Deploy node 的所有邏輯分支
- Config 屬性讀取

**關鍵測試**:

- `test_deploy_node_success` - 成功部署
- `test_deploy_node_with_binary_args` - 參數傳遞
- `test_deploy_node_rejects_dangerous_binary_args` - 安全驗證
- `test_deploy_operations_all_functions` - deploy_operations 完整測試

### Integration Tests

**端到端場景**:

1. AM62x 部署流程（init → build → deploy）
2. STM32 燒錄流程（init → build → deploy）
3. Run 命令（build + deploy）

**關鍵驗證**:

- Graph routing 正確性
- CLI 命令解析
- State 更新正確性

### Manual Testing Steps

**Phase 3 完成後的關鍵測試**:

1. **AM62x 平台測試**:

   ```bash
   cd /path/to/am62x/project
   fwauto deploy --binary-args "on"
   # 驗證：SCP 成功，SSH 執行成功，日誌記錄正確
   ```

2. **STM32 平台測試**:

   ```bash
   cd /path/to/stm32/project
   fwauto deploy
   # 驗證：ST-LINK 燒錄成功，開發板重啟
   ```

3. **Run 命令測試**:

   ```bash
   fwauto run
   # 驗證：Build → Deploy 流程完整
   ```

4. **錯誤處理測試**:
   ```bash
   # 測試網路斷線
   # 測試開發板離線
   # 測試錯誤的 binary_args
   ```

### Performance Considerations

**無性能影響**：此重構只是命名變更，不涉及邏輯修改，預期無性能影響。

**驗證點**:

- Deploy 時間應與之前相同
- Graph routing 延遲無增加
- CLI 啟動時間不變

---

## Migration Notes

### 對現有專案的影響

**✅ 無需遷移**（專案尚未 release）:

- 沒有外部使用者的專案
- 沒有需要保留的 config 檔案
- 可以直接更新所有程式碼

### 對開發者的影響

**需要注意的變更**:

1. CLI 命令從 `fwauto flash` 改為 `fwauto deploy`
2. Import path 從 `fwauto.nodes.flash` 改為 `fwauto.nodes.deploy`
3. Template 目錄從 `.fwauto/flash/` 改為 `.fwauto/deploy/`

**開發習慣調整**:

- 文件中提到 "flash" 時，統一改用 "deploy"
- 程式碼註解和 commit message 使用 "deploy" 術語

---

## Risk Mitigation

### Phase 3 特殊風險管控

**風險點**:

- Graph routing 邏輯錯誤可能導致 workflow 中斷
- CLI 命令解析錯誤可能導致無法執行
- execution_mode 錯誤傳遞可能導致錯誤的 node 執行

**緩解措施**:

1. **增量修改**: 先更新 graph.py，驗證通過後再更新 cli.py
2. **完整測試**: 每個修改後立即運行相關測試
3. **手動驗證**: 在真實環境測試所有 CLI 命令
4. **Rollback 準備**: 確保每個步驟都有 git commit，可以快速回退

### 整體風險管控

**Git 策略**:

```bash
# 每個 Phase 完成後 commit
git add .
git commit -m "Phase X: [描述]"

# 如果發現問題，立即回退
git reset --hard HEAD~1
```

**測試策略**:

- 每個 Phase 完成後運行完整測試套件
- Phase 3 和 5 完成後進行手動測試
- 最終在兩個平台上進行端到端測試

---

## References

### Original Research

- **Research Document**: `.ai/prpi/research/2025-11-12-flash-to-deploy-rename.md`
- **Decision Record**: 研究檔案 Decision Record 章節
- **影響範圍分析**: 研究檔案 Detailed Findings 章節

### Related Documents

- `.ai/prpi/research/2025-11-06-am62x-deployment-config.md` - AM62x 部署配置研究
- `.ai/prpi/implementations/2025-11-06-am62x-deployment-params.md` - 部署參數實施報告

### Code References

**核心檔案**:

- `src/fwauto/state.py:44-46` - State schema
- `src/fwauto/nodes/flash.py:48-202` - Flash node 實作
- `src/fwauto/flash_operations.py:1-422` - Flash operations 模組
- `src/fwauto/graph.py:28,58,82,98,120-127` - Graph routing
- `src/fwauto/config.py:109-160` - Deployment config

**測試檔案**:

- `tests/nodes/test_flash_makefile.py` - 13 個單元測試
- `tests/integration/test_flash_integration.py` - 3 個整合測試
- `tests/test_cli.py` - 7 個 CLI 測試

---

## Implementation Checklist

### Pre-Implementation

- [ ] 備份當前 codebase（git commit 或 branch）
- [ ] 確認所有測試通過（110/110）
- [ ] 確認開發環境設置正確

### Phase-by-Phase Execution

- [ ] **Phase 1**: State Schema 更新 ✅
- [ ] **Phase 2**: 核心模組重新命名 ✅
- [ ] **Phase 3**: Graph 與 CLI 整合（高風險）⚠️
- [ ] **Phase 4**: 配置與模板更新 ✅
- [ ] **Phase 5**: 測試完整更新 ✅
- [ ] **Phase 6**: 文件同步（最小異動）📝

### Post-Implementation

- [ ] 完整測試驗證（110/110 測試通過）
- [ ] 手動測試（STM32 + AM62x）
- [ ] 文件審查（README, CLAUDE.md）
- [ ] Git commit 與 push
- [ ] 更新 CHANGELOG（如果有）

---

## Success Metrics

**定量指標**:

- ✅ 110/110 測試通過
- ✅ 0 個 flash 相關命名殘留（除了 git 歷史）
- ✅ Type checking 0 errors
- ✅ Linting 0 warnings

**定性指標**:

- ✅ CLI 命令正常運作（deploy, run）
- ✅ STM32 和 AM62x 兩個平台都能正常部署
- ✅ 文件清晰易懂，術語一致
- ✅ 代碼可讀性提升

**驗證方式**:

```bash
# 1. 所有測試通過
uv run pytest

# 2. 無 flash 殘留
grep -r "flash" src/ --exclude-dir=.git | grep -v "deploy"  # 應該為空

# 3. CLI 正常
uv run fwauto deploy --help
uv run fwauto run --help

# 4. 實際部署測試（手動）
cd /path/to/test/project
uv run fwauto deploy
```

---

## Appendix: 命名對照表

### State 欄位

| 舊名稱         | 新名稱          | 位置        |
| -------------- | --------------- | ----------- |
| `flash_status` | `deploy_status` | state.py:44 |
| `flash_errors` | `deploy_errors` | state.py:45 |
| `flash_log`    | `deploy_log`    | state.py:46 |

### 模組檔案

| 舊名稱                | 新名稱                 |
| --------------------- | ---------------------- |
| `flash_operations.py` | `deploy_operations.py` |
| `nodes/flash.py`      | `nodes/deploy.py`      |

### 類別與函數

| 舊名稱                | 新名稱                 | 位置                     |
| --------------------- | ---------------------- | ------------------------ |
| `FlashConfig`         | `DeployConfig`         | deploy_operations.py:34  |
| `FlashResult`         | `DeployResult`         | deploy_operations.py:48  |
| `flash_firmware()`    | `deploy_firmware()`    | deploy_operations.py:363 |
| `flash_node()`        | `deploy_node()`        | nodes/deploy.py:48       |
| `route_after_flash()` | `route_after_deploy()` | graph.py:120             |

### CLI 命令

| 舊名稱            | 新名稱             |
| ----------------- | ------------------ |
| `fwauto flash`    | `fwauto deploy`    |
| `flash_command()` | `deploy_command()` |

### Template 目錄

| 舊名稱                 | 新名稱                  |
| ---------------------- | ----------------------- |
| `.fwauto/flash/`       | `.fwauto/deploy/`       |
| `templates/.../flash/` | `templates/.../deploy/` |

### 測試檔案

| 舊名稱                      | 新名稱                       |
| --------------------------- | ---------------------------- |
| `test_flash_makefile.py`    | `test_deploy_makefile.py`    |
| `test_flash_integration.py` | `test_deploy_integration.py` |
| `test_flash_node_*()`       | `test_deploy_node_*()`       |

---

**預期完成時間**: 4-6 小時（取決於手動測試的時間）

**建議執行方式**: 按 Phase 順序執行，每個 Phase 完成後 git commit，確保可以回退。Phase 3 完成後進行完整的手動測試再繼續。
