# 4D PluginLoader 程式 repo 結構檢查表

本文件記錄 2026-06-06 進入第四階段 4D PluginLoader 最小 contract 實作前，對程式 repo `hs-device-control-template` 的唯讀結構檢查、可承接範圍、候選修改檔案與停止線確認。

本檢查承接 [4D PluginLoader 邊界分析](phase-four-d-pluginloader-boundary-analysis.md)、[4D PluginLoader 決策確認表](phase-four-d-pluginloader-decision-confirmation.md) 與 [4D PluginLoader contract 草案 / 實作前確認表](phase-four-d-pluginloader-contract-preimplementation-checklist.md)。檢查結果只代表可在 Application 層評估最小 metadata / verification / state / audit contract，不代表授權建立 Loader、建立 `IPluginLoader` public contract、掃描 plugin folder、載入外部 DLL、執行外部程式碼、修改 Adapter public contract、修改 config schema 或接真實硬體。

## 0. 檢查狀態

| 項目 | 內容 |
|---|---|
| 文件狀態 | 已完成 |
| 檢查日期 | 2026-06-06 |
| 對應階段 | 第四階段 4D PluginLoader |
| 程式 repo | `hs-device-control-template` |
| 本機路徑 | `C:\Users\Evan\OneDrive - 鴻森智能科技有限公司\重要資料\hs-device-control-template` |
| 程式 branch | `poc/nmodbus-tcp` |
| 程式基準 commit | `a8462121ca0e62d4d4c4396497c564bc1540a339` |
| 工作樹 | 乾淨，無待提交變更 |
| 前置確認 | 使用者已確認 4D contract 七項決策 |
| 檢查結論 | 可在既有 `HS.DeviceControl.Application/Plugins` 補最小 contract 與測試，不需新增專案或修改 solution |

## 1. 檢查方法

| 檢查項目 | 實際結果 |
|---|---|
| `git status --short --branch` | 位於 `poc/nmodbus-tcp...origin/poc/nmodbus-tcp`，工作樹乾淨 |
| `git rev-parse HEAD` | `a8462121ca0e62d4d4c4396497c564bc1540a339` |
| Solution 盤點 | `HS.DeviceControl.Application`、`HS.DeviceControl.Application.Tests`、`HS.DeviceControl.ServiceHost`、`HS.DeviceControl.WebApi` 均已在 solution 內 |
| Plugin 關鍵字掃描 | 未找到 `IPluginLoader`、`PluginLoader`、`Assembly.Load`、`LoadFrom`、`LoadFile` |
| Application plugin 檔案讀取 | 已確認 `PluginDescriptor`、`PluginCapabilityDescriptor`、`PluginCatalogService`、`PluginCatalogResult`、`IPluginCatalogService` |
| ServiceHost 讀取 | 已確認 `ServiceHostRuntime` 只做 start / stop / status / QueueTask，不含 PluginLoader |
| Adapter 邊界讀取 | 已確認 `IDeviceAdapter`、`DeviceAdapterDispatcher`、`ExecuteResult` 既有 contract 可維持不變 |
| Config schema 讀取 | `devices.json`、`workflows.json`、`appsettings.json` 沒有 plugin path、plugin folder 或 DLL path 欄位 |
| 測試盤點 | 已有 `PluginCatalogServiceTests`，尚未有 verification / state / audit tests |

## 2. 現有可承接結構

| 區域 | 現況 | 對 4D 的判定 |
|---|---|---|
| `HS.DeviceControl.Application` | 已存在並只參考 Core / Adapters | 可承接 4D 第一版 contract，不新增專案 |
| `Application.Plugins` | 已有 metadata catalog 第一版 | 可在同資料夾補 verification / state / audit |
| `Application.Tests` | 已有 plugin catalog 單元測試 | 可補 4D contract 測試 |
| `ServiceHost` | 已有 lifecycle runtime 與 tests | 4D 可保留 ServiceHost lifecycle 邊界，但本輪不改 ServiceHost |
| `Adapters` | 已有 `IDeviceAdapter`、Dispatcher、Mock、Modbus | 4D 第一版不改 Adapter public contract |
| `Config` | 仍以 devices / workflows / appsettings 為主 | 4D 第一版不新增 plugin schema |
| `WebApi` | 4B 第一版已存在 | 4D 不新增 route、controller 或 HTTP plugin 管理 API |

## 3. Application.Plugins 目前狀態

| 檔案 | 現況 | 缺口 |
|---|---|---|
| `PluginDescriptor.cs` | 已有 `PluginId`、`Version`、`DisplayName`、`Capabilities`、`Checksum`，註解明確不含 DLL 載入或執行資訊 | 尚缺 `ContractVersion`、`Source`、`Enabled`、`DisabledReason` 等 4D contract 欄位候選 |
| `PluginCapabilityDescriptor.cs` | 已有 `CapabilityId`、`DeviceType`、`CommandName`、`AdapterContractVersion` | 可沿用，不需改 Adapter contract |
| `PluginCatalogService.cs` | 已檢查必填欄位與 sensitive marker，回傳標準 `PluginCatalogResult` | 尚未有 verification result、state 或 audit record |
| `PluginCatalogResult.cs` | 已有 `Success`、`Code`、`Message`、`Error` | 可作為 result 風格參考 |
| `IPluginCatalogService.cs` | 只提供 `ListPlugins()`，註解明確不負責載入 DLL 或執行 Plugin | 不建議改成 Loader contract |
| `PluginCatalogServiceTests.cs` | 已覆蓋 metadata 不載入 DLL、缺少 PluginId、敏感資訊、缺少 capability | 可延伸 verification / audit 測試 |

## 4. 明確尚未存在的候選檔案

| 檔案 | 目前狀態 | 判定 |
|---|---|---|
| `src/HS.DeviceControl.Application/Plugins/PluginVerificationResult.cs` | 不存在 | 可作為 4D 最小 contract 新增候選 |
| `src/HS.DeviceControl.Application/Plugins/PluginLoadState.cs` | 不存在 | 可作為 4D state contract 新增候選 |
| `src/HS.DeviceControl.Application/Plugins/PluginAuditRecord.cs` | 不存在 | 可作為 audit summary contract 新增候選 |
| `src/HS.DeviceControl.Application/Plugins/IPluginLoader.cs` | 不存在 | 符合停止線，不應新增 |
| `src/HS.DeviceControl.Application/Plugins/PluginLoader.cs` | 不存在 | 符合停止線，不應新增 |
| `tests/HS.DeviceControl.Application.Tests/PluginVerificationResultTests.cs` | 不存在 | 可新增單元測試候選 |
| `tests/HS.DeviceControl.Application.Tests/PluginAuditRecordTests.cs` | 不存在 | 可新增單元測試候選 |

## 5. ServiceHost / Adapter / Config 邊界

| 邊界 | 檢查結果 | 本輪判定 |
|---|---|---|
| ServiceHost lifecycle | `ServiceHostRuntime` 已處理 start / stop / status / QueueTask，啟動時連接 Adapter 並查 health | 4D 可不改 ServiceHost；未來 Loader lifecycle 需另行確認 |
| Adapter dispatcher | `DeviceAdapterDispatcher` 依 `DeviceCommand.DeviceId` 分派，支援 connect / disconnect / status / execute | 不修改 `IDeviceAdapter`、`ExecuteResult`、`DeviceCommand` |
| Config schema | `devices.json` 與 `workflows.json` 仍以 `DeviceId` / `CommandName` 為核心；`appsettings.json` 無 plugin 區塊 | 不新增 plugin folder、DLL path、來源白名單設定 |
| WebApi | 既有 WebApi controller 不含 plugin route | 不新增 plugin HTTP API |
| External DLL | 關鍵字未命中 `Assembly.Load`、`LoadFrom`、`LoadFile` | 不載入外部 DLL，保持文件停止線 |

## 6. 若進入最小 contract 實作的候選範圍

以下只是候選清單，不代表本文件已修改程式 repo。

| 類型 | 候選檔案 | 建議內容 |
|---|---|---|
| 新增 state enum | `src/HS.DeviceControl.Application/Plugins/PluginLoadState.cs` | 定義 `Discovered`、`Verified`、`Rejected`、`Disabled`、`Faulted`；`Loaded` 若保留，需標示為未授權載入狀態 |
| 新增 verification result | `src/HS.DeviceControl.Application/Plugins/PluginVerificationResult.cs` | 回傳 `Success`、`Code`、`Message`、`PluginId`、`State`、`Checks`、`Warnings`、`TimeTakenMs` |
| 新增 audit record | `src/HS.DeviceControl.Application/Plugins/PluginAuditRecord.cs` | 記錄 `AuditId`、`PluginId`、`Decision`、`Reason`、`Operator`、`Source`、`Checksum`、`CreatedAtUtc` |
| 視需要新增 check item | `src/HS.DeviceControl.Application/Plugins/PluginVerificationCheck.cs` | 若 `Checks` 需結構化，定義檢查名稱、成功狀態、摘要訊息 |
| 擴充 metadata | `src/HS.DeviceControl.Application/Plugins/PluginDescriptor.cs` | 以相容方式補 `ContractVersion`、`Source`、`Enabled`、`DisabledReason` |
| 擴充驗證 | `src/HS.DeviceControl.Application/Plugins/PluginCatalogService.cs` | 補 source / contract version / disabled metadata 驗證，仍不讀檔 |
| 補錯誤碼 | `src/HS.DeviceControl.Application/Common/ApplicationErrorCodes.cs` | 保留 `APP-033x` 區段，例如 verification / disabled / audit invalid |
| 新增測試 | `tests/HS.DeviceControl.Application.Tests/*` | 覆蓋 required fields、sensitive data、checksum mismatch、version mismatch、disabled、audit sanitization |

## 7. 明確不修改

| 不修改項目 | 原因 |
|---|---|
| `HS.DeviceControl.sln` | SDK-style project 會自動納入新 `.cs` 檔；不新增專案 |
| `HS.DeviceControl.Core` public contract | 4D 最小 contract 屬 Application 層 metadata / audit，不進 Core |
| `HS.DeviceControl.Adapters` public contract | 不改 `IDeviceAdapter`、`ExecuteResult`、`DeviceCommand` |
| `HS.DeviceControl.ServiceHost` | 不建立 Loader lifecycle，不改啟動方式 |
| `HS.DeviceControl.WebApi` | 不新增 plugin route、controller、DTO 或 auth |
| `devices.json`、`workflows.json`、`appsettings.json` | 不新增 plugin schema、DLL path、正式來源或敏感資訊 |
| `Infrastructure.MySql` | 不寫 DB、不建 audit table、不做 DDL / ALTER TABLE |
| 外部 DLL / plugin folder | 不掃描、不載入、不執行 |

## 8. 建議驗收條件

| 驗收項目 | 通過基準 |
|---|---|
| Application plugin contract 編譯 | 新增 / 修改的 Application plugin contract 可 build |
| Application plugin tests | `PluginCatalogServiceTests` 延伸與新增 verification / audit tests 通過 |
| 停止線測試 | 測試不呼叫 `Assembly.Load`、`LoadFrom`、`LoadFile`，不依賴 DLL file |
| Config 不變 | 不修改 sample config 與 config model schema |
| Adapter 不變 | 不修改 Adapter public contract 與 dispatcher 行為 |
| 回歸測試 | `dotnet test tests/HS.DeviceControl.Application.Tests/HS.DeviceControl.Application.Tests.csproj` 通過；必要時再跑 full solution |

## 9. 結論

程式 repo 結構允許 4D 進入「最小 Application plugin contract」實作評估。建議第一版只補 `Application.Plugins` 的 metadata / verification / state / audit model 與 Application.Tests，不新增 Loader、不新增 `IPluginLoader`、不掃描 plugin folder、不載入外部 DLL、不改 Adapter public contract、不改 config schema。

建議下一步：進入 4D 最小 contract 程式實作前最後確認，確認候選檔案與測試策略後，再決定是否修改程式 repo。
