# 驗證節點紀錄

本文件記錄已完成功能節點的實際驗證結果，用來確認「程式測試通過」以外，使用者也能理解目前功能實際跑起來的效果。

## 驗證摘要

| 項目 | 內容 |
|---|---|
| 驗證日期 | 2026-05-22 |
| 程式 repo | [`hs-device-control-template`](https://github.com/Hongsen-tw/hs-device-control-template) |
| 驗證 commit | `60e61b5` |
| 驗證環境 | Windows、.NET SDK 9.x 執行 .NET 5.0 專案 |
| 自動測試結果 | `dotnet test` 通過 49 個測試 |
| 注意事項 | .NET 5.0 已 EOL，因此執行時會出現 `NETSDK1138` 警告，屬於目前指定版本的預期現象 |

## Config Loader

| 項目 | 內容 |
|---|---|
| 驗證節點 | Config Loader |
| 驗證目的 | 確認系統可以從指定資料夾載入 `devices.json`、`workflows.json`、`appsettings.json`，並在載入後交由 `ConfigValidator` 驗證 |
| 驗證方式 | 執行 `dotnet test`，檢查 `ConfigLoaderTests` |
| 實際結果 | 可成功載入 `samples/config`；資料夾不存在、缺少必要檔案、JSON 格式錯誤、載入後驗證失敗，都會回傳失敗結果與可讀錯誤 |
| 是否符合預期 | 符合 |
| 發現問題或限制 | 第一階段僅從檔案系統載入 JSON，尚未導入資料庫或遠端設定中心 |
| 建議下一步 | 保留目前 JSON 設定作為第一階段來源，後續若要支援多案場或雲端管理，再討論設定來源抽象化 |

## Config Mapper

| 項目 | 內容 |
|---|---|
| 驗證節點 | Config Mapper |
| 驗證目的 | 確認 `WorkflowConfiguration` 可以轉成 `WorkflowEngine` 可執行的 `WorkflowDefinition` |
| 驗證方式 | 執行 `dotnet test`，檢查 `WorkflowConfigurationMapperTests` 與流程模擬測試 |
| 實際結果 | 可將 sample workflow 轉成可執行定義，並由 `WorkflowEngine` 完成燈號導引 + Sensor 驗證代表流程 |
| 是否符合預期 | 符合 |
| 發現問題或限制 | `DeviceId` 已帶入 `WorkflowNode` 與 Log，但目前仍是單一 Mock Adapter，尚未依 `DeviceId` 分派到不同 Adapter 實例 |
| 建議下一步 | 評估是否建立 Adapter 分派器，讓未來可依 `DeviceId` 選擇對應設備 Adapter |

## ConsoleHost 設定檔啟動

| 項目 | 內容 |
|---|---|
| 驗證節點 | ConsoleHost 設定檔啟動 |
| 驗證目的 | 確認 ConsoleHost 可以用設定檔啟動代表流程，而不是寫死程式內流程 |
| 驗證方式 | 執行 `dotnet run --project src\HS.DeviceControl.ConsoleHost -- samples\config LIGHT_SENSOR_DEMO` |
| 實際結果 | ConsoleHost 顯示 `Loading config from: samples\config`，接著依序完成 `light-on` 與 `sensor-verify`，Log 可看到 `deviceId="LED_001"` 與 `deviceId="SENSOR_001"`，最後輸出 `Workflow completed.` |
| 是否符合預期 | 符合 |
| 發現問題或限制 | 目前仍使用 Mock Adapter，不接真實硬體；ConsoleHost 適合第一階段 Debug，不是正式背景服務入口 |
| 建議下一步 | 進入設備離線、逾時與重試驗證案例，確認失敗路徑也能保留 DeviceId 與錯誤資訊 |

### ConsoleHost 實際輸出摘要

```text
Loading config from: samples\config
2026-05-22T00:26:20.6077037+08:00 level="INFO" taskId="demo-task" nodeId="light-on" nodeName="開啟燈號" deviceId="LED_001" command="LightOn" status="completed" retryCount=0 timeTakenMs=0 errorCode="NONE" message="Mock command 'LightOn' completed."
2026-05-22T00:26:20.6188458+08:00 level="INFO" taskId="demo-task" nodeId="sensor-verify" nodeName="Sensor 驗證" deviceId="SENSOR_001" command="SensorVerify" status="completed" retryCount=0 timeTakenMs=0 errorCode="NONE" message="Mock command 'SensorVerify' completed."
Workflow completed.
```

## 節點失敗與重試驗證

| 項目 | 內容 |
|---|---|
| 驗證節點 | 節點失敗、逾時與重試 |
| 驗證目的 | 確認 WorkflowEngine 可處理設備離線、節點逾時、重試後成功、重試耗盡失敗 |
| 驗證方式 | 執行 `dotnet test`，檢查 `LightSensorWorkflowTests` 中的失敗與重試案例 |
| 實際結果 | 設備離線會回傳 `DEV-0002`；節點逾時會回傳 `WF-0004`；`RetryCount=1` 時會最多執行 2 次；重試成功會完成節點，重試耗盡會失敗 |
| 是否符合預期 | 符合 |
| 發現問題或限制 | 目前逾時判斷是在同步命令返回後計算耗時，尚未做到執行中取消命令 |
| 建議下一步 | 評估 Adapter 分派器或 TaskEngine，決定是否需要更完整的取消、暫停與背景執行模型 |

## Adapter 分派器

| 項目 | 內容 |
|---|---|
| 驗證節點 | Adapter Dispatcher |
| 驗證目的 | 確認 ConsoleHost 可依 `DeviceId` 將命令分派到不同設備 Adapter，避免所有命令共用單一 Mock Adapter |
| 驗證方式 | 執行 `dotnet test`，檢查 `DeviceAdapterDispatcherTests`；再執行 `dotnet run --project src\HS.DeviceControl.ConsoleHost -- samples\config LIGHT_SENSOR_DEMO` |
| 實際結果 | `DeviceAdapterDispatcher` 可依 `LED_001`、`SENSOR_001` 選擇不同 Adapter；未知 DeviceId 會回傳 `DEV-0003`；ConsoleHost 代表流程仍可完成 |
| 是否符合預期 | 符合 |
| 發現問題或限制 | 目前 Dispatcher 只負責 Execute 分派，尚未管理 Connect、Disconnect、GetStatus 等設備生命週期 |
| 建議下一步 | 規劃 TaskEngine，或先補 Adapter 生命週期介面，讓真實設備接入時能管理連線狀態 |

## TaskEngine 最小版本

| 項目 | 內容 |
|---|---|
| 驗證節點 | TaskEngine |
| 驗證目的 | 確認 `TaskEngine` 可將 Workflow 包裝成 `TaskExecutionRecord` 任務紀錄，並追蹤 TaskId、WorkflowId、狀態、開始時間、結束時間、耗時與執行結果 |
| 驗證方式 | 執行 `dotnet test`，檢查 `TaskEngineTests`；再執行 `dotnet run --project src\HS.DeviceControl.ConsoleHost -- samples\config LIGHT_SENSOR_DEMO` 確認既有 ConsoleHost 啟動方式不受影響 |
| 實際結果 | 成功 Workflow 會產生 `Completed` 任務紀錄；失敗 Workflow 會產生 `Failed` 任務紀錄並保留錯誤；空白 TaskId 會自動產生識別碼 |
| 是否符合預期 | 符合 |
| 發現問題或限制 | 目前 TaskEngine 是同步執行包裝，尚未支援背景排程、暫停、取消或任務儲存 |
| 建議下一步 | 決定下一階段要先補 Adapter 連線生命週期，或讓 TaskEngine 支援取消與背景執行 |

## Adapter 生命週期

| 項目 | 內容 |
|---|---|
| 驗證節點 | Adapter Connect / Disconnect / GetStatus |
| 驗證目的 | 確認 `IDeviceAdapter` 具備最小連線生命週期，並透過 `DeviceConnectionStatus` 讓 Mock Adapter 表達 `Disconnected`、`Connected` 狀態，且未連線時命令會回傳 `DEV-0002` |
| 驗證方式 | 執行 `dotnet test`，檢查 `MockDeviceAdapterTests` 與 `DeviceAdapterDispatcherTests`；再執行 `dotnet run --project src\HS.DeviceControl.ConsoleHost -- samples\config LIGHT_SENSOR_DEMO` |
| 實際結果 | `Connect()` 會讓 Mock Adapter 進入 `Connected`；`Disconnect()` 會回到 `Disconnected`；Dispatcher 可一次連線或斷線所有註冊 Adapter；ConsoleHost 啟動時會先連線再執行代表流程 |
| 是否符合預期 | 符合 |
| 發現問題或限制 | 目前狀態仍是記憶體內 Mock 狀態，尚未對應真實 PLC、IO、Serial、TCP 或 Modbus 連線細節 |
| 建議下一步 | 討論真實設備 Adapter 的設定欄位、連線失敗重試策略與狀態查詢格式 |

## 開發狀態自動同步

| 項目 | 內容 |
|---|---|
| 驗證節點 | 開發狀態自動同步 |
| 驗證目的 | 確認程式 repo push 後，能透過 GitHub Actions 通知文件 repo，並自動更新 `status.json`、`public/status.json` 與 Cloudflare Pages 首頁開發狀態。 |
| 驗證方式 | 在程式 repo `poc/nmodbus-tcp` 分支建立測試 commit `3c05cf5`，觸發 `notify-docs` workflow；確認文件 repo 自動產生 commit `1e1fd11`，再檢查公開 `status.json`。 |
| 實際結果 | 文件 repo 已自動產生 `1e1fd11 同步程式 repo 開發狀態`；公開 `status.json` 顯示 `shortCommit=3c05cf5`、`branch=poc/nmodbus-tcp`、`source=github-actions`。 |
| 是否符合預期 | 符合 |
| 發現問題或限制 | PowerShell 終端直接顯示公開 JSON 時，中文可能因終端編碼顯示成亂碼；使用 UTF-8 JSON parser 檢查時，`commitMessage`、`stage`、`nextStep` 均為正確中文。 |
| 建議下一步 | 後續每次程式 repo push 後，以首頁與 `status.json` 確認開發狀態是否更新；若未更新，優先檢查程式 repo `notify-docs` workflow 與文件 repo `apply-code-status` workflow。 |

## 整體判斷

| 項目 | 判斷 |
|---|---|
| Config Loader | 可作為第一階段設定入口 |
| Config Mapper | 可把設定檔流程轉成可執行流程，並保留 DeviceId |
| ConsoleHost | 可作為第一階段代表流程驗證入口 |
| Adapter 分派器 | 可依 DeviceId 分派到不同設備 Adapter |
| TaskEngine | 可追蹤單次 Workflow 任務執行紀錄 |
| Adapter 生命週期 | 可管理 Mock Adapter 連線、斷線與狀態查詢 |
| Log 呈現 | 已可看到 TaskId、NodeId、NodeName、DeviceId、Command、Status、RetryCount、TimeTakenMs、ErrorCode、Message |
| 是否可進下一步 | 可以 |

## 下一步建議

1. 討論真實設備 Adapter 的設定欄位與連線失敗處理。
2. 評估 TaskEngine 是否需要支援暫停、取消與背景執行。
3. 討論同步 Timeout 是否足夠，或後續需要支援可取消的非同步命令。

## ConsoleHost Schema Dry Run 顯示人工驗證

| 項目 | 內容 |
|---|---|
| 驗證節點 | ConsoleHost Schema Dry Run 顯示人工驗證 |
| 驗證目的 | 確認 ConsoleHost 可清楚顯示 Dry Run 摘要、SQL preview 與安全警告 |
| 驗證方式 | `dotnet run --project src\HS.DeviceControl.ConsoleHost` |
| 實際結果 | Workflow 正常完成，並顯示 `Schema dry run:`、`CREATE TABLE IF NOT EXISTS task_executions` 與 `Dry Run 不會連線或修改 MySQL` |
| 是否符合預期 | 符合預期 |
| 詳細紀錄 | [consolehost-schema-dry-run-display-verification-record.md](./consolehost-schema-dry-run-display-verification-record.md) |
| 建議下一步 | 進入 Schema Initializer DryRun 流程設計 |
