docs(cqrs-rewrite): 收敛恢复入口文档

- 更新 active tracking,仅保留 RP-076、PR #307、活跃风险、权威验证与下一推荐步骤

- 重构 active trace,仅保留当前阶段决策、验证结果与后续恢复方向

- 补充 RP-062 至 RP-076 的 trace 归档,承接迁出的历史阶段上下文
This commit is contained in:
gewuyou 2026-04-30 18:47:55 +08:00
parent 9296def108
commit 26314dba5e
3 changed files with 83 additions and 665 deletions

View File

@ -0,0 +1,34 @@
# CQRS 重写迁移追踪归档RP-062 至 RP-076
## 说明
- 本文件承接从 active trace 中迁出的 `RP-062``RP-076` 阶段细节。
- `boot` 默认恢复入口应回到 `ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md`,不要从本归档直接挑选旧阶段作为当前恢复点。
## 覆盖范围
- `CQRS-REWRITE-RP-062``CQRS-REWRITE-RP-076`
- 对应 active trace 清理前的 `2026-04-29``2026-04-30` 阶段记录
## 归档摘要
- `RP-062``PR #305` review follow-up 收敛补齐并发测试、logger provider 恢复、真实上下文注入与 tracking/trace 细节修正
- `RP-063``CQRS vs Mediator` 结构化评估归档
- `RP-064`notification publisher seam 最小实现与回归补齐
- `RP-065``Mediator` 历史测试命名与目录收口
- `RP-066`legacy `ICqrsRuntime` alias compatibility slice 收敛
- `RP-067`generated request invoker provider 最小落地
- `RP-068`generated stream invoker provider 最小落地
- `RP-069`generated invoker 在 hidden-implementation + visible-interface 场景下的发射范围补强
- `RP-070`hidden-implementation generated invoker runtime 回归补强
- `RP-071`precise reflected invoker provider 合同边界回归
- `RP-072`request / stream provider gate 合同回归
- `RP-073`generated invoker provider runtime 失败边界修复
- `RP-074`non-enumerating provider reflection fallback 回归
- `RP-075``PR #307` review follow-up 收敛,补齐 descriptor 合同防御、空枚举回退与文档口径
- `RP-076`stream invoker gate 四项 runtime 合同分支补强,并最终将 active tracking / trace 收敛为单一恢复入口
## 备注
- `RP-063``RP-074` 的详细命令级验证仍以 `archive/todos/cqrs-rewrite-validation-history-rp063-through-rp074.md` 为准。
- `RP-075``RP-076` 的权威验证结论已同步沉淀到 active tracking / trace后续若需追溯阶段细节应同时参考对应测试文件、提交记录与本归档摘要。

View File

@ -9,264 +9,52 @@ CQRS 迁移与收敛。
- 恢复点编号:`CQRS-REWRITE-RP-076`
- 当前阶段:`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` 主线的恢复入口
- 已完成一轮 notification publisher seam 最小落地:`GFramework.Cqrs` 新增 `INotificationPublisher`
`NotificationPublishContext<TNotification>` 与默认 `SequentialNotificationPublisher`
- `CqrsDispatcher` 现会在解析当前通知处理器集合后,把执行顺序委托给 publisher seam默认行为仍保持
“零处理器静默完成、顺序执行、首错即停”
- `CqrsRuntimeFactory``CqrsRuntimeModule``GFramework.Tests.Common.CqrsTestRuntime` 现支持在 runtime 创建前复用
容器里已显式注册的 `INotificationPublisher`
- 已补充 `CqrsNotificationPublisherTests`,覆盖自定义 publisher 接管、上下文注入、零处理器静默完成、首错即停,以及
`RegisterInfrastructure` 默认接线复用预注册 publisher 的回归
- 已完成一轮 `Mediator` 测试命名收口:
- `MediatorAdvancedFeaturesTests` -> `CqrsArchitectureContextAdvancedFeaturesTests`
- `MediatorArchitectureIntegrationTests` -> `CqrsArchitectureContextIntegrationTests`
- `MediatorComprehensiveTests` -> `ArchitectureContextComprehensiveTests`
- `GFramework.Cqrs.Tests` 中这三份历史测试现已统一迁入 `Cqrs/` 目录,并将命名空间、类名、中文注释与嵌套测试类型中的
`Mediator` 语义收口为 `CQRS` / `ArchitectureContext`
- 已补充 `ArchitectureContextTests` 并发 lazy-resolution 回归,锁定 `PublishAsync(...)``CreateStream(...)`
在并发首次访问时也只会解析一次 `ICqrsRuntime`
- 已完成一轮 `LegacyICqrsRuntime` compatibility slice 收口:
- `CqrsRuntimeModule``GFramework.Tests.Common.CqrsTestRuntime` 现把 legacy alias 注册收敛到显式 helper
- `MicrosoftDiContainerTests` 已补充“只预注册正式 `ICqrsRuntime` seam 时,也会回填 legacy alias 且保持同实例”的回归
- `GFramework.Core.Abstractions/README.md``docs/zh-CN/abstractions/core-abstractions.md`
`docs/zh-CN/core/cqrs.md` 现已明确:旧命名空间下的 `ICqrsRuntime` 仅作为 compatibility alias 保留,
新代码应直接依赖 `GFramework.Cqrs.Abstractions.Cqrs.ICqrsRuntime`
- 已完成一轮 `dispatch/invoker` 生成前移的最小 request 切片:
- `GFramework.Cqrs` 新增 `ICqrsRequestInvokerProvider``IEnumeratesCqrsRequestInvokerDescriptors`
`CqrsRequestInvokerDescriptor``CqrsRequestInvokerDescriptorEntry`
- generated registry 若实现 request invoker provider 契约,`CqrsHandlerRegistrar` 现会在激活 registry 后把 provider 注册进容器,
并把 provider 枚举出的 request invoker 描述符写入 dispatcher 的进程级弱缓存
- `CqrsDispatcher` 现会在首次创建 request dispatch binding 时优先命中 generated request invoker 描述符;
未命中时仍回退到既有 `MakeGenericMethod + Delegate.CreateDelegate` 路径
- `GFramework.Cqrs.Tests` 已补充 `CqrsGeneratedRequestInvokerProviderTests`,锁定 registrar 接线和 dispatcher 消费 generated invoker 的最小语义
- `GFramework.SourceGenerators.Tests` 已补充 generator 回归,锁定当 runtime 暴露新契约时generated registry 会额外发射 request invoker provider 成员与 invoker 方法
- 已完成一轮 `dispatch/invoker` 生成前移的最小 stream 切片:
- `GFramework.Cqrs` 新增 `ICqrsStreamInvokerProvider``IEnumeratesCqrsStreamInvokerDescriptors`
`CqrsStreamInvokerDescriptor``CqrsStreamInvokerDescriptorEntry`
- generated registry 若实现 stream invoker provider 契约,`CqrsHandlerRegistrar` 现会在激活 registry 后把 provider 注册进容器,
并把 provider 枚举出的 stream invoker 描述符写入 dispatcher 的进程级弱缓存
- `CqrsDispatcher` 现会在首次创建 stream dispatch binding 时优先命中 generated stream invoker 描述符;
未命中时仍回退到既有 `MakeGenericMethod + Delegate.CreateDelegate` 流式 binding 路径
- `GFramework.Cqrs.Tests` 已扩充 `CqrsGeneratedRequestInvokerProviderTests`,锁定 registrar 接线和 dispatcher 消费 generated stream invoker 的最小语义
- `GFramework.SourceGenerators.Tests` 已补充 generator 回归,锁定当 runtime 暴露新契约时generated registry 会额外发射 stream invoker provider 成员与 invoker 方法
- `GFramework.Cqrs/README.md``GFramework.Cqrs.SourceGenerators/README.md``docs/zh-CN/core/cqrs.md`
`docs/zh-CN/source-generators/cqrs-handler-registry-generator.md` 现已同步说明 generated stream invoker 的接线与回退边界
- 已完成一轮 generated invoker 发射范围补强:
- `CqrsHandlerRegistryGenerator` 现会把 generated request / stream invoker 的发射范围,从“仅 direct registration”扩大到“实现类型隐藏、但 handler interface 仍可直接表达”的 reflected-implementation registration
- 当前扩展仍刻意避开 `PreciseReflectedRegistrationSpec`,不把隐藏 request/response 类型误拉进 provider 发射,继续保持生成源码可编译边界
- `GFramework.SourceGenerators.Tests` 已新增两条 hidden-implementation 回归,锁定 request / stream provider 在该场景下都会继续发射 descriptor 与静态 invoker 方法
- 已完成一轮 hidden-implementation generated invoker runtime 回归补强:
- `GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs` 现覆盖“实现类型隐藏、但 handler interface 可见”场景下的 generated request / stream invoker 消费路径
- `HiddenImplementationGeneratedRequestInvokerProviderRegistry``HiddenImplementationGeneratedStreamInvokerProviderRegistry` 与对应 container / handler fixture 现锁定 registrar 接线后dispatcher 会优先命中 generated descriptor而不是退回反射 invoker
- 当前 runtime 回归继续保持 `PreciseReflectedRegistrationSpec` 排除边界不变,只验证已允许发射 provider 元数据的 visible-interface hidden-implementation 场景
- 已完成一轮 precise reflected invoker provider 合同边界回归:
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 现新增 request / stream 两条回归,明确当 handler 仍需走 `PreciseReflectedRegistrationSpec`generator 即使检测到 invoker provider runtime 合同,也不会错误发射 descriptor、枚举接口或静态 invoker 桥接
- 本轮接受了一条只读 subagent 的“继续评估 precise reflected + provider 发射”候选思路,但主线程复核后确认该候选并不存在可安全放宽的 `typeof(request/response)` 子集,因此收敛为“锁定当前排除边界”的测试批次,而不是修改生产 generator 逻辑
- 已完成一轮 invoker provider gate 合同回归:
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 现新增四条回归,分别锁定 request / stream 在缺少 `ICqrsRequestInvokerProvider``IEnumeratesCqrsRequestInvokerDescriptors``ICqrsStreamInvokerProvider``IEnumeratesCqrsStreamInvokerDescriptors`generator 都会整体跳过对应 provider 元数据发射
- 本轮最初采用固定源码片段替换来裁剪测试输入,但因三引号字符串缩进差异导致 helper 过脆;当前已收敛为按稳定起止标记移除源码块的 `RemoveBlock(...)` helper避免 gate 回归依赖精确空格对齐
- 已完成一轮 stream invoker descriptor gate 合同补强:
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 现额外新增两条 stream gate 回归,分别锁定 runtime 缺少 `CqrsStreamInvokerDescriptor``CqrsStreamInvokerDescriptorEntry`generator 同样会整体跳过 stream provider 元数据发射
- 本轮补强直接对应 `CqrsHandlerRegistryGenerator``supportsStreamInvokerProvider` 的四项合同探测,避免此前只覆盖 provider / enumerator 缺失而漏掉 descriptor 两条分支
- 已完成一轮 generated invoker provider runtime 失败边界修复:
- `GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs` 现新增 request / stream 两组 `non-static invoker``incompatible invoker` 回归,锁定 dispatcher 在首次绑定阶段会显式拒绝非法 generated descriptor
- `GFramework.Cqrs/Internal/CqrsDispatcher.cs` 现把 `Delegate.CreateDelegate(...)` 抛出的 `ArgumentException` 统一包装为已有 XML 文档承诺的 `InvalidOperationException`,保持 request / stream 两条错误消息语义一致
- 本轮顺手为新增异步断言补齐 `ConfigureAwait(false)`,消除新测试引入的 `MA0004` warning
- 已完成一轮 non-enumerating provider reflection fallback 回归:
- `GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs` 现新增 request / stream 两条回归,锁定当 registry 只暴露 provider 接口、但不实现 `IEnumeratesCqrs*InvokerDescriptors`registrar 不会预热 dispatcher 缓存,后续 dispatch 会继续回退到既有反射路径
- 当前回归明确区分“provider 已注册”和“descriptor 已枚举入缓存”这两个阶段,避免后续把 `TryGetDescriptor(...)` 的存在误当成 dispatcher 会主动查询 provider 的合同
- 已完成 `PR #307` review follow-up 的当前批次:
- `CqrsRequestInvokerDescriptor` / `CqrsStreamInvokerDescriptor` 现会在构造阶段拒绝实例方法,避免非法 generated metadata 延迟到首次分发时才暴露
- `CqrsRequestInvokerDescriptorEntry` / `CqrsStreamInvokerDescriptorEntry` 现补齐公开入口空值防御,保持 request / stream 描述符合同一致
- `CqrsGeneratedRequestInvokerProviderTests` 现补齐空 descriptor 枚举回退回归,并把“非静态 invoker”语义收敛为 registrar 放弃 generated registry 后回退到反射路径
- `docs/zh-CN/core/cqrs.md` 已改正文档里“元数据异常会回退到反射”的错误表述,并将源码阅读表中的 `Internal/` 路径文案改为语义标签
- active tracking 已把 `RP-063``RP-074` 的命令级验证明细迁移到 `archive/todos/cqrs-rewrite-validation-history-rp063-through-rp074.md`,当前入口只保留最近权威验证与恢复点
- 当前相对 `origin/main` 的累计 branch diff 为 `24 files / 1754 changed lines`,仍低于本轮 `$gframework-batch-boot 50` 的主要 stop condition可继续推进下一批低风险切片
- 已将 mixed fallback 场景进一步收敛:当 runtime 允许同一程序集声明多个 `CqrsReflectionFallbackAttribute` 实例时generator 现会把可直接引用的 fallback handlers 与仅能按名称恢复的 fallback handlers 拆分发射
- `CqrsReflectionFallbackAttribute` 现允许多实例,以承载 `Type[]` 与字符串 fallback 元数据的组合输出
- 已将 generator 的程序集级 fallback 元数据进一步收敛:当全部 fallback handlers 都可直接引用且 runtime 暴露 `params Type[]` 合同时,生成器现优先发射 `typeof(...)` 形式的 fallback 元数据
- 当 runtime 不支持多实例 fallback 特性或缺少对应构造函数时mixed fallback 场景仍会整体保守回退到字符串元数据,避免仅部分 handler 走 `Type[]` 时漏掉剩余需按名称恢复的 handlers
- 已完成 request pipeline executor 形状缓存:`CqrsDispatcher` 现会在单个 request binding 内按 `behaviorCount` 复用强类型 pipeline executor而不是每次 `SendAsync` 都重建整条 `next` 委托链
- 已补充 dispatcher pipeline executor 缓存与双行为顺序回归,锁定缓存复用后仍保持现有行为执行顺序
- 已补充 cached request pipeline executor 的上下文刷新回归,锁定 executor 复用时仍会为当次 handler / singleton behavior 重新注入当前 `ArchitectureContext`
- 已补充 cached notification / stream dispatch binding 的上下文刷新回归,锁定 binding 复用时仍会为当次 handler 重新注入当前 `ArchitectureContext`
- 已补充非 `IArchitectureContext` 的 dispatcher 失败语义回归,锁定 context-aware request / notification / stream handler 在注入前置条件不满足时会显式抛出异常
- 已补充 registrar fallback 失败分支回归,锁定 named fallback 无法解析、named fallback 解析抛异常、direct fallback 跨程序集三类 warning 语义
- 已完成 generated registry 激活路径收敛:`CqrsHandlerRegistrar` 现优先复用缓存工厂委托,避免重复 `ConstructorInfo.Invoke`
- 已补充私有无参构造 generated registry 的回归测试,确保兼容现有生成器产物
- 已修正 pointer / function pointer 泛型合同的错误覆盖:生成器不再为这两类类型发射 precise runtime type 重建代码
- 已补充非法 CQRS 泛型合同的输入诊断断言,明确 `CS0306` 与 fallback / diagnostic 路径的组合语义
- 已为 registrar 的 reflection 注册路径补充 handler-interface 元数据缓存,减少跨容器重复注册时的 `GetInterfaces()` 反射
- 已将 registrar 的重复映射判定从线性扫描 `IServiceCollection` 收敛为本地映射索引,减少 fallback 注册路径的重复查找
- 已完成一轮 `static lambda + state` 微收敛:`CqrsDispatcher``CqrsHandlerRegistrar` 现会在弱缓存 / 并发缓存入口优先使用无捕获工厂,继续压低热路径上的额外闭包分配
- 已补充 `CqrsReflectionFallbackAttribute` 叶子级合同测试,锁定空 marker、字符串 fallback 名称归一化、直接 `Type` fallback 归一化与空参数防御语义
- 已完成 `PR #304` review follow-up 收敛:`CqrsDispatcher` 现补齐 pipeline executor / continuation 缓存的线程模型文档,并把 request pipeline invoker 从按 `behaviorCount` 重复创建收敛为 binding 内复用
- 已补齐 `CqrsDispatcherContextValidationTests` 三个上下文校验 handler 的 XML `param` / `returns` 注释,以及 `DispatcherNotificationContextRefreshNotification``DispatcherStreamContextRefreshRequest``DispatchId` XML 参数注释,收敛上一轮 PR review 遗留的文档类 minor feedback
- 已收紧 CQRS / generator 回归测试的脆弱断言日志断言改为语义匹配precise runtime type lookup 回归改为锁定数组秩、外部类型查找与“未发射 fallback metadata”这些稳定语义
- 已为 dispatcher cache / context refresh / pipeline order 三组测试状态容器补齐并发保护,并将 `CqrsDispatcherCacheTests` 标记为 `NonParallelizable`,避免静态缓存与共享快照在并行测试中相互污染
- 中期上继续 `Phase 8` 主线:参考 `ai-libs/Mediator`,继续扩大 generator 覆盖,并选择下一个收益明确的 dispatch / invoker 反射收敛点
## 当前状态摘要
- 已完成 `Mediator` 外部依赖移除、CQRS runtime 重建、默认架构接线和显式程序集 handler 注册入口
- 已完成 `GFramework.Cqrs.Abstractions` / `GFramework.Cqrs` 项目骨架与 runtime seam 收敛
- 已完成 handler registry generator 的多轮收敛,当前合法 closed handler contract 已统一收敛到更窄的注册路径
- 已完成一轮公开入口文档与 source-generator 命名空间收口
- 已完成一轮 `CQRS vs Mediator` 对照评估,确认当前主问题已从“是否能替代外部依赖”转为“框架内部收口与能力深化顺序”
- 已接入 `$gframework-pr-review`,可直接抓取当前分支对应 PR 的 CodeRabbit 评论、checks 和测试结果
- 当前 PR 锚点:`PR #307`
- 当前结论:
- `GFramework.Cqrs` 已完成对外部 `Mediator` 的生产级替代,当前主线已从“是否可替代”转向“仓库内部收口与能力深化顺序”
- `dispatch/invoker` 生成前移已扩展到 request / stream 路径,当前 `RP-076` 已补齐 stream invoker provider gate 的四项 runtime 合同分支
- `ai-plan` active 入口现以 `PR #307``RP-076` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准
## 当前活跃事实
- `Phase 8` 仍是当前主线,不再回退到 `Phase 7`
- `2026-04-20` 已重新执行 `$gframework-pr-review`
- 当前分支对应 `PR #261`,状态为 `OPEN`
- latest reviewed commit 当前剩余 `1` 条 open CodeRabbit thread指向 `ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md``RP-047``RP-050` 的历史语义冲突
- 本地已同步修正该追踪歧义:`RP-047` 明确标注为已被 `RP-050` 覆盖,后续不得恢复 `MakePointerType()` precise registration
- 远端测试信号保持通过:最新 CTRF 汇总为 `2118/2118` passedMegaLinter 仅剩 `dotnet-format` restore failure 预警,当前未提供本地仍然成立的文件级格式问题
- `2026-04-20` 已完成一轮冷启动反射收敛:
- generated registry 类型首次分析后,会缓存一个可复用的激活工厂,而不是在后续容器注册时重复走 `ConstructorInfo.Invoke`
- 若运行环境不允许动态方法,仍保留原有的反射激活回退,避免阻塞 generated registry 路径
- `GFramework.Cqrs.Tests` 已补充“私有无参构造 registry 仍可激活”的回归覆盖
- `2026-04-20` 已完成一轮 generator 覆盖面扩展:
- `CqrsHandlerRegistryGenerator` 现会在 runtime type 建模入口直接拒绝 `IPointerTypeSymbol``IFunctionPointerTypeSymbol`
- `CanReferenceFromGeneratedRegistry` 不再递归判断 pointer / function pointer 的内部元素,而是统一返回 `false`
- 相关 source-generator 回归已改为区分输入源诊断与生成源诊断,避免把非法泛型合同误判为成功生成
- `2026-04-20` 已完成一轮 registrar reflection 路径收敛:
- `CqrsHandlerRegistrar` 现会按 `Type` 弱键缓存已筛选且排序好的 supported handler interface 列表
- 同一 handler 类型跨容器重复注册时,不再重复执行 `GetInterfaces()` 与支持接口筛选
- `GFramework.Cqrs.Tests` 已补充 registrar 静态缓存隔离与 supported interface 缓存复用回归
- `2026-04-20` 已完成一轮 registrar 去重路径收敛:
- `CqrsHandlerRegistrar` 现会在单次 reflection 注册流程开始时构建已注册 handler 映射索引
- 同一批注册中后续 duplicate handler mapping 不再重复线性扫描 `IServiceCollection`
- `GFramework.Cqrs.Tests` 已补充“程序集返回重复 handler 类型时仍只注册一份映射”的回归
- `2026-04-29` 已完成一轮 generator fallback 元数据收敛:
- `CqrsHandlerRegistryGenerator` 现会探测 runtime 是否同时支持 `params string[]``params Type[]` 两类 `CqrsReflectionFallbackAttribute` 构造函数
- 当本轮 fallback handlers 全部可被生成代码直接引用时,生成器会优先发射 `typeof(...)` 形式的程序集级 fallback 元数据,减少运行时 `Assembly.GetType(...)` 回查
- 当 fallback handlers 中仍存在不能直接引用的实现类型时,生成器继续统一发射字符串元数据,避免 mixed 场景只恢复部分 handlers
- `GFramework.SourceGenerators.Tests` 已补充 runtime 同时暴露两类构造函数时优先选择直接 `Type` 元数据的回归
- `2026-04-29` 已完成一轮 mixed fallback 元数据拆分:
- `CqrsReflectionFallbackAttribute` 现显式允许 `AllowMultiple = true`
- `CqrsHandlerRegistryGenerator` 现会探测 runtime 是否允许多个 fallback 特性实例
- 当本轮 fallback 同时包含可直接引用与仅能按名称恢复的 handlers且 runtime 同时支持 `Type[]``string[]` 和多实例特性时,生成器会拆分输出两段 fallback 元数据
- `GFramework.Cqrs.Tests` 已补充 mixed fallback metadata 回归,锁定 registrar 只对字符串条目执行定向 `Assembly.GetType(...)`
- `GFramework.SourceGenerators.Tests` 已补充 mixed fallback emission 回归,锁定 generator 会输出两个程序集级 fallback 特性实例而不是整体退回字符串
- `2026-04-29` 已重新执行 `$gframework-pr-review`
- 当前分支对应 `PR #302`,状态为 `OPEN`
- latest reviewed commit 当前剩余 `3` 条 open AI review threads`2` 条 Greptile、`1` 条 CodeRabbit
- 本地核对后确认 `dotnet-format` 仍只有 `Restore operation failed` 噪音,没有附带当前仍成立的文件级格式诊断
- 已按 review triage 修正 generator source preamble 的多实例 fallback 特性排版、移除死参数,并补强 mixed/direct fallback 发射回归断言与 XML 文档
- `2026-04-30` 已重新执行 `$gframework-pr-review`
- 当前分支对应 `PR #305`,状态为 `OPEN`
- 当前抓取到 `9` 条 CodeRabbit open threads、`2` 条 Greptile open threads远端 CTRF 汇总为 `2214/2214` passedMegaLinter 仍只暴露 `dotnet-format``Restore operation failed` 环境噪音
- 本地核对后,已确认以下评论仍然成立并已完成修正:`ArchitectureContextTests` 并发测试失败路径释放、`CqrsGeneratedRequestInvokerProviderTests` 的全局 logger provider 恢复与私有缓存断言解耦、`CqrsArchitectureContextIntegrationTests` 的真实上下文注入断言、`GeneratedRequestInvokerRequest` / `INotificationPublisher` XML 文档、`CqrsHandlerRegistrar` 的 provider 注册顺序、`CqrsTestRuntime` 的 legacy alias 显式失败模式,以及 `cqrs-rewrite` trace 重复标题
- 对于 `ICqrsRequestInvokerProvider` / generated `TryGetDescriptor(...)` 相关 Greptile 评论,本地评估后未改 dispatcher 热路径语义;改为补齐公开注释与生成器方法级注释,明确默认 runtime 只在注册阶段经 `IEnumeratesCqrsRequestInvokerDescriptors` 预热缓存,`TryGetDescriptor(...)` 保留为显式查询 seam
- 本轮额外修正了 `GFramework.SourceGenerators.Tests` 中先读取 `GeneratedSources[0]` 再断言长度的脆弱顺序,并将 `ArchitectureContextTests` 的并发 orchestration 收敛到公共 helper消除本轮引入的 `MA0051` warning
- `2026-04-29` 已完成一轮 precise runtime type lookup 的数组回归补强:
- `GFramework.SourceGenerators.Tests` 已新增多维数组、交错数组、外部程序集隐藏元素类型三类回归
- 当前生成器在 precise runtime type lookup 下已稳定保留数组秩信息,并递归发射交错数组的 `MakeArrayType()`
- 本轮定向测试未暴露数组发射缺陷,因此未改动 fallback 合同选择逻辑,也未调整 direct / named / mixed fallback 排版路径
- `2026-04-29` 已补齐一轮外部程序集隐藏泛型定义回归覆盖:
- `GFramework.SourceGenerators.Tests` 已新增“外部程序集隐藏泛型定义 + 可见类型实参”的 precise registration 回归
- 当前生成器会继续为这类 handler 合同发射 `ResolveReferencedAssemblyType(...) + MakeGenericType(...)` 组合,而不是退回字符串 fallback 元数据
- 本轮定向测试未暴露新的实现缺口,因此未改动 direct / named / mixed fallback 选择逻辑,也未调整 generator runtime type 建模实现
- `2026-04-29` 已完成一轮缓存工厂闭包收敛:
- `CqrsDispatcher` 现会在 notification / stream / request binding 与 pipeline executor 缓存入口优先使用无捕获工厂
- `CqrsHandlerRegistrar` 现会在程序集元数据缓存与可加载类型缓存入口复用 `static` 工厂 + 显式状态参数
- 本轮未改动公开语义,也未修改 fallback 合同与 handler / behavior 生命周期边界
- `2026-04-29` 已完成一轮 request pipeline executor 形状缓存:
- `CqrsDispatcher` 现会继续按 `requestType + responseType` 缓存 request dispatch binding并在 binding 内按 `behaviorCount` 缓存强类型 pipeline executor
- 每次分发只绑定当前 handler / behaviors 实例,不缓存容器解析结果,因此不改变 transient 生命周期与上下文注入语义
- `GFramework.Cqrs.Tests` 已补充 executor 首次创建 / 后续复用与双行为顺序回归
- `2026-04-29` 已完成一轮 cached executor 上下文刷新回归补强:
- `GFramework.Cqrs.Tests` 已新增 `DispatcherPipelineContextRefresh*` 测试替身,分别记录 request handler 与 pipeline behavior 在每次分发中实际观察到的实例身份与 `ArchitectureContext`
- `CqrsDispatcherCacheTests` 现明确断言:同一个 cached request pipeline executor 在重复分发时会继续命中同一 executor 形状,但不会跨分发保留旧上下文
- 本轮定向测试未暴露新的 runtime 缺口,因此没有改动 `GFramework.Cqrs/Internal/CqrsDispatcher.cs`
- `2026-04-29` 已完成一轮 cached notification / stream binding 上下文刷新回归补强:
- `GFramework.Cqrs.Tests` 已新增 `DispatcherNotificationContextRefresh*``DispatcherStreamContextRefresh*` 测试替身,分别记录 notification handler 与 stream handler 在重复分发时观察到的实例身份与 `ArchitectureContext`
- `CqrsDispatcherCacheTests` 现明确断言:同一个 cached notification / stream dispatch binding 在重复分发时会继续命中同一 binding但不会跨分发保留旧上下文
- 本轮定向测试未暴露新的 runtime 缺口,因此没有改动 `GFramework.Cqrs/Internal/CqrsDispatcher.cs`
- `2026-04-29` 已完成一轮 dispatcher 上下文前置条件失败语义回归:
- `GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherContextValidationTests.cs` 已通过公开工厂 `CqrsRuntimeFactory.CreateRuntime(...)` 锁定默认 dispatcher 的失败语义
- 当 context-aware request / notification / stream handler 遇到仅实现 `ICqrsContext`、但未实现 `IArchitectureContext` 的上下文时dispatcher 会在调用前显式抛出 `InvalidOperationException`
- 本轮只补测试,不改 runtime 实现与文档口径
- `2026-04-29` 已接受一轮 delegated registrar fallback 失败分支测试:
- `GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarFallbackFailureTests.cs` 已覆盖 named fallback 无法解析、named fallback 解析抛异常、direct fallback 跨程序集三类 warning 语义
- 主线程已复核该新文件并重新执行定向测试,确认当前 registrar 在 fallback 元数据失效时仍保持“跳过条目 + 记录告警”的既有语义
- `2026-04-29` 已接受一轮 delegated 叶子级 fallback 合同测试:
- `GFramework.Cqrs.Tests/Cqrs/CqrsReflectionFallbackAttributeTests.cs` 已锁定空 marker、字符串 fallback 名称去空/去重/排序、直接 `Type` fallback 去空/去重/排序与空参数数组防御语义
- 当前 runtime 读取程序集级 fallback 元数据时所依赖的 attribute 归一化合同,现已有独立叶子级测试文件覆盖
- `2026-04-29` 已完成一轮 CQRS 入口文档对齐:
- `GFramework.Cqrs/README.md``docs/zh-CN/core/cqrs.md``docs/zh-CN/api-reference/index.md` 现已明确 generated registry 优先、targeted fallback 补齐剩余 handler 的当前语义
- `2026-04-29` 已完成一轮 generator pointer runtime-reconstruction 残留清理:
- `CqrsHandlerRegistryGenerator` 的运行时类型引用模型已移除不可达的 pointer 子结构
- `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`
- `2026-04-30` 已接受两条只读 subagent 结论并完成 notification publisher seam 最小实现:
- 相对 `ai-libs/Mediator`,本轮只吸收 notification publisher 的策略接缝,不照搬 `NotificationHandlers<T>` 包装、
并行 publisher 或异常聚合语义
- 当前 seam 刻意保持在默认 runtime 内部:`ICqrsRuntime.PublishAsync(...)` 外形不变dispatcher 仍负责 handler 解析与
`IContextAware` 上下文注入
- 用户若需替换通知发布策略,只需在 runtime 创建前向容器显式注册 `INotificationPublisher`
- `2026-04-30` 已接受三条 worker 切片并完成一轮测试命名收口:
- 三个 worker 分别独立拥有一份 `GFramework.Cqrs.Tests/Mediator/*.cs` 文件,主线程只做集成验证与后续追踪更新
- 当前分支已不再保留 `GFramework.Cqrs.Tests/Mediator/` 目录下的生产内涵测试,相关文件均迁移到 `GFramework.Cqrs.Tests/Cqrs/`
- 本轮没有修改测试行为,只收口命名、注释、局部变量与嵌套测试类型语义
- 当前主线优先级:
- dispatch/invoker 反射占比继续下降,并优先评估生成前移方案
- 基于已落地 publisher seam继续评估是否需要公开配置面、并行策略或 telemetry decorator
- package / facade / 兼容层继续收口
- pipeline 分层扩展、可观测性 seam 与 benchmark baseline 进入中期候选
- 当前分支对应 `PR #307`,状态为 `OPEN`
- latest-head review 仍以 `ai-plan` 恢复文档收敛为主要待闭环项;代码与测试侧的本地有效问题已收敛
- 远端 `CTRF` 最新汇总为 `2247/2247` passed
- `MegaLinter` 当前只暴露 `dotnet-format``Restore operation failed` 环境噪音,尚未提供本地仍成立的文件级格式诊断
## 当前风险
- 当前 `dotnet build GFramework.sln -c Release` 在 WSL 环境仍会受顶层 `GFramework.csproj` 的 Windows NuGet fallback 配置影响
- 当前 `GFramework.Cqrs.Tests` 仍直接引用 `GFramework.Core`,说明测试已按模块意图拆分,但 runtime 物理迁移尚未完全切断依赖
- 当前对外替代已基本完成,但若不单独规划旧 `Command` / `Query``LegacyICqrsRuntime` 与测试命名的收口顺序,
后续仍会持续混淆“生产替代已完成”与“仓库内部收口未完成”这两个不同结论
- 顶层 `GFramework.sln` / `GFramework.csproj` 在 WSL 下仍可能受 Windows NuGet fallback 配置影响,完整 solution 级验证成本高于模块级验证
- 仓库内部仍保留旧 `Command` / `Query` API、`LegacyICqrsRuntime` alias 与部分历史命名语义,后续若不继续分批收口,容易混淆“对外替代已完成”与“内部收口未完成”
- 若继续扩大 generated invoker 覆盖面,需要持续区分“可静态表达的合同”与 `PreciseReflectedRegistrationSpec` 等仍需保守回退的场景
## 最近权威验证
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json --json-output /tmp/current-pr-review.json`
- 结果:通过
- 备注:确认当前分支对应 `PR #307`,本轮剩余 open AI feedback 主要集中在 `ai-plan` 收敛
- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Entry_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
- 结果:通过,`5/5` passed
## 下一推荐步骤
1. 继续处理 `PR #307` 的剩余 review 收尾,优先保持 `ai-plan` active 入口与 trace 的单一锚点一致
2. 若继续推进代码切片,优先复核 request 侧是否存在与 stream gate 对称的生成合同遗漏,再决定是否补同批 generator 回归
3. 在进入下一批 runtime / generator 收敛前,保持最小 Release build 或 targeted test 作为权威验证
## 活跃文档
- 历史跟踪归档:[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)
- `RP-063``RP-074` 验证归档:[cqrs-rewrite-validation-history-rp063-through-rp074.md](../archive/todos/cqrs-rewrite-validation-history-rp063-through-rp074.md)
- `RP-062``RP-076` trace 归档:[cqrs-rewrite-history-rp062-through-rp076.md](../archive/traces/cqrs-rewrite-history-rp062-through-rp076.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)
## 验证说明
## 说明
- `RP-043` 之前的详细阶段记录、定向验证命令和阶段性决策均已移入主题内归档
- `RP-046``RP-062` 的历史验证命令与阶段性结果已移入验证归档active tracking 只保留当前恢复入口需要的最新验证
- `RP-063``RP-074` 的详细验证命令与阶段性结果已移入验证归档active tracking 只保留当前 PR 复核批次的权威结果
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --json-output /tmp/current-pr-review.json`
- 结果:通过
- 备注:确认当前分支对应 `PR #307`,状态为 `OPEN`;当前仍有 `9` 条 CodeRabbit open thread本轮只接受其中经本地复核后仍成立的合同防御、文档和 tracking 建议
- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`
- 结果:通过
- 备注:`0 warning / 0 error`确认描述符前置防御、XML 文档与文档修正未引入 `GFramework.Cqrs` 模块告警
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests"`
- 结果:通过
- 备注:`16/16` passed确认非静态 invoker 回退语义、空 descriptor 枚举回退,以及既有 generated / incompatible 分支均保持通过
## 下一步
1. 在保持 branch diff 明显低于 `50 files` 的前提下,继续挑选下一批低风险 `dispatch/invoker` 收敛切片,并优先考虑 request / stream provider 的剩余缓存预热边界或 generator gate 合同补强
2. 基于已落地的 notification publisher seam评估是否需要第二阶段公开配置面、并行 publisher 或 telemetry decorator
3. 单独规划旧 `Command` / `Query` API 的收口顺序;`LegacyICqrsRuntime` compatibility slice 已收口到显式 helper 与专门测试,可暂时移出最高优先级
- `PR #261``PR #302``PR #305` 及更早阶段的详细过程已不再作为 active 恢复入口;如需追溯,以对应归档文件为准
- active tracking 仅保留当前恢复点、当前风险、最近权威验证与下一推荐步骤,避免 `boot` 落到历史阶段细节

View File

@ -2,435 +2,31 @@
## 2026-04-30
### 阶段PR #307 stream invoker gate 回归补强CQRS-REWRITE-RP-076
### 阶段PR #307 active 入口收敛CQRS-REWRITE-RP-076
- 继续沿用 `$gframework-pr-review``PR #307` 的 latest-head review triage只处理本地仍成立且写集可控的 generator regression gap
- 主线程复核 `GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs:88-92` 后确认:`supportsStreamInvokerProvider` 依赖四项合同,但现有测试只覆盖 `ICqrsStreamInvokerProvider``IEnumeratesCqrsStreamInvokerDescriptors` 缺失分支,确实遗漏 `CqrsStreamInvokerDescriptor` / `CqrsStreamInvokerDescriptorEntry`
- 本轮实现收敛:
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 新增两条 `RemoveBlock(...)` 回归,分别移除 `CqrsStreamInvokerDescriptor``CqrsStreamInvokerDescriptorEntry` 合同定义
- 新回归继续锁定统一结果:当 stream invoker runtime 合同四者缺一时generated registry 不会残留 provider 接口、descriptor entry 枚举或静态 invoker 桥接
- active tracking 已把恢复点推进到 `RP-076`,避免 PR review 结论只体现在测试代码里
- 继续沿用 `$gframework-pr-review``PR #307` 做 latest-head triage本轮只处理仍成立的 `ai-plan` 恢复入口问题
- 主线程确认当前远端权威信号:
- 当前分支对应 `PR #307`,状态为 `OPEN`
- 远端 `CTRF` 最新汇总为 `2247/2247` passed
- `MegaLinter` 仅剩 `dotnet-format``Restore operation failed` 环境噪音
- 仍未闭环的 review 重点集中在 `cqrs-rewrite` active tracking / trace 仍保留过多历史锚点,而非新的运行时代码缺陷
- 本轮决策:
- 将 active tracking 收敛为单一恢复入口,只保留 `RP-076``PR #307`、活跃风险、最近权威验证与下一推荐步骤
- 将 active trace 收敛为当前阶段的关键事实与决策,不再在默认恢复入口中保留 `RP-062` 之后的长阶段流水账
- 新增 `archive/traces/cqrs-rewrite-history-rp062-through-rp076.md` 承接 `RP-062``RP-076` 的详细 trace 历史,保持旧阶段仍可追溯
### 验证RP-076
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json --json-output /tmp/current-pr-review.json`
- 结果:通过
- 备注:确认 `PR #307` 的当前 review 重点已收敛到 `ai-plan` 文档收尾
- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- 备注:首轮并发跑 build/test 时出现过 `MSB3248` / `MSB3026` 输出文件占用噪音;按仓库规则改为串行复核后,本轮 authoritative build 结果为干净通过
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Entry_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
- 结果:通过,`5/5` passed
- 备注:新增两条 descriptor gate 回归与既有 stream happy-path 一并通过,确认 `supportsStreamInvokerProvider` 的四项合同缺一不可
### 当前下一步RP-076
1. 提交本轮 `PR #307` stream gate 合同补强与 `ai-plan` 恢复点更新
2. 后续若继续处理 review优先清点 request 侧是否也存在同构遗漏,再决定是否追加同批对称测试
3. 保持忽略工作区里无关的 `.gitignore` 本地改动,不把它混入本轮提交
### 阶段PR #307 review follow-up 收敛CQRS-REWRITE-RP-075
- 在 `RP-074` 后继续沿用 `gframework-batch-boot 50` 的低风险切片策略,本轮只处理 `$gframework-pr-review` 对当前 `PR #307` 仍然成立的本地问题
- 主线程先用 `fetch_current_pr_review.py --json-output /tmp/current-pr-review.json` 抓取 PR #307 的 latest-head open threads确认真正仍需处理的项集中在
- stream/request invoker 描述符入口缺少更早的合同防御
- request/stream provider 测试缺少“实现枚举契约但返回空 descriptor 集合”的回退覆盖
- `docs/zh-CN/core/cqrs.md` 把 generated metadata 不兼容时的行为误写成“回退到反射”
- active tracking 累积了 `RP-063``RP-074` 的长验证历史,不再适合作为默认恢复入口
- 本轮实现收敛:
- `GFramework.Cqrs/CqrsRequestInvokerDescriptor.cs``GFramework.Cqrs/CqrsStreamInvokerDescriptor.cs` 现会在构造阶段拒绝实例方法,把非法 generated metadata 失败点前移到 registrar 激活/预热阶段
- `GFramework.Cqrs/CqrsRequestInvokerDescriptorEntry.cs``GFramework.Cqrs/CqrsStreamInvokerDescriptorEntry.cs` 现补齐公开构造入口的空值防御,并保持 request / stream 形状对称
- `GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs` 现补齐 request / stream 的空 descriptor 枚举回退回归,并把“非静态 invoker”断言从首次分发抛错收敛为 registrar 放弃 generated registry 后回退到反射路径
- `GFramework.Cqrs.Tests/Cqrs/HiddenImplementationGeneratedStreamInvokerProviderRegistry.cs` 现补齐 `<exception>` XML 注释与 `TryGetDescriptor(...)` 参数空值防御
- `docs/zh-CN/core/cqrs.md` 现明确区分“未命中 generated descriptor 时回退到反射绑定”和“已命中的不兼容 generated metadata 会直接抛错”,并把 reader-facing 表格里的 `Internal/` 路径标签改成语义文案
- `ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md` 现把恢复点推进到 `RP-075`,同时把 `RP-063``RP-074` 的命令级验证历史迁移到新的归档文件active 入口只保留最近 PR 锚点与权威验证
### 验证RP-075
- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests"`
- 结果:通过,`16/16` passed
### 当前下一步RP-075
1. 提交本轮 PR #307 review follow-up 收敛保持恢复点、trace 与已验证代码状态一致
2. 若继续下一批,优先挑选 request / stream provider 的缓存预热边界或 generator gate 合同补强,而不是扩散到新的模块
3. 保持只暂存本轮相关文件,避免把工作区里无关的 `.gitignore` 本地改动混入提交
### 阶段non-enumerating provider reflection fallback 回归CQRS-REWRITE-RP-074
- 在 `RP-073` 提交后继续按 `gframework-batch-boot 50` 执行;当前 branch diff 相对 `origin/main` 仍远低于 `50 files` 阈值,因此继续追加一轮单文件 runtime contract 回归
- 本轮接受只读 subagent 的收敛建议把切片限定为“provider 已注册但未向 dispatcher 可枚举地贡献 descriptor”时的 fallback 语义
- 主线程已完成:
- `GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs` 新增 request / stream 两条回归,锁定仅实现 `ICqrsRequestInvokerProvider` / `ICqrsStreamInvokerProvider`、但未实现 `IEnumeratesCqrs*InvokerDescriptors` 的 registry 仍会让 dispatch 回退到既有反射路径
- 当前回归刻意不修改 `CqrsDispatcher``CqrsHandlerRegistrar`它只把现有实现和注释里已经隐含的“descriptor cache 预热优先于 provider 显式查询”语义提升为可执行合同
### 验证RP-074
- `dotnet build GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests"`
- 结果:通过,`14/14` passed
### 当前下一步RP-074
1. 先提交本轮 non-enumerating provider 回归与恢复点更新
2. 重新复算 branch diff 后,再判断是否继续推进 provider 的空枚举 descriptor 边界或在本轮阈值前停下
3. 若继续下一批,优先保持单文件测试写集,不扩散到新的模块
### 阶段generated invoker provider runtime 失败边界修复CQRS-REWRITE-RP-073
- 在 `RP-072` 提交后继续按 `gframework-batch-boot 50` 执行;当前 branch diff 相对 `origin/main` 仍为 `24 files`,文件阈值 headroom 依然充足,因此继续推进下一批 runtime 失败边界回归
- 本轮原计划只补 `CqrsGeneratedRequestInvokerProviderTests` 的 request / stream 非 happy-path 回归,但定向测试首轮直接暴露出一个真实 runtime 缺口:
- `CqrsDispatcher.CreateRequestInvokerDescriptor(...)``CreateStreamInvokerDescriptor(...)` 的 XML 文档和消息语义都承诺会抛 `InvalidOperationException`
- 实际实现先调用 `Delegate.CreateDelegate(...)`,当 invoker 签名不兼容时会直接冒出 `ArgumentException`,导致文档承诺与运行时行为不一致
- 主线程已完成:
- `GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs` 新增 request / stream 两组 `non-static invoker``incompatible invoker` 回归,并保留 request / stream happy-path 作为同批守护断言
- `GFramework.Cqrs/Internal/CqrsDispatcher.cs` 现对 request / stream 两条 descriptor 创建路径统一捕获 `ArgumentException`,并转换成带原有错误消息的 `InvalidOperationException`
- 新增异步断言已补齐 `ConfigureAwait(false)`,避免测试批次自身引入 `MA0004` analyzer warning
### 验证RP-073
- `dotnet build GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release`
- 结果:通过
- 备注:并行执行 build/test 时曾出现 `MSB3026` 输出文件竞争噪音;无真实编译失败,也未引入新增 analyzer warning
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests.SendAsync_Should_Throw_When_Generated_Request_Invoker_Is_Not_Static|FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests.SendAsync_Should_Throw_When_Generated_Request_Invoker_Is_Incompatible|FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests.CreateStream_Should_Throw_When_Generated_Stream_Invoker_Is_Not_Static|FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests.CreateStream_Should_Throw_When_Generated_Stream_Invoker_Is_Incompatible|FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests.SendAsync_Should_Use_Generated_Request_Invoker_When_Provider_Is_Registered|FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests.CreateStream_Should_Use_Generated_Stream_Invoker_When_Provider_Is_Registered"`
- 结果:通过,`6/6` passed
### 当前下一步RP-073
1. 先提交本轮 runtime 失败边界修复与恢复点更新
2. 重新复算 branch diff 后,再判断是否继续推进剩余 provider 失败边界或在接近阈值前停下
3. 若继续下一批,优先保持单文件或双文件写集,避免在本轮后段扩散 review 面积
### 阶段invoker provider gate 合同回归CQRS-REWRITE-RP-072
- 在 `RP-071` 提交后继续按 `gframework-batch-boot 50` 执行;当前 branch diff 相对 `origin/main` 仍为 `24 files`,未接近主要 stop condition因此继续追加一轮 test-only generator 合同回归
- 本轮接受一条只读 subagent 建议把下一批进一步收敛为“runtime 合同不完整时不发射 provider 元数据”的单文件测试波次
- 主线程已完成:
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 新增四条 gate 回归,分别锁定 request / stream 在缺少 provider 接口或缺少 descriptor 枚举接口时,都会整体跳过元数据发射
- 初版实现曾使用整段源码片段替换来删减测试输入,但因三引号字符串缩进差异导致 helper 匹配失败;随后改为按稳定起止标记移除源码块的 `RemoveBlock(...)` helper使测试意图与输入格式解耦
- 同一组定向验证同时保留 request / stream happy-path 两条既有回归,确认 gate 收紧后不会误伤原本完整合同下的 provider 发射
### 验证RP-072
- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`
- 结果:通过
- 备注:并行执行 build/test 时曾出现 `MSB3026` 输出文件竞争噪音;无真实编译错误,随后以串行 test 结果作为本轮 authoritative 行为验证
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
- 结果:通过,`6/6` passed
### 当前下一步RP-072
1. 先提交本轮 generator gate 合同回归与恢复点更新
2. 重新复算 branch diff 后,再决定是否继续推进 request / stream provider 的 runtime 失败边界测试
3. 若继续下一批,优先保持 test-only 或极小写集,避免在接近阈值前扩散到新的生产模块
### 阶段precise reflected invoker provider 合同边界回归CQRS-REWRITE-RP-071
- 在 `RP-070` 提交后继续按 `gframework-batch-boot 50` 执行;当前已提交 branch diff 仍为 `24 files`headroom 充足,因此继续下一批 generator-only 合同收敛
- 本轮先接受一条只读 subagent 的候选建议,评估是否可把 `PreciseReflectedRegistrationSpec` 的某个安全子集也纳入 request / stream provider 发射
- 主线程复核 `TryCreatePreciseReflectedRegistration(...)``CreateRequestInvokerEmissions(...)` / `CreateStreamInvokerEmissions(...)` 与现有 precise 测试素材后确认:
- precise reflected 分支之所以存在,正是因为 handler interface 的请求或响应类型无法完全通过 `typeof(...)` 稳定表达
- 当前 provider descriptor 合同需要直接发射 `typeof(requestType)` / `typeof(responseType)`;因此不存在可无条件放宽的“安全子集”
- 本轮最终不改生产 generator而是把这条边界显式固化到回归测试避免后续误把不存在的子集当成已支持能力
- 主线程已完成:
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 新增两条回归,分别锁定 request / stream 的 precise reflected 注册不会发射 invoker provider 元数据
- 同一组定向测试同时复核 hidden-implementation + visible-interface 场景仍会继续发射 provider 元数据,确保“允许发射”和“继续排除”的边界没有被本轮测试收紧弄混
### 验证RP-071
- `dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- 备注:并行验证时曾出现 `MSB3026` 输出文件竞争噪音,随后已串行重跑同批命令并取得干净结果
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_For_Precise_Reflected_Request_Registrations|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_For_Precise_Reflected_Stream_Registrations|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_For_Hidden_Implementation_With_Visible_Handler_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_For_Hidden_Implementation_With_Visible_Handler_Interface"`
- 结果:通过,`4/4` passed
- `git diff --name-only origin/main...HEAD | wc -l`
- 结果:通过
- 备注:当前相对 `origin/main` 的已提交 branch diff 仍为 `24 files`
- `git diff --numstat origin/main...HEAD`
- 结果:通过
- 备注:当前相对 `origin/main` 的工作分支累计 diff 为 `1793 changed lines`
### 当前下一步RP-071
1. 先提交本轮 generator 合同边界回归保持恢复点、trace 与已验证测试状态一致
2. 继续挑选下一批低风险切片,优先考虑 request / stream provider 的 runtime 或 generator 诊断边界,而不是贸然扩大 precise reflected 支持面
3. 若下一批仍可拆分为非冲突文件,再恢复只读 / 写入 subagent 的分工方式压低主线程上下文
### 阶段hidden-implementation generated invoker runtime 回归补强CQRS-REWRITE-RP-070
- 在 `5a77e2fb` 提交后补齐 active `ai-plan` 恢复入口,继续按 `gframework-batch-boot 50` 执行,基线仍为当前本地 `origin/main`
- 当前已提交 branch diff 复算为 `24 files / 1754 changed lines`,仍低于主要 stop condition因此本轮只补 runtime 回归与恢复点,不改 generator / runtime 生产实现
- 本轮关键目标是把 `RP-069` 已落地的 hidden-implementation provider 发射范围补强,继续向 runtime 消费侧闭环,避免 active tracking 只记录了 generator 侧验证
- 主线程已完成:
- `GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs` 新增 hidden-implementation + visible-interface 的 request / stream runtime 回归
- `HiddenImplementationGeneratedRequestInvokerProviderRegistry``HiddenImplementationGeneratedStreamInvokerProviderRegistry` 与对应 container fixture 已被纳入同一组 provider 消费测试,锁定 registrar 接线与 dispatcher 优先命中 generated descriptor 的语义
- 当前测试仍保持 `PreciseReflectedRegistrationSpec` 排除边界不变,不把隐藏 request/response 类型场景错误抬升为 runtime 支持承诺
### 验证RP-070
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests"`
- 结果:通过,`8/8` passed
- `git diff --name-only origin/main...HEAD | wc -l`
- 结果:通过
- 备注:当前相对 `origin/main` 的已提交 branch diff 为 `24 files`
- `git diff --numstat origin/main...HEAD`
- 结果:通过
- 备注:当前相对 `origin/main` 的已提交 branch diff 为 `1754 changed lines`
### 当前下一步RP-070
1. 先提交本轮 `ai-plan` 恢复点更新,保持 batch 追踪与已提交代码状态一致
2. 在剩余 headroom 内继续选择下一批低风险 `dispatch/invoker` 收敛切片,优先考虑 request / stream provider 的诊断、入口或测试补强
3. 如下一批写集仍可拆分,再用只读 / 写入 subagent 分离非冲突切片,继续降低主线程上下文压力
### 阶段generated stream invoker provider 最小落地CQRS-REWRITE-RP-068
- 继续按 `gframework-batch-boot 50` 执行,基线仍为当前本地 `origin/main`
- 本轮开始前,`origin/main` 已追平到当前 `HEAD`;因此 branch diff 重新归零,主 stop condition 仍为“相对 `origin/main` 接近 `50 files`
- 当前批次沿用上一轮 request invoker provider 的设计形状,只做 stream 路径的最小对称扩展,避免把 notification publisher seam、pipeline 或 telemetry 一并卷入
- 本轮切片拆分:
- worker`GFramework.Cqrs/README.md``docs/zh-CN/core/cqrs.md``docs/zh-CN/source-generators/cqrs-handler-registry-generator.md`
- worker`GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs`
- 主线程:`GFramework.Cqrs/Internal/CqrsDispatcher.cs``GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs`
`GFramework.Cqrs/*.cs` 新增 stream provider 契约、`GFramework.Cqrs.SourceGenerators/Cqrs/*`
`GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs`
- 主线程关键设计调整:
- 继续保持 dispatcher 的 stream binding 静态缓存只依赖 `requestType + responseType`,不回调具体容器实例
- stream provider 与 request provider 一样在 registrar 注册阶段一次性枚举 descriptor并写入 dispatcher 的进程级弱缓存
- generated registry 同时实现 request 与 stream 两组 descriptor 枚举契约时,改用显式接口实现 `GetDescriptors()`,避免同名方法冲突
- 已完成实现:
- `GFramework.Cqrs` 新增 `ICqrsStreamInvokerProvider``IEnumeratesCqrsStreamInvokerDescriptors`
`CqrsStreamInvokerDescriptor``CqrsStreamInvokerDescriptorEntry`
- `CqrsHandlerRegistrar` 新增 stream provider 接线与 descriptor 登记路径
- `CqrsDispatcher` 新增 generated stream invoker 弱缓存,并在 `CreateStream(...)` 首次创建 stream binding 时优先消费 generated stream invoker 元数据
- `CqrsHandlerRegistryGenerator` 新增 stream invoker registration 建模、descriptor 发射、显式枚举接口实现与 `InvokeStreamHandler{n}(...)` 静态桥接方法
- `GFramework.Cqrs.Tests` 新增 `GeneratedStreamInvokerProviderRegistry``GeneratedStreamInvokerRequest``GeneratedStreamInvokerRequestHandler`,并扩充 `CqrsGeneratedRequestInvokerProviderTests`
- `GFramework.Cqrs.SourceGenerators/README.md` 额外补齐模块级 README对齐 generated stream invoker 语义
- worker 产出已接受:
- 文档切片已把 request / stream invoker provider 作为并列 reader-facing 语义写入公开文档
- generator 测试切片已补齐 stream invoker provider fixture 与断言;主线程根据最终实现把 request / stream 的 `GetDescriptors()` 断言统一收敛到显式接口实现版本
### 验证RP-068
- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet build GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests"`
- 结果:通过,`4/4` passed
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
- 结果:通过,`2/2` passed
- `GIT_DIR=/mnt/f/gewuyou/System/Documents/WorkSpace/GameDev/GFramework/.git/worktrees/GFramework-cqrs GIT_WORK_TREE=/mnt/f/gewuyou/System/Documents/WorkSpace/GameDev/GFramework-WorkTree/GFramework-cqrs bash scripts/validate-csharp-naming.sh`
- 结果:通过
- `git diff --name-only origin/main...HEAD | wc -l`
- 结果:通过
- 备注:当前相对 `origin/main` 的已提交 branch diff 为 `4 files`
- `git diff --numstat origin/main...HEAD`
- 结果:通过
- 备注:当前相对 `origin/main` 的已提交 branch diff 为 `217 changed lines`
### 当前下一步RP-068
1. 在保持 branch diff 远低于 `50 files` 阈值的前提下,继续评估下一个低风险 `dispatch/invoker` 收敛切片
2. 优先候选仍是 notification 路径是否值得引入同类 generated invoker seam或继续补强 request / stream provider 的公开 API 入口与诊断语义
3. 下一批落地前先提交当前 stream provider 批次,避免未提交改动持续堆叠
### 阶段generated invoker reflected-implementation 发射范围补强CQRS-REWRITE-RP-069
- 在 `RP-068` 提交后,重新复算 branch diff相对 `origin/main` 升至 `20 files / 1015 changed lines`,仍明显低于 `gframework-batch-boot 50` 的 stop condition因此继续下一批
- 本轮目标只收敛 source generator不扩散到 runtime 或公开文档:把 generated request / stream invoker 的发射范围从“仅 direct registration”扩大到“实现类型隐藏、但 handler interface 可直接表达”的 reflected-implementation registration
- 接受只读 subagent 结论后确认:
- 现有分类阶段已经为 reflected-implementation registration 保留了 request / stream invoker registration 元数据
- 真正缺口只在 `CreateRequestInvokerEmissions(...)``CreateStreamInvokerEmissions(...)` 仍只遍历 `DirectRegistrations`
- `PreciseReflectedRegistrationSpec` 继续排除在 provider 发射范围外,避免隐藏 request/response 类型导致生成源码不可编译
- 主线程已完成:
- `ReflectedImplementationRegistrationSpec` 显式承载 request / stream invoker registration 元数据
- `CreateRequestInvokerEmissions(...)``CreateStreamInvokerEmissions(...)` 现会同时消费 reflected-implementation registration
- `GFramework.SourceGenerators.Tests` 已新增 hidden-implementation + visible-interface 两条 provider 回归
- 本轮不改 runtimedispatcher / registrar 对 generated provider 的消费语义保持不变,变化只在 generator 愿意发射更多可安全静态表达的 descriptor
### 验证RP-069
- `dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Generates_Direct_Interface_Registrations_For_Hidden_Implementation_When_Handler_Interface_Is_Public|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
- 结果:通过,`3/3` passed
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_For_Hidden_Implementation_With_Visible_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_For_Hidden_Implementation_With_Visible_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
- 结果:通过,`4/4` passed
### 当前下一步RP-069
1. 提交当前 generator-only 批次,继续保持每个低风险切片可独立回滚与审查
2. 继续评估下一个能明显降低反射占比、但不需要同时改动 runtime 语义的切片
### 阶段generated request invoker provider 最小落地CQRS-REWRITE-RP-067
- 继续按 `gframework-batch-boot 50` 执行,基线仍为本地现有 `origin/main`
- 在 `RP-066` 提交后复算 branch diff相对 `origin/main` 增长到 `22 files`,仍明显低于 `50 files` stop condition因此继续下一批
- 本轮 critical path 保持在主线程,本地完成 `dispatch/invoker` 生成前移的最小 request 切片;尝试委派 source-generator 测试给 worker 时因 subagent 名额已满失败,因此主线程直接接管该测试修改
- 本轮关键设计调整:
- 不按 `requestType.Assembly` 做 provider 发现,避免“请求定义在 A、handler 与 generated registry 在 B”时漏掉 generated invoker
- generated registry 若实现 `ICqrsRequestInvokerProvider`registrar 会在激活 registry 后把 provider 注册进容器,并通过 `IEnumeratesCqrsRequestInvokerDescriptors` 把描述符写入 dispatcher 的进程级弱缓存
- dispatcher 首次创建 request dispatch binding 时只按 `requestType + responseType` 读取静态弱缓存,不依赖具体容器实例;未命中时仍走既有反射创建路径
- 已完成实现:
- `GFramework.Cqrs` 新增 `ICqrsRequestInvokerProvider``IEnumeratesCqrsRequestInvokerDescriptors`
`CqrsRequestInvokerDescriptor``CqrsRequestInvokerDescriptorEntry`
- `CqrsHandlerRegistrar` 现会识别 generated registry 的 request invoker provider 能力,并登记 provider 与 request invoker 描述符
- `CqrsDispatcher` 新增 generated request invoker 弱缓存,并在 request binding 创建时优先消费该元数据
- `CqrsHandlerRegistryGenerator` 在 runtime 合同可用时,会让 generated registry 额外实现 request invoker provider 相关接口,并发射 descriptor 列表、`TryGetDescriptor(...)``GetDescriptors()` 与 request invoker 静态方法
- 已补充测试:
- `CqrsGeneratedRequestInvokerProviderTests` 锁定 registrar 会注册 generated request invoker provider且 dispatcher 走 generated invoker 后会返回 `generated:` 前缀结果
- `CqrsHandlerRegistryGeneratorTests` 锁定 generated source 会包含 request invoker provider 接口、descriptor 条目与 `InvokeRequestHandler0(...)` 方法
### 验证RP-067
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsGeneratedRequestInvokerProviderTests|FullyQualifiedName~CqrsHandlerRegistrarTests|FullyQualifiedName~CqrsDispatcherCacheTests"`
- 结果:通过,`22/22` passed
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
- 结果:通过,`1/1` passed
- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
### 当前下一步RP-067
1. 评估 notification / stream invoker 是否值得沿同一 provider 模式继续前移,或先补 request provider 的公开说明与诊断语义
2. 继续在保持 branch diff 低于阈值的前提下推进下一批;当前相对 `origin/main` 的 branch diff 为 `22 files`
### 阶段LegacyICqrsRuntime compatibility slice 收口CQRS-REWRITE-RP-066
- 继续按 `gframework-batch-boot 50` 执行,基线仍为本地现有 `origin/main`
- 在 `RP-065` 之后复算 branch diff相对 `origin/main` 仍为 `19 files`,明显低于 `50 files` stop condition因此继续下一批
- 本轮按“关键路径本地、非冲突文档委派”的方式拆成两个切片:
- worker`GFramework.Core.Abstractions/README.md``docs/zh-CN/abstractions/core-abstractions.md``docs/zh-CN/core/cqrs.md`
- 主线程:`GFramework.Core/Services/Modules/CqrsRuntimeModule.cs``GFramework.Tests.Common/CqrsTestRuntime.cs``GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs`
- 接受只读 subagent 结论后,将 `LegacyICqrsRuntime` 定位为“容器兼容层”,明确本轮不删除别名、不改 dispatcher 主体、不与旧 `Command` / `Query` API 清理混做
- 主线程已完成:
- `CqrsRuntimeModule` 把 legacy alias 注册收敛到 `RegisterLegacyRuntimeAlias(...)` helper并在 XML 文档里明确新旧服务类型解析到同一 runtime 实例
- `CqrsTestRuntime.RegisterInfrastructure(...)` 现也通过同名 helper 补齐 legacy alias当容器只预注册正式 `ICqrsRuntime` seam 时,会在幂等接线时回填旧命名空间 alias
- `MicrosoftDiContainerTests` 新增 `RegisterInfrastructure_Should_Backfill_Legacy_Cqrs_Runtime_Alias_With_The_Same_Instance`,锁定“只存在正式 seam 时也会补旧 alias且两者仍指向同一实例”的兼容合同
- worker 已完成文档收口:
- `GFramework.Core.Abstractions/README.md`
- `docs/zh-CN/abstractions/core-abstractions.md`
- `docs/zh-CN/core/cqrs.md`
- 三处文档都已明确:`GFramework.Core.Abstractions.Cqrs.ICqrsRuntime` 只是旧命名空间下保留的 compatibility alias新代码应依赖 `GFramework.Cqrs.Abstractions.Cqrs.ICqrsRuntime`
### 验证RP-066
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~MicrosoftDiContainerTests"`
- 结果:通过,`42/42` passed
- `dotnet build GFramework.Core/GFramework.Core.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
### 当前下一步RP-066
1. 在保持 branch diff 低于阈值的前提下,回到 `dispatch/invoker` 生成前移主线
2. 优先尝试只覆盖 request 路径的 generated invoker/provider 最小切片,避免一次卷入 notification / stream / pipeline executor
3. 下一次 batch 结束后继续复算 branch diff确认距 `50 files` stop condition 的剩余 headroom
### 阶段:测试命名收口与 ArchitectureContext lazy-resolution 回归CQRS-REWRITE-RP-065
- 继续按 `gframework-batch-boot 50` 执行,基线仍为本地现有 `origin/main`
- `22f608eb` 之后复算 branch diff相对 `origin/main` 已达到 `18 files`,仍明显低于 `50 files` stop condition因此继续下一批
- 本轮拆成四个互不冲突切片:
- worker 1`MediatorAdvancedFeaturesTests.cs`
- worker 2`MediatorArchitectureIntegrationTests.cs`
- worker 3`MediatorComprehensiveTests.cs`
- 主线程:`GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs`
- 三个 worker 均只收口单文件命名与注释语义,并把测试文件迁移到 `GFramework.Cqrs.Tests/Cqrs/`
- 主线程新增 `ArchitectureContextTests` 并发 lazy-resolution 回归,锁定:
- `PublishAsync(...)` 在并发首次访问时只解析一次 `ICqrsRuntime`
- `CreateStream(...)` 在并发首次访问时只解析一次 `ICqrsRuntime`
- 集成后已确认三份测试文件中不再残留 `GFramework.Cqrs.Tests.Mediator` 命名空间或 `Mediator` 语义命名
### 验证RP-065
- `dotnet build GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~ArchitectureContextTests"`
- 结果:通过,`22/22` passed
### 当前下一步RP-065
1. 继续 `Phase 8` 主线,回到 `dispatch/invoker` 生成前移或 `LegacyICqrsRuntime` 收口的下一个低风险切片
2. 在下一次 batch 结束后复算 branch diff确认距 `50 files` stop condition 的剩余 headroom
### 阶段notification publisher seam 最小落地CQRS-REWRITE-RP-064
- 本轮按 `gframework-batch-boot 50` 继续 `cqrs-rewrite`,基线使用本地现有 `origin/main`
- 当前 branch diff 相对 `origin/main` 开始时仅 `3 files / 164 lines`,远低于 `50 files` stop condition因此继续推进真实代码切片
- 主线程锁定 `notification publisher seam` 为本轮最低风险高收益切片,并保持关键路径在本地实现
- 接受两条只读 subagent 结论:
- 对照 `ai-libs/Mediator` 后,只吸收 notification publisher 策略接缝,不在本轮引入并行 publisher、异常聚合或公开配置面
- 现有仓库测试需要锁定的兼容语义是:零处理器静默完成、顺序执行、首错即停、上下文逐次注入
- 已完成实现:
- `GFramework.Cqrs` 新增 `INotificationPublisher``NotificationPublishContext<TNotification>`
`DelegatingNotificationPublishContext<TNotification, TState>` 与默认 `SequentialNotificationPublisher`
- `CqrsDispatcher.PublishAsync(...)` 改为解析 handlers 后构造发布上下文,并委托给 publisher seam 执行
- `CqrsRuntimeFactory``CqrsRuntimeModule``GFramework.Tests.Common.CqrsTestRuntime` 现会在 runtime 创建前复用容器里已注册的 `INotificationPublisher`
- `GFramework.Cqrs.Tests` 新增 `CqrsNotificationPublisherTests`,覆盖自定义 publisher、上下文注入、零处理器、首错即停与默认接线复用
- `GFramework.Cqrs/README.md``docs/zh-CN/core/cqrs.md` 已同步说明默认通知语义与可替换 seam
- 中途验证曾因并行 .NET 构建产生输出文件锁噪音;已改为串行重跑并获取干净结果
### 验证RP-064
- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet build GFramework.Core/GFramework.Core.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsNotificationPublisherTests"`
- 结果:通过,`5/5` passed
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~MicrosoftDiContainerTests"`
- 结果:通过,`41/41` passed
- `GIT_DIR=/mnt/f/gewuyou/System/Documents/WorkSpace/GameDev/GFramework/.git/worktrees/GFramework-cqrs GIT_WORK_TREE=/mnt/f/gewuyou/System/Documents/WorkSpace/GameDev/GFramework-WorkTree/GFramework-cqrs bash scripts/validate-csharp-naming.sh`
- 结果:通过
### 当前下一步RP-064
1. 评估 notification publisher seam 的第二阶段是否需要公开配置面、并行 publisher 或 telemetry decorator
2. 把 `dispatch/invoker` 生成前移重新拉回 `Phase 8` 主线,作为下一个实现切片
### 阶段CQRS vs Mediator 评估归档CQRS-REWRITE-RP-063
- 本轮按用户要求使用 `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 生成前移做下一轮设计收敛”
### 验证RP-063
- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
## 活跃事实
- 当前主题仍处于 `Phase 8`
- 当前主题的主问题已从“是否完成外部依赖替代”转为“内部兼容层收口顺序与下一轮能力深化优先级”
- 已完成阶段的详细执行历史不再留在 active trace默认恢复入口只保留当前恢复点、活跃事实、风险与下一步
## 当前风险
- 当前 `dotnet build GFramework.sln -c Release` 在 WSL 环境仍会受顶层 `GFramework.csproj` 的 Windows NuGet fallback 配置影响
- 若不把“生产替代完成”与“仓库内部收口完成”分开记录,后续很容易重复争论当前 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. 补一轮最小 Release 构建验证,确认本次 `ai-plan` 与评估文档更新未引入仓库级异常
2. 以 `notification publisher seam``dispatch/invoker` 生成前移为优先对象,形成下一轮可执行设计
1. 继续按 `PR #307` 的 latest-head review 收尾,优先保持 active tracking 与 active trace 的单一锚点一致
2. 若继续推进代码切片,先复核 request 侧是否仍存在与 stream invoker gate 对称的生成合同遗漏
3. 进入下一批前继续使用最小 Release build 或 targeted test 作为权威验证,避免把环境噪音误判为代码问题