P5.UB14-plugin-management-api · C# IPluginRegistry Service + REST 拉取 v7 ModuleRegistry
Worker: ClaudeB · 部门: 后端 C# · 预计: 1.5d · 优先级: P2 · 状态: dispatched
🔍 触发与解锁链
- 触发:ADR-AIOS-14 §4.2 fork 3 · 用户 2026-06-02 10:48
start P5.UB14-plugin-management-api - 解锁:fork 4 P1.UB14-module-library-from-registry(前端 ModuleLibrary 改 hardcode → /api/plugins/list 数据源)
- 依赖:fork 1(
DynChain_LoadDynamicPluginsframework API)+ fork 2(xisound-host.lib导出ModuleRegistry_Register)· 运行时联调依赖:fork 2 zombie 后才能拉真 ModuleRegistry · 本期落 C# 框架 + xunit + P/Invoke 接口签名(可 stub mock)
任务定义(基于 ADR-AIOS-14 §2.5 + §4.2 fork 3)
新建 C# IPluginRegistry Service + REST 双端点 · 通过 P/Invoke 桥接 v7 ModuleRegistry(builtin + 第三方合并视图)· 严守 ADR-07 §1.3.4 三层分工铁律(P5 仅 I/O · 不算数学 · 不直接持有原生指针生命周期)。
业务行为契约 5 必填段:完整继承 ADR-AIOS-14 §2.5 ① 输入输出 + ② 收敛判据 + ③ 失败回退 5 类 + ④ 用户操作流 5 步 + ⑤ e2e 真值(本 prompt 不重复 · worker 必读 ADR §2.5)。本 fork e2e 真值落点 = §⑤ 测试用例 Step 2-3(C# REST + ModuleLibrary 暴露断言)+ xunit 集成测试(builtin module 至少返回 gain / pink_noise 等 v7 已注册项 ≥ 1 条)。
完整 prompt(直接复制粘贴 worker 终端)
[U-thread] P5.UB14-plugin-management-api(ADR-14 fork 3)
[部门] 后端 C# · ClaudeB · 1.5d · P2
[Worker CWD] d:/work/25_claude/workspace/AlgoDepartment/04_development/
[Occupies] P5.K-plugin-management(新建 · backend_csharp/Models/Plugin/ + Services/Plugin/ + Routes/PluginManagementApiRoutes.cs)
[优先级] P2 · feature · 🧵 file 隔离
[ADR] docs/08-implementation/40-aios/ADR/ADR-AIOS-14-pc-dynamic-plugin-loading.md(必读 §2.3 API + §2.5 5 必填段 + §4.2 fork 3)
[参考文档]
- dsp-algo v7 §5 ModuleRegistry:docs/03-platform/40-dsp-algo/10-architecture-v7.md(ModuleRegistry_Register / ModuleRegistry_FindByNumId / ModuleRegistry_FindByName / g_registry[64])
- 三层分工铁律:docs/08-implementation/40-aios/ADR/ADR-AIOS-07-p3-p4-overlap.md §1.3.4(P5 仅 I/O · 不算数学)
- 标本仿写:prompts/done/P5.U-meter-source-tap--4adda88.md(ClaudeB · 1.5d · 9 文件 · Models/Meter/* + Services/Meter/* + Routes/MeterDevApiRoutes.cs)
- fork 1 prompt(P/Invoke 上游 framework API):prompts/active/P6.UB14-load-dynamic-plugins-api.md(DynChain_LoadDynamicPlugins 签名 + LoadDynamicPluginsStats 结构)
- fork 2 prompt(P/Invoke 上游 dll 导出):prompts/active/P6.UB14-pc-host-sdk-export.md(ModuleRegistry_Register 导出符号 + xisound-host.lib)
【背景】
ADR-14 §4.2 fork 3:C# 端封装 v7 ModuleRegistry 暴露 REST · 解锁前端 ModuleLibrary(fork 4)从 hardcode 切到动态数据源。
worker 必读 ADR §2.3 看 LoadDynamicPluginsStats 结构(scanned/loaded/failed/skipped)+ §2.5 业务行为契约 5 段(input/output + 收敛 + 失败回退 5 类 + 操作流 + e2e 真值)。
注意 P5 三层分工:Service 层只 P/Invoke + 包装 + 错误转 RFC7807 · 不做 module 数学 · 不持有原生回调长生命周期。
【执行步骤 7 步】
Step 1 · 上游真值核查(0.1d)
- read ADR-14 §2.3+§2.5 全段 · v7 §5 ModuleRegistry 全段 · ADR-07 §1.3.4 三层分工
- read 标本 P5.U-meter-source-tap--4adda88.md 文件清单 + Service 层组织风格
- dotnet build + dotnet test 跑过当前主仓基线(217/0 应保持)
- 检查 fork 2 zombie 状态:read prompts/active/P6.UB14-pc-host-sdk-export.md 是否已 mv 到 done/
若否 → 本任务走 P/Invoke stub 模式(签名落地 + 真调用 try/catch + 测试用 mock IPluginRegistry)
若是 → 本任务走 P/Invoke 真模式(链接 xisound-host.lib · 真拉 g_registry)
Step 2 · 新建 Models/Plugin/(0.2d)
- LoadedPluginInfo.cs:typeNumId(uint)+ typeName(string)+ vendorTag(string · 高 16 位解析:builtin/xivst/temp)+ source(builtin/thirdparty)+ dllPath(string?)
- PluginLoadStats.cs:scanned + loaded + failed + skipped + lastScanAt(DateTimeOffset)· 字段对齐 ADR-14 §2.3 LoadDynamicPluginsStats
- 字段约束 + xmldoc 含单位/段位说明 · description case 走 camelCase(对齐 P5 现有 Models)
Step 3 · 新建 Services/Plugin/(0.4d)
- IPluginRegistry.cs · 3 方法:GetAll() / GetStats() / TriggerRescan(下季度可空实现 · 本期 throw NotImplementedException)
- PluginRegistryService.cs · 实现 IPluginRegistry · 内含 P/Invoke 声明:
[DllImport("DSPAlgo.dll", EntryPoint = "ModuleRegistry_Count")] static extern int ModuleRegistry_Count();
[DllImport(...)] static extern IntPtr ModuleRegistry_GetAt(int idx, out uint typeNumId, out IntPtr typeNamePtr);
[DllImport(...)] static extern int DynChain_GetLastLoadStats(out LoadDynamicPluginsStatsNative stats);
(worker 自行决定 P/Invoke 接口具体形态 · 与 fork 2 ModuleRegistry_Register 导出对齐 · 若 fork 2 未 zombie 则签名 stub + 单测 mock)
- vendorTag 解析(高 16 位):0x0000=xistudio_builtin / 0x0001~0xAAA9=xistudio_ext / 0xAAAA~0xFFFE=thirdparty / 0xFFFF=reserved
- 错误处理 5 类对齐 ADR-14 §2.5 ③(dll 损坏 / 入口缺失 / register 异常 / typeNumId 冲突 / 卸载未释放)· 每类返回 RFC7807 ProblemDetails
Step 4 · 新建 Routes/PluginManagementApiRoutes.cs(0.2d)
- GET /api/plugins/list → 200 List<LoadedPluginInfo> · 空 list 返 200 [](不报错)
- GET /api/plugins/load-stats → 200 PluginLoadStats · 含 lastScanAt
- 注册到 Program.cs · MapEndpoints 模式对齐 MeterDevApiRoutes.cs 现有先例
Step 5 · 新建 Tests/Services/Plugin/PluginRegistryServiceTests.cs(0.3d · ≥ 5 case)
- case 1 happy:mock g_registry 含 3 builtin module → GetAll 返 3 项 · vendorTag = xistudio_builtin
- case 2 thirdparty 标记:typeNumId=0xAAAA0001 → vendorTag = thirdparty
- case 3 stats 空:loaded=0 / failed=0 / skipped=0 → GetStats 返 0 计数
- case 4 P/Invoke 失败:DllNotFoundException → Service 返 RFC7807 + 503
- case 5 typeNumId 冲突 stats:skipped=2 → 字段透传
- 用 xunit + Moq · 不依赖真 DSPAlgo.dll(测试 stub mock 出 IPluginRegistry 内部 IModuleRegistryNative)
Step 6 · 端到端真值(0.2d)
- dotnet build → 0 error
- dotnet test → 217+5 = 222/0(基线保持)
- 启动 host(若 fork 2 zombie):curl http://localhost:5000/api/plugins/list 返 builtin module ≥ 1 条
- 若 fork 2 未 zombie:curl 返 [] + log "DSPAlgo.dll P/Invoke pending fork 2 zombie" warning(不阻塞)
Step 7 · commit(0.1d)
- git add backend_csharp/Models/Plugin/ Services/Plugin/ Routes/PluginManagementApiRoutes.cs Tests/Services/Plugin/ Program.cs
- subject:feat(P5.UB14/plugin-management-api): C# IPluginRegistry Service + REST 拉 v7 ModuleRegistry
- 三元组 trailer:[step=7/7] [pid=P5] [uid=UB14-plugin-management-api] [occupies=P5.K-plugin-management] [files=Models/Plugin/* Services/Plugin/* Routes/PluginManagementApiRoutes.cs Tests/Services/Plugin/*]
- 若 fork 2 未 zombie:加 [need: P6.UB14-pc-host-sdk-export] 联调标识
【验收】
☐ 文件清单:Models/Plugin/{LoadedPluginInfo,PluginLoadStats}.cs + Services/Plugin/{IPluginRegistry,PluginRegistryService}.cs + Routes/PluginManagementApiRoutes.cs + Tests/Services/Plugin/PluginRegistryServiceTests.cs + Program.cs +N 行注册
☐ dotnet build 0 error · dotnet test 222/0(基线 217 + 新增 5)
☐ /api/plugins/list 200 + /api/plugins/load-stats 200 · 字段对齐 ADR-14 §2.3 stats schema
☐ vendorTag 4 段位解析正确(builtin / ext / thirdparty / reserved)
☐ ADR-07 §1.3.4 三层分工严守(P5 不算数学 · 不持有原生指针长生命周期 · IPluginRegistry 仅 I/O 包装)
☐ 业务行为契约 5 段引用 ADR-14 §2.5(input/output + 收敛 + 失败回退 5 类 + 操作流 + e2e 真值)
☐ 端到端真值:fork 2 zombie 后联调 builtin gain module 在 list 中可见(若 fork 2 未 zombie 留 TODO + commit trailer 标 need)
【禁止】
❌ 不修改 framework/* 任何文件(fork 1)
❌ 不修改 dll/dspalgo_dll.c 或 sdk/include/*(fork 2)
❌ 不修改 backend_csharp/Services/Realtime/* + Models/Realtime/*(ADR-13 fork 2 在跑)
❌ 不修改 backend_csharp/Services/AudioDevice/*(ADR-13 fork 3 在跑)
❌ 不引入第二套 module ABI(强制复用 v7 ModuleFuncTable · 通过 P/Invoke 拉 g_registry)
❌ 不在 Service 层做 module 数学计算(P5 三层分工铁律 · 仅 I/O 包装)
❌ 不嵌入完整 C# Service class > 10 行到 prompt(本 prompt 已严守)· worker 自行仿写 P5.U-meter-source-tap 标本
❌ commit 不带三元组(7 天宽限期 warning · 6/2 起 strict mode hook 硬拒)
解锁链(本任务 zombie 后)
- ✅ fork 4
P1.UB14-module-library-from-registry(前端 ClaudeA · 1.0d · ModuleLibrary 改 /api/plugins/list 数据源) - ✅ fork 5
xivst-sdk.UB14-pc-only-bootstrap(若 fork 2 同步 zombie · 2.0d ClaudeB+Cline-AIOS · 含 hello-effect-v1.dll 端到端联调)
风险评估
| 风险 | 缓解 |
|---|---|
| fork 2 未 zombie 时 P/Invoke 真调用失败 | Step 3 stub 模式 + Step 5 mock 单测 + commit trailer 标 [need: P6.UB14-pc-host-sdk-export] |
| ClaudeB 严重过载(并发 5 fork:UA13-builtin + UA13-audio + UB14-load + UB14-host-sdk + 本 fork) | 任务自身 1.5d 工作量小 + 文件正交无锁竞争 + 排队尾部不阻塞前序 |
| Services/Realtime + Services/AudioDevice 子目录与本 fork Services/Plugin 子目录是否真正交 | 严守 §禁止 · Services/Plugin/ 全新建 · 不动其他子目录 |
| P/Invoke schema 与 fork 2 导出符号对不齐 | Step 1 必读 fork 2 prompt · 不齐则 commit trailer 留 need 标识 |
历史
| 时间 | 事件 | hash |
|---|---|---|
| 2026-06-02 10:48 | dispatched · ClaudeB · 1.5d · 本期 C# 框架 + xunit + P/Invoke 签名(stub 或真) | - |