# 4D PluginLoader contract 草案 / 實作前確認表

本文件承接 [4D PluginLoader 邊界分析](phase-four-d-pluginloader-boundary-analysis.md) 與 [4D PluginLoader 決策確認表](phase-four-d-pluginloader-decision-confirmation.md)，整理 4D 進入任何程式修改前需要再次確認的 contract 草案、候選檔案、測試策略與停止線。

本文件記錄使用者已同意 4D contract 七項文件型決策；此同意只代表可進入程式 repo 唯讀結構檢查與最小 contract 實作評估，不代表已同意建立 PluginLoader、建立 `IPluginLoader` public contract、掃描 plugin folder、載入外部 DLL、執行外部程式碼、修改 `IDeviceAdapter` public contract、修改 config schema、導入 plugin framework、保存正式 DLL 路徑、接真實硬體、執行正式 DB DDL 或改變程式啟動方式。

## 0. 確認狀態

| 項目 | 內容 |
|---|---|
| 文件狀態 | 已確認 |
| 整理日期 | 2026-06-06 |
| 確認日期 | 2026-06-06 |
| 對應階段 | 第四階段 4D PluginLoader contract |
| 前置文件 | 4D 邊界分析、4D 決策確認表 |
| 程式 repo | `hs-device-control-template` |
| 程式 branch | `poc/nmodbus-tcp` |
| 程式基準 commit | `a846212 新增 4C ServiceHost 第一版與驗收測試` |
| 已完成前置 | 4A 邊界與決策確認、4B WebApi 第一版、4C ServiceHost 第一版、4D 邊界分析、4D 決策確認 |
| 本文件目標 | 固定 metadata、verification result、state、audit、候選檔案、測試策略與停止線 |
| 確認後可進入 | 程式 repo 唯讀結構檢查與最小 contract 實作評估 |
| 本文件仍不做 | 不建立 Loader、不載入 DLL、不掃描 plugin folder、不改 Adapter / config / DB、不接真實硬體 |

## 1. Contract 第一版定位

4D contract 第一版只應定義「如何描述、驗證、拒絕、停用、追蹤 plugin 候選物件」，不是讓 plugin 立即可執行。

| 原則 | 說明 |
|---|---|
| Contract 先於 Loader | 先固定資料模型、狀態、錯誤與測試語意，不建立實際 Loader。 |
| Metadata 不等於載入授權 | metadata 通過格式檢查仍不得自動進入 `Loaded`。 |
| Verification 是獨立結果 | checksum、來源、版本、敏感資訊與人工核准都要回到標準結果。 |
| State 不直接執行 | `Discovered`、`Verified`、`Rejected`、`Disabled`、`Faulted` 只代表狀態語意，不代表呼叫 DLL。 |
| Audit 先採安全摘要 | 可先定義 audit record，不寫 DB、不保存正式路徑或敏感資訊。 |
| Lifecycle 由 ServiceHost 承接 | 未來若有 Loader lifecycle，應由 ServiceHost 組裝，不由 WebApi Controller 載入 DLL。 |

## 2. Metadata contract 草案

| 欄位 | 建議語意 | 第一版限制 |
|---|---|---|
| `PluginId` | Plugin 唯一識別，需穩定且不可空白。 | 不得含路徑、IP、Port 或 secret。 |
| `DisplayName` | 人員可讀名稱。 | 不作為安全判斷依據。 |
| `Version` | Plugin 版本。 | 需與 contract version 分開。 |
| `ContractVersion` | 目標 Application / Adapter contract 版本。 | 不相容時只能拒絕，不自動降級。 |
| `Source` | plugin 來源，例如 repository fixture 或受控白名單來源。 | 不接受任意資料夾。 |
| `Checksum` | artifact checksum 宣告值。 | 本階段只定義欄位與比對規則，不讀檔。 |
| `Capabilities` | 對應 3D capability、device type、command name。 | 不得繞過 Resource / Command / Adapter 邊界。 |
| `Enabled` | 是否允許被 catalog 顯示為可候選。 | 不代表可載入或可執行。 |
| `DisabledReason` | 停用原因。 | 不保存敏感資訊或完整例外。 |

## 3. Verification result 草案

| 欄位 | 建議語意 |
|---|---|
| `Success` | 驗證是否通過。 |
| `Code` | 標準錯誤碼，建議延續 Application `APP-03xx` 區段或另列 `APP-04xx` 候選。 |
| `Message` | 安全摘要，不包含 secret、正式路徑、完整 stack trace。 |
| `PluginId` | 對應 plugin identity。 |
| `State` | 驗證後狀態，例如 `Verified`、`Rejected`、`Disabled`、`Faulted`。 |
| `Checks` | 來源、checksum、版本、敏感資訊、人工核准等子檢查摘要。 |
| `Warnings` | 非阻擋但需提示的問題。 |
| `TimeTakenMs` | 驗證耗時。 |

## 4. State contract 草案

| 狀態 | 語意 | 是否可執行 |
|---|---|---|
| `Discovered` | 已發現 metadata 或候選描述。 | 否 |
| `Verified` | metadata、來源、checksum、版本與必要核准通過。 | 否，本階段仍不載入 |
| `Rejected` | 驗證失敗或來源不可信。 | 否 |
| `Disabled` | 被人工或策略停用。 | 否 |
| `Faulted` | 驗證或未來 lifecycle 發生錯誤。 | 否 |
| `Loaded` | 保留給未來 Loader 實作。 | 本階段不可使用 |

## 5. Audit contract 草案

| 欄位 | 建議語意 | 限制 |
|---|---|---|
| `AuditId` | 單筆 audit 識別。 | 可用記憶體或測試用 id，不寫正式 DB。 |
| `PluginId` | 對應 plugin。 | 不可空白。 |
| `Decision` | `Verified`、`Rejected`、`Disabled`、`Faulted` 等結果。 | 不等於執行授權。 |
| `Reason` | 人工或系統原因摘要。 | 不包含 secret、正式路徑或完整 exception。 |
| `Operator` | 操作者或系統來源。 | 若無正式帳號，只能用測試值。 |
| `Source` | 安全來源摘要。 | 不保存完整正式 DLL path。 |
| `Checksum` | checksum 摘要。 | 可遮罩或縮短。 |
| `CreatedAtUtc` | 發生時間。 | 使用 UTC。 |

## 6. 候選程式檔案

以下只是使用者確認後的候選範圍，尚未授權修改程式 repo。

| 類型 | 候選檔案或位置 |
|---|---|
| Application plugin contract | `src/HS.DeviceControl.Application/Plugins/*` |
| Verification model | `src/HS.DeviceControl.Application/Plugins/PluginVerificationResult.cs` |
| State enum | `src/HS.DeviceControl.Application/Plugins/PluginLoadState.cs` |
| Audit model | `src/HS.DeviceControl.Application/Plugins/PluginAuditRecord.cs` |
| Catalog extension | 既有 `IPluginCatalogService` / `PluginCatalogService`，僅評估是否補只讀查詢 |
| 測試 | `tests/HS.DeviceControl.Application.Tests/Plugins/*` |
| Solution | 原則上不新增專案，不需修改 `.sln` |
| 文件 | contract 決策確認、程式 repo 結構檢查、實作紀錄、完成稽核、驗收紀錄 |

## 7. 測試策略

| 測試 | 目的 | 本輪是否可確認 |
|---|---|---|
| Metadata required fields | 驗證必要欄位缺漏會回標準錯誤。 | 可確認 |
| Sensitive data rejection | 驗證 metadata 內含 password、token、connection string、正式 IP / Port 時被拒絕。 | 可確認 |
| Checksum mismatch | 驗證 checksum 不符會回 `Rejected`。 | 可確認，但不讀真實 DLL |
| Version mismatch | 驗證 contract version 不相容會被拒絕。 | 可確認 |
| Disabled plugin | 驗證停用 plugin 不可被視為可載入。 | 可確認 |
| Audit summary | 驗證 audit 不含 secret 或正式路徑。 | 可確認 |
| Loader lifecycle | 驗證 load / unload / recover。 | 不可確認，需另行授權 |
| External DLL test | 使用測試 DLL 驗證載入。 | 不可確認，需另行授權 |

## 8. 七項 contract 確認表

使用者已同意以下七項，可進入程式 repo 唯讀結構檢查與最小 contract 實作評估。

| 編號 | 決策項 | 確認結果 | 影響 |
|---:|---|---|---|
| 1 | 4D contract 第一版放在 Application `Plugins` 區域 | 已同意，第一版只評估 Application 層 model / service extension。 | 不新增 Loader 專案。 |
| 2 | 第一版新增或補齊 metadata / verification / state / audit contract | 已同意，可盤點候選 model 與 tests。 | 不載入 DLL。 |
| 3 | 不建立 `IPluginLoader` public contract | 已同意，Loader 仍留在後續階段。 | 避免過早固定載入 API。 |
| 4 | 不修改 `IDeviceAdapter` public contract | 已同意，plugin capability 必須經 Adapter / dispatcher 邊界承接。 | 保持既有分層。 |
| 5 | 不修改 config schema，不保存正式 DLL path 或敏感資訊 | 已同意，只做 model / test，不改 `devices.json`、`workflows.json`、`appsettings.json`。 | 避免未成熟 schema 進正式契約。 |
| 6 | 測試只做 metadata / verification / audit，不做外部 DLL | 已同意，測試不呼叫 assembly loading API。 | 降低外部程式碼風險。 |
| 7 | 程式修改前先做唯讀結構檢查並回報候選檔案 | 已同意，先盤點程式 repo，再決定是否實作。 | 保留使用者確認點。 |

使用者確認文字：

```text
4D contract 確認：1. 同意 ... 7. 同意
```

## 9. 仍需停止的項目

即使本文件七項全部同意，除非使用者另外明確授權，仍不得自動執行以下項目：

- 不建立 `PluginLoader` 程式。
- 不建立 `IPluginLoader` public contract。
- 不掃描 plugin folder。
- 不載入外部 DLL。
- 不呼叫 `Assembly.Load`、`LoadFrom`、`LoadFile` 或類似 API。
- 不執行外部 plugin 程式碼。
- 不新增或更換 plugin framework / DI framework / sandbox 套件。
- 不修改 `IDeviceAdapter` public contract。
- 不修改 Core / Adapters / Infrastructure / Application 既有 public method 簽章。
- 不修改 `devices.json`、`workflows.json`、`appsettings.json` schema。
- 不保存密碼、Token、IP、Port、完整 connection string、正式 DLL 路徑或正式環境資訊。
- 不執行 DB 寫入、DDL、ALTER TABLE 或正式 Apply。
- 不接真實硬體或案場客製 plugin。

## 10. 建議下一步

七項確認已完成，且程式 repo 唯讀結構檢查已整理完成。下一步建議進入 4D 最小 Application plugin contract 實作前最後確認，確認 `PluginLoadState`、`PluginVerificationResult`、`PluginAuditRecord` 與測試策略後，再決定是否修改程式 repo。
