diff --git a/ai-plan/public/cqrs-rewrite/archive/todos/cqrs-vs-mediator-assessment-rp063.md b/ai-plan/public/cqrs-rewrite/archive/todos/cqrs-vs-mediator-assessment-rp063.md new file mode 100644 index 00000000..88fdc64e --- /dev/null +++ b/ai-plan/public/cqrs-rewrite/archive/todos/cqrs-vs-mediator-assessment-rp063.md @@ -0,0 +1,98 @@ +# CQRS 与 Mediator 评估归档(RP-063) + +## 背景 + +- 本轮目的不是继续实现 runtime / generator,而是基于当前 `feat/cqrs-optimization` 工作树事实, + 评估 `GFramework.Cqrs` 相对 `ai-libs/Mediator` 的替代完成度、设计吸收度与后续可借鉴项。 +- 本评估只使用仓库内现有实现、文档、`ai-plan` 记录与只读第三方参考副本 `ai-libs/Mediator`。 + +## 评估结论 + +### 1. 当前阶段 + +- `cqrs-rewrite` 当前处于 `Phase 8`,恢复点提升到 `CQRS-REWRITE-RP-063`。 +- 当前主线已从“移除外部依赖并让默认 runtime 可用”转入“继续扩大 generator 覆盖、继续压低 dispatch / + invoker 反射占比、继续收口 facade 与兼容层”的中后期收敛阶段。 +- 这一结论延续了 active tracking 中的 `RP-062` 事实,不代表回退到早期迁移阶段。 + +### 2. 对外部 Mediator 的替代完成度 + +- 生产依赖层面:已基本完成替代。 + - `GFramework.Cqrs` 当前不再引用外部 `Mediator` 包。 + - 默认 runtime 已切换为自有 `CqrsDispatcher`、`CqrsHandlerRegistrar` 与 `CqrsRuntimeFactory`。 + - `GFramework.Core` 通过 `CqrsRuntimeModule` 自动接线默认 CQRS runtime。 +- 运行时主路径层面:已基本完成替代。 + - `ArchitectureContext` 已提供统一的 `SendRequestAsync`、`PublishAsync`、`CreateStream` 入口。 + - handler 注册链路已以 generated registry 优先、targeted fallback 次之、整程序集扫描兜底为主。 +- 结论: + - 若“完全替代”指“不再依赖外部 `Mediator` 作为生产 runtime”,答案是 `是`。 + - 若“完全替代”指“仓库内部所有旧总线、旧 seam、旧命名与兼容入口都已删除”,答案是 `否`。 + +### 3. 对 Mediator 设计思想的吸收度 + +- 已吸收: + - 统一 request / command / query / notification / stream 消息模型。 + - 源码生成优先、反射 fallback 次之的注册策略。 + - 通过缓存压低 registrar / dispatcher 热路径上的重复反射成本。 + - 将 CQRS runtime 明确接入框架架构上下文,而不是维持独立外部服务入口。 +- 部分吸收: + - `GFramework.Cqrs.SourceGenerators` 已深度参与 handler 注册,但当前仍主要生成 registry 与 fallback 元数据, + 而非像 `Mediator` 那样进一步生成 runtime 主体或更大范围的 DI glue。 +- 尚未充分吸收: + - notification publisher 作为可替换策略的一等抽象。 + - stream pipeline、pre/post processor、exception pipeline 这类更细粒度的扩展分层。 + - telemetry、diagnostics、benchmark、allocation tracking 作为框架主能力的完整体系。 + - 进一步把强类型 dispatch / invoker 主体前移到生成器,而不是继续依赖运行时 `MakeGenericMethod` + + `Delegate.CreateDelegate` 后再缓存。 + +### 4. 仓库内部仍未完全收口的部分 + +- 旧 `GFramework.Core.Command` / `GFramework.Core.Query` 路径仍然存在。 +- `ArchitectureContext` 仍同时暴露旧 Command / Query 路径与新 CQRS 路径。 +- `CqrsRuntimeModule` 仍注册 `LegacyICqrsRuntime = GFramework.Core.Abstractions.Cqrs.ICqrsRuntime` 兼容别名。 +- `CqrsReflectionFallbackAttribute` 仍保留空 marker 与字符串 fallback 语义,说明 runtime 继续承担旧版兼容契约。 +- `GFramework.Cqrs.Tests/Mediator/` 目录与若干测试类仍沿用 `Mediator` 命名,但测试内部实际已调用当前 CQRS runtime。 +- 结论:当前真正残留的主要是兼容层、旧术语与评估/测试命名,而不是外部运行时依赖本身。 + +## 关键证据 + +- 当前阶段与主线: + - `ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md` + - `ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md` +- 自有 runtime 与默认接线: + - `GFramework.Cqrs/CqrsRuntimeFactory.cs` + - `GFramework.Cqrs/Internal/CqrsDispatcher.cs` + - `GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs` + - `GFramework.Core/Services/Modules/CqrsRuntimeModule.cs` + - `GFramework.Core/Architectures/ArchitectureContext.cs` +- generator 与 fallback 合同: + - `GFramework.Cqrs.SourceGenerators/README.md` + - `GFramework.Cqrs/CqrsReflectionFallbackAttribute.cs` + - `docs/zh-CN/core/cqrs.md` +- 第三方参考源: + - `ai-libs/Mediator/README.md` + - `ai-libs/Mediator/src/Mediator.SourceGenerator/**` + - `ai-libs/Mediator/src/Mediator/INotificationPublisher.cs` + - `ai-libs/Mediator/benchmarks/README.md` + +## 建议优先级 + +### P1 + +- 评估是否继续前移 generator 职责,生成部分强类型 dispatch / invoker 主体,而不再只停留在 registry。 +- 为 notification fan-out 引入可替换 publisher seam,并先定义顺序与并发两种语义模型。 + +### P2 + +- 扩展 pipeline 体系,评估 stream pipeline、pre-processor、post-processor、exception handler 的契约边界。 +- 为 CQRS runtime 设计 tracing / metrics seam,至少先完成 contracts 与默认 no-op / logger 对齐方案评估。 + +### P3 + +- 建立 CQRS runtime 的 benchmark / allocation 基线,让“继续压低反射成本”从经验判断转为可量化验证。 +- 单独规划旧 `Command` / `Query`、`LegacyICqrsRuntime` 与测试命名的收口顺序,不与 runtime 微优化混在同一波。 + +## 默认下一步 + +1. 以 `notification publisher seam` 与 `dispatch/invoker 生成前移` 为首轮设计评估对象。 +2. 若进入实现阶段,优先做 seam 与契约扩展,再决定是否调整旧测试目录与历史命名。 diff --git a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md index 4703ad8c..78545e85 100644 --- a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md +++ b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md @@ -7,9 +7,16 @@ CQRS 迁移与收敛。 ## 当前恢复点 -- 恢复点编号:`CQRS-REWRITE-RP-062` +- 恢复点编号:`CQRS-REWRITE-RP-063` - 当前阶段:`Phase 8` - 当前焦点: + - 已完成一轮 `CQRS vs Mediator` 只读评估归档,结论已沉淀到 `archive/todos/cqrs-vs-mediator-assessment-rp063.md` + - 当前评估结论已明确:`GFramework.Cqrs` 已完成对外部 `Mediator` 的生产级替代,但仓库内部旧总线 API、 + 兼容 seam、fallback 旧语义与测试命名仍未完全收口 + - 当前评估结论已明确:相对 `ai-libs/Mediator`,框架已吸收统一消息模型、generator 优先注册与热路径缓存思路, + 但仍未完整吸收 publisher 策略抽象、细粒度 pipeline、telemetry / diagnostics / benchmark 体系与 runtime 主体生成 + - 下一阶段建议优先级已收敛为:`notification publisher seam`、`dispatch/invoker 生成前移`、`pipeline 分层扩展`、 + `可观测性 seam` 与 `benchmark / allocation baseline` - 当前功能历史已归档,active 跟踪仅保留 `Phase 8` 主线的恢复入口 - 已将 mixed fallback 场景进一步收敛:当 runtime 允许同一程序集声明多个 `CqrsReflectionFallbackAttribute` 实例时,generator 现会把可直接引用的 fallback handlers 与仅能按名称恢复的 fallback handlers 拆分发射 - `CqrsReflectionFallbackAttribute` 现允许多实例,以承载 `Type[]` 与字符串 fallback 元数据的组合输出 @@ -41,6 +48,7 @@ CQRS 迁移与收敛。 - 已完成 `GFramework.Cqrs.Abstractions` / `GFramework.Cqrs` 项目骨架与 runtime seam 收敛 - 已完成 handler registry generator 的多轮收敛,当前合法 closed handler contract 已统一收敛到更窄的注册路径 - 已完成一轮公开入口文档与 source-generator 命名空间收口 +- 已完成一轮 `CQRS vs Mediator` 对照评估,确认当前主问题已从“是否能替代外部依赖”转为“框架内部收口与能力深化顺序” - 已接入 `$gframework-pr-review`,可直接抓取当前分支对应 PR 的 CodeRabbit 评论、checks 和测试结果 ## 当前活跃事实 @@ -129,20 +137,31 @@ CQRS 迁移与收敛。 - `SourceEmission` 不再保留 `MakePointerType()` 源码发射分支,`RuntimeTypeReferences` 也已删掉对应的外部程序集递归扫描死代码 - pointer / function pointer 的拒绝语义保持不变,direct / named / mixed fallback 逻辑未改动 - 当前工作区相对 `origin/main` 的累计 diff 已达到 `14 files`,仍低于本轮 `gframework-batch-boot 50` 的主要 stop condition +- `2026-04-30` 已完成一轮 `CQRS vs Mediator` 结构化评估: + - 生产依赖与默认 runtime 接线层面,`GFramework.Cqrs` 已完成对外部 `Mediator` 的替代 + - 仓库内部收口层面,旧 `Command` / `Query` API、`LegacyICqrsRuntime` 别名、fallback 空 marker 兼容语义与 + `Mediator` 测试命名仍然存在 + - 设计吸收层面,当前已吸收统一消息模型、generator 优先注册与反射收敛思路;仍未完整吸收 publisher 策略抽象、 + stream / exception pipeline、telemetry / diagnostics / benchmark 体系与 runtime 主体生成 + - 详细结论与证据已归档到 `archive/todos/cqrs-vs-mediator-assessment-rp063.md` - 当前主线优先级: - - generator 覆盖面继续扩大 - - dispatch/invoker 反射占比继续下降 + - `notification publisher seam` 评估与设计优先 + - dispatch/invoker 反射占比继续下降,并优先评估生成前移方案 - package / facade / 兼容层继续收口 + - pipeline 分层扩展、可观测性 seam 与 benchmark baseline 进入中期候选 ## 当前风险 - 当前 `dotnet build GFramework.sln -c Release` 在 WSL 环境仍会受顶层 `GFramework.csproj` 的 Windows NuGet fallback 配置影响 - 当前 `GFramework.Cqrs.Tests` 仍直接引用 `GFramework.Core`,说明测试已按模块意图拆分,但 runtime 物理迁移尚未完全切断依赖 +- 当前对外替代已基本完成,但若不单独规划旧 `Command` / `Query`、`LegacyICqrsRuntime` 与测试命名的收口顺序, + 后续仍会持续混淆“生产替代已完成”与“仓库内部收口未完成”这两个不同结论 ## 活跃文档 - 历史跟踪归档:[cqrs-rewrite-history-through-rp043.md](../archive/todos/cqrs-rewrite-history-through-rp043.md) - 验证历史归档:[cqrs-rewrite-validation-history-through-rp062.md](../archive/todos/cqrs-rewrite-validation-history-through-rp062.md) +- CQRS 与 Mediator 评估归档:[cqrs-vs-mediator-assessment-rp063.md](../archive/todos/cqrs-vs-mediator-assessment-rp063.md) - 历史 trace 归档:[cqrs-rewrite-history-through-rp043.md](../archive/traces/cqrs-rewrite-history-through-rp043.md) - `RP-046` 至 `RP-061` trace 归档:[cqrs-rewrite-history-rp046-through-rp061.md](../archive/traces/cqrs-rewrite-history-rp046-through-rp061.md) @@ -159,7 +178,11 @@ CQRS 迁移与收敛。 - `bash scripts/validate-csharp-naming.sh` - 结果:通过 - 备注:使用显式 `GIT_DIR` / `GIT_WORK_TREE` 绑定重跑后,`1045` 个 tracked C# 文件的命名校验全部通过;本轮 `_syncRoot` 改名未引入命名规则回归 +- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release` + - 结果:通过 + - 备注:`0 warning / 0 error`;本轮确认 `ai-plan` 评估与恢复文档更新未影响 `GFramework.Cqrs` 的最小 Release 构建 ## 下一步 -1. push 当前 follow-up 提交后,重新执行 `$gframework-pr-review`,确认 `PR #304` 的 latest unresolved threads 是否已刷新为已解决,或仅剩新增有效项 +1. 以 `notification publisher seam` 与 `dispatch/invoker` 生成前移为优先对象,补一轮面向实现的设计评估 +2. 单独规划旧 `Command` / `Query` API、`LegacyICqrsRuntime` 与 `Mediator` 测试命名的收口顺序,避免与 runtime 微优化混做 diff --git a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md index 821683e2..a54aa34d 100644 --- a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md +++ b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md @@ -2,36 +2,43 @@ ## 2026-04-30 -### 阶段:PR #304 剩余 review follow-up 收敛(CQRS-REWRITE-RP-062) +### 阶段:CQRS vs Mediator 评估归档(CQRS-REWRITE-RP-063) -- 本轮再次执行 `$gframework-pr-review`,确认当前分支 `feat/cqrs-optimization` 仍对应 `PR #304` -- 本地复核后继续收敛了上一轮遗留的 review 项: - - `GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarFallbackFailureTests.cs` 已补 `NonParallelizable` - - `GFramework.Cqrs.Tests/Cqrs/DispatcherStreamContextRefreshState.cs` 已改用 `_syncRoot` 命名,并补齐缺失的 XML 文档标签 - - `GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherContextValidationTests.cs` 三个内部 `Handle(...)` 已补齐 XML `param` / `returns` - - `DispatcherNotificationContextRefreshNotification` 与 `DispatcherStreamContextRefreshRequest` 已补 `DispatchId` XML 参数注释 - - `cqrs-rewrite` active tracking / trace 已压缩为当前恢复入口,并将已完成阶段的详细历史移入 archive -- 验证: - - `dotnet build GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release` +- 本轮按用户要求使用 `gframework-boot` 启动上下文后,先完成 `cqrs-rewrite` 现状核对,再并行对照 + `GFramework.Cqrs` 与 `ai-libs/Mediator` +- 只读评估结论已归档到 `ai-plan/public/cqrs-rewrite/archive/todos/cqrs-vs-mediator-assessment-rp063.md` +- 本轮关键判断: + - `GFramework.Cqrs` 已完成对外部 `Mediator` 作为生产 runtime 依赖的替代 + - 当前尚未完成的是仓库内部旧 `Command` / `Query` API、兼容 seam、fallback 旧语义与测试命名的收口 + - 当前已吸收 `Mediator` 的统一消息模型、generator 优先注册与热路径缓存思路 + - 当前仍未完整吸收 publisher 策略抽象、细粒度 pipeline、telemetry / diagnostics / benchmark 体系与 runtime 主体生成 +- 本轮把默认下一步从“继续盯 PR thread”调整为“围绕 publisher seam 与 dispatch/invoker 生成前移做下一轮设计收敛” + +### 验证 + +- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release` - 结果:通过,`0 warning / 0 error` ## 活跃事实 - 当前主题仍处于 `Phase 8` -- `PR #304` 的本地 follow-up 已再次收口一轮,后续需要在 push 后重新观察 GitHub 的 unresolved thread 刷新结果 +- 当前主题的主问题已从“是否完成外部依赖替代”转为“内部兼容层收口顺序与下一轮能力深化优先级” - 已完成阶段的详细执行历史不再留在 active trace;默认恢复入口只保留当前恢复点、活跃事实、风险与下一步 ## 当前风险 - 当前 `dotnet build GFramework.sln -c Release` 在 WSL 环境仍会受顶层 `GFramework.csproj` 的 Windows NuGet fallback 配置影响 -- 远端 review thread 在本地提交前不会自动刷新,GitHub 上看到的 open 状态可能暂时滞后于当前代码 +- 若不把“生产替代完成”与“仓库内部收口完成”分开记录,后续很容易重复争论当前 CQRS 迁移是否已经完成 ## Archive Context +- 当前评估归档: + - `ai-plan/public/cqrs-rewrite/archive/todos/cqrs-vs-mediator-assessment-rp063.md` - 历史 trace 归档: - `ai-plan/public/cqrs-rewrite/archive/traces/cqrs-rewrite-history-through-rp043.md` - `ai-plan/public/cqrs-rewrite/archive/traces/cqrs-rewrite-history-rp046-through-rp061.md` ## 当前下一步 -1. push 当前 follow-up 提交后,重新执行 `$gframework-pr-review`,确认 `PR #304` 的 latest unresolved threads 是否已刷新为已解决,或仅剩新增有效项 +1. 补一轮最小 Release 构建验证,确认本次 `ai-plan` 与评估文档更新未引入仓库级异常 +2. 以 `notification publisher seam` 与 `dispatch/invoker` 生成前移为优先对象,形成下一轮可执行设计