# 4D 最小 Application plugin contract 實作與驗收紀錄

本文件承接 [4D 最小 Application plugin contract 實作前最後確認表](phase-four-d-pluginloader-application-contract-preimplementation-checklist.md)，記錄 4D 最小 Application plugin contract 的程式實作範圍、測試結果與停止線。

本次完成不代表真正 PluginLoader 已完成，不代表建立 `IPluginLoader`，不代表掃描 plugin folder、載入外部 DLL、執行外部 plugin 程式碼、修改 Adapter public contract、修改 config schema、執行 DB DDL 或接真實硬體。

## 0. 驗收狀態

| 項目 | 內容 |
|---|---|
| 文件狀態 | 已完成 |
| 整理日期 | 2026-06-06 |
| 對應階段 | 第四階段 4D 最小 Application plugin contract |
| 程式 repo | `hs-device-control-template` |
| 程式 branch | `poc/nmodbus-tcp` |
| 前一程式基準 commit | `a846212 新增 4C ServiceHost 第一版與驗收測試` |
| 4D 程式 commit | [`6f34bb9`](https://github.com/Hongsen-tw/hs-device-control-template/commit/6f34bb94de8fe9a63303fe672f7de92c98f07274) `新增 4D 最小 Application plugin contract` |
| push 狀態 | 已 push 至 `origin/poc/nmodbus-tcp` |
| GitHub Actions | Run [`27064992270`](https://github.com/Hongsen-tw/hs-device-control-template/actions/runs/27064992270) success |
| 使用者確認 | `4D 最小 contract 確認` 七項皆同意 |
| 本次定位 | Application 層 plugin metadata / verification / state / audit 最小 contract |
| 本次驗收結論 | 通過；Application.Tests 40 passed，solution tests 492 passed，程式 repo commit / push / Actions success |

## 1. 程式實作範圍

| 類型 | 檔案 | 說明 |
|---|---|---|
| 新增 state enum | `src/HS.DeviceControl.Application/Plugins/PluginLoadState.cs` | 定義 `Discovered`、`Verified`、`Rejected`、`Disabled`、`Faulted`、`Loaded`；`Loaded` 僅保留未來語意，第一版不產生。 |
| 新增 verification check | `src/HS.DeviceControl.Application/Plugins/PluginVerificationCheck.cs` | 定義單一檢查項目的 `Name`、`Success`、`Code`、`Message`。 |
| 新增 verification result | `src/HS.DeviceControl.Application/Plugins/PluginVerificationResult.cs` | 定義 `Success`、`Code`、`Message`、`PluginId`、`State`、`Checks`、`Warnings`、`TimeTakenMs`、`Error`。 |
| 新增 audit record | `src/HS.DeviceControl.Application/Plugins/PluginAuditRecord.cs` | 定義 `AuditId`、`PluginId`、`Decision`、`Reason`、`Operator`、`Source`、`Checksum`、`CreatedAtUtc`。 |
| 新增內部安全 helper | `src/HS.DeviceControl.Application/Plugins/PluginContractTextSafety.cs` | 只供 Application plugin contract 內部判斷 sensitive marker 與疑似正式路徑，不是 public Loader contract。 |
| 擴充 descriptor | `src/HS.DeviceControl.Application/Plugins/PluginDescriptor.cs` | 相容擴充 `ContractVersion`、`Source`、`Enabled`、`DisabledReason`，既有 constructor 仍保留。 |
| 擴充 catalog validation | `src/HS.DeviceControl.Application/Plugins/PluginCatalogService.cs` | 補 contract version、source、disabled reason 與 sensitive metadata 驗證；仍不讀檔、不掃描 folder。 |
| 擴充錯誤碼 | `src/HS.DeviceControl.Application/Common/ApplicationErrorCodes.cs` | 新增 `APP-0332` 至 `APP-0335`。 |
| 新增與擴充測試 | `tests/HS.DeviceControl.Application.Tests/*` | 補 verification result、audit record、catalog contract version/source/disabled 驗證。 |

## 2. Contract 行為

| Contract | 行為 |
|---|---|
| `PluginLoadState` | 成功驗證只回 `Verified`；`Loaded` 只保留未來語意。 |
| `PluginVerificationResult.Ok` | 回 `Success=true`、`Code=NONE`、`State=Verified`，可承接 checks / warnings / timeTakenMs。 |
| `PluginVerificationResult.Fail` | 回 `Success=false`，若外部傳入 `Loaded` 會降為 `Rejected`，避免第一版產生載入狀態。 |
| `PluginVerificationCheck` | message 會做敏感資訊與路徑遮罩。 |
| `PluginAuditRecord` | 不寫 DB，會遮罩 token / password / connection string / 正式路徑。 |
| `PluginDescriptor` | metadata 加上 contract version、source、enabled、disabled reason；啟用不代表可載入 DLL。 |
| `PluginCatalogService` | 只驗 metadata，不建立 Loader，不讀取 DLL，不掃描 plugin folder。 |

## 3. 驗證紀錄

| 驗證項目 | 指令 / 方法 | 結果 |
|---|---|---|
| Application tests 初次執行 | `dotnet test tests/HS.DeviceControl.Application.Tests/HS.DeviceControl.Application.Tests.csproj` | 第一次因 NuGet AppData lock 無法取得鎖定而中止，不是測試失敗。 |
| Application tests 重跑 | `dotnet test tests/HS.DeviceControl.Application.Tests/HS.DeviceControl.Application.Tests.csproj` | Passed：40 passed / 0 failed / 0 skipped。 |
| Solution tests | `dotnet test HS.DeviceControl.sln` | Passed：492 passed / 0 failed / 0 skipped。 |
| Loader / DLL 停止線掃描 | `rg "Assembly\.Load\|LoadFrom\(\|LoadFile\(\|IPluginLoader\|class PluginLoader" src tests samples` | 無命中。 |
| diff check | `git diff --check` | 無 whitespace error；僅有 LF/CRLF 提醒。 |
| 尾端空白掃描 | `rg "\s+$"` 掃描本次程式檔 | 無命中。 |

## 4. 測試覆蓋

| 測試 | 驗證內容 |
|---|---|
| `PluginCatalogServiceTests` | metadata 不載入 DLL、缺少 PluginId、敏感資訊、缺少 capability、缺 contract version、unsafe source、disabled reason。 |
| `PluginVerificationResultTests` | 成功狀態為 `Verified`、失敗狀態不可產生 `Loaded`、失敗訊息遮罩、disabled state 可表達。 |
| `PluginAuditRecordTests` | safe summary 保留、敏感 reason 與正式路徑遮罩、AuditId 缺省時自動產生。 |

## 5. 停止線稽核

| 停止線 | 本次結果 |
|---|---|
| 不建立 `IPluginLoader` | 遵守 |
| 不建立 `PluginLoader` | 遵守 |
| 不掃描 plugin folder | 遵守 |
| 不載入外部 DLL | 遵守 |
| 不執行外部 plugin 程式碼 | 遵守 |
| 不改 Adapter public contract | 遵守 |
| 不改 config schema | 遵守 |
| 不新增 WebApi route / ServiceHost lifecycle | 遵守 |
| 不寫 DB、不執行 DDL / ALTER TABLE / Apply | 遵守 |
| 不保存密碼、Token、connection string 或正式 DLL 路徑 | 遵守 |

## 6. 完成判定

4D 最小 Application plugin contract 第一版已完成本機實作、測試驗證、程式 repo commit / push 與 GitHub Actions 查驗，可作為未來真正 PluginLoader 前的 metadata / verification / state / audit contract 基礎。

本次仍未建立動態 Loader；外部 DLL 載入、簽章驗證、版本信任模型落地、plugin folder 掃描、config schema 與 Adapter contract 仍需另行確認。

## 7. 建議下一步

建議接著查看 [4D PluginLoader 完成稽核表](phase-four-d-pluginloader-completion-audit.md)，再同步文件 repo stage / commit / push 與線上部署查驗。
