- 新增 活跃主题的 archive 目录并归档已完成且已验证的历史 tracking 与 trace\n- 更新 ai-plan 治理规则、README 与 boot skill,明确 active todo 和 trace 必须保持精简\n- 收短 ai-plan-governance、ai-first-config-system 与 cqrs-rewrite 的默认恢复入口并补充归档索引
101 KiB
CQRS 重写迁移追踪
2026-04-14
阶段:初始化
- 建立
CQRS-REWRITE-RP-001恢复点 - 已确认本次迁移目标:
- 彻底参考
Mediator思路重写 GFramework 正式 CQRS - 不保留对
Mediator的兼容层 - 使用
abstractions + runtime 可选模块边界 - 保留
EventBus,不与 CQRS notification 合并
- 彻底参考
已确认的实现前提
CoreGrid-Migration当前仍依赖 NuGet 版GeWuYou.GFramework*CoreGrid/scripts/core/GameArchitecture.cs与CoreGrid-Migration/scripts/core/GameArchitecture.cs通过AddMediator(...)启用基于生成器的 runtimeGFramework当前IArchitectureContext与一批 CQRS 基类直接引用Mediator.*CoreGrid/scripts/cqrs/**的 handler 很薄,主要迁移成本在框架 runtime 和注册机制,不在业务逻辑本身
当前动作
- 准备更新
AGENTS.md,补充恢复点 / trace / subagent 协作规范 - 准备将
CoreGrid-Migration切换为本地项目引用,建立真实验证链路
下一步
- 完成
AGENTS.md规则补充 - 改造
CoreGrid-Migration/CoreGrid.csproj为本地项目与本地生成器引用 - 进行第一次构建验证,确认本地链路可用
阶段:CQRS 主路径迁移完成
CoreGrid-Migration/CoreGrid.csproj已切到本地ProjectReference+ 本地 source generatorsCoreGrid-Migration/scripts/core/GameArchitecture.cs已删除AddMediator(...)配置钩子GFramework.Core.Abstractions新增 GFramework 自有 CQRS 契约与UnitIArchitectureContext/ArchitectureContext已切到自有 CQRS 签名ArchitectureBootstrapper已内建 handler 扫描注册,使用方无需再显式调用AddMediator(...)CqrsDispatcher已补齐 request/notification/stream dispatch 与 pipeline behavior 执行GFramework.Core.Cqrs.*基类、ContextAwareMediator*Extensions、Godot 协程上下文扩展均已迁到新契约GFramework.Core.Tests中原依赖旧Mediator注册入口的测试已迁移到CqrsTestRuntime反射注册路径
阶段:验证
dotnet build GFramework.Core/GFramework.Core.csproj- 结果:通过
dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj- 结果:通过
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj --no-build- 结果:通过
- 明细:
1621个测试全部通过
dotnet build GFramework.sln- 结果:通过
dotnet build ../CoreGrid-Migration/CoreGrid.sln- 结果:通过
- 备注:仅存在既有 analyzer warnings,无新增构建错误
阶段:CQRS 收尾修正
- 建立
CQRS-REWRITE-RP-003恢复点 - 修正
IArchitectureContext、QueryBase、Abstract*Handler与MessageHandlerDelegate的 XML 文档,明确旧 Command/Query 总线与新 CQRS runtime 的兼容边界 CqrsHandlerRegistrar改为按程序集名、处理器类型名与处理器接口名稳定排序CqrsHandlerRegistrar在ReflectionTypeLoadException场景下会记录告警并保留可加载类型继续注册- 自动扫描到的 request / notification / stream handler 改为 transient,避免
ContextAwareBase派生处理器在并发请求间共享可变上下文 CqrsTestRuntime移除自建 pipeline 执行逻辑,测试改为走ArchitectureContext.SendRequestAsync(...)正式入口MediatorAdvancedFeaturesTests为断路器静态状态补上统一重置,消除测试间污染
阶段:补充验证
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorAdvancedFeaturesTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorComprehensiveTests"
- 结果:通过
- 明细:49 个测试全部通过
阶段:review 收尾修正
- 建立
CQRS-REWRITE-RP-004恢复点 AbstractStreamCommandHandler<TCommand, TResponse>已把上下文注入窗口、瞬态实例约束与流创建/枚举取消边界移入显式<remarks>CqrsHandlerRegistrarTests已改为从CqrsTestRuntime.RegisterHandlers(...)真实入口覆盖部分类型加载失败场景,不再反射RecoverLoadableTypes(...)CqrsTestRuntime已补齐 XML 文档,并改为按IIocContainer + IEnumerable<Assembly> + ILogger精确绑定RegisterHandlers(...)反射签名,避免未来重载漂移- 定向验证期间发现
CqrsHandlerRegistrar.cs缺少Microsoft.Extensions.DependencyInjection的using,导致IServiceCollection无法编译;该编译阻塞已一并修复
阶段:review 修正验证
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
47个测试全部通过
阶段:去外部依赖收尾
- 建立
CQRS-REWRITE-RP-005恢复点 GFramework.Core.Abstractions已移除Mediator.Abstractions包引用,并显式改依赖Microsoft.Extensions.DependencyInjection.Abstractions以承接IServiceCollection/IServiceScopeGFramework.Core.Tests已移除Mediator.Abstractions与Mediator.SourceGenerator包引用MediatorCoroutineExtensions已改为直接走IArchitectureContext.SendAsync(...)内建 CQRS 入口,不再解析IMediatorArchitecture/ArchitectureModules/IIocContainer/MicrosoftDiContainer/ArchitectureBootstrapper与主文档已补充“历史命名保留,但 runtime 已为内建 CQRS”说明- 并行 subagent 盘点确认:生产代码与主文档中剩余的
Mediator主要是历史兼容命名,不再对应任何外部包依赖
阶段:去外部依赖验证
dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build- 结果:通过
- 明细:
1624个测试全部通过
dotnet build ../CoreGrid-Migration/CoreGrid.sln- 结果:通过
- 备注:仅存在既有 analyzer warnings 与
GodotProjectDir缺失导致的 generator warning,无新增构建错误
dotnet build GFramework.sln -c Release- 结果:失败
- 原因:当前 WSL 环境下顶层
GFramework.csproj仍引用 Windows NuGet fallback package folderD:\Tool\Development Tools\Microsoft Visual Studio\Shared\NuGetPackages - 结论:属于既有环境配置问题,与本轮 CQRS 去
Mediator改动无关
阶段:历史命名中性化
- 建立
CQRS-REWRITE-RP-006恢复点 IArchitecture/IIocContainer/Architecture/MicrosoftDiContainer已新增RegisterCqrsPipelineBehavior<TBehavior>()推荐入口- 旧的
RegisterMediatorBehavior<TBehavior>()已降级为[Obsolete]兼容包装层,并转发到新的 CQRS 中性命名 - 新增
ContextAwareCqrsExtensions、ContextAwareCqrsCommandExtensions、ContextAwareCqrsQueryExtensions与CqrsCoroutineExtensions - 旧的
ContextAwareMediator*Extensions与MediatorCoroutineExtensions已改为[Obsolete]兼容包装层 - 新的
ContextAwareCqrs*/CqrsCoroutineExtensions已放入独立命名空间,避免与旧扩展同时导入时产生调用歧义 ArchitectureModulesBehaviorTests、CqrsCoroutineExtensionsTests、docs/zh-CN/core/cqrs.md、docs/zh-CN/core/index.md与CoreGrid-Migration命中的旧扩展调用点已迁到新的中性命名入口
阶段:历史命名中性化验证
dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build- 结果:通过
- 明细:
1624个测试全部通过
dotnet build ../CoreGrid-Migration/CoreGrid.sln- 结果:通过
- 备注:消除了新增扩展类带来的调用歧义,仅剩既有 analyzer warnings
阶段:兼容层正式弃用
- 建立
CQRS-REWRITE-RP-007恢复点 IArchitecture、IIocContainer、Architecture、ArchitectureModules与MicrosoftDiContainer上剩余的RegisterMediatorBehavior<TBehavior>()已统一补充 future-major 移除说明ContextAwareMediatorExtensions、ContextAwareMediatorCommandExtensions、ContextAwareMediatorQueryExtensions与MediatorCoroutineExtensions已统一补充 future-major 移除说明- 上述历史兼容入口已统一加上
EditorBrowsable(EditorBrowsableState.Never),从 IntelliSense 主路径隐藏, 将迁移默认路径进一步收敛到新的Cqrs命名入口 docs/zh-CN/core/cqrs.md与CLAUDE.md已同步记录“兼容别名进入正式弃用周期”的事实MediatorCompatibilityDeprecationTests已新增并通过反射断言锁定:- 公开兼容方法保留行为兼容,但必须带有
Obsolete - 公开兼容方法与兼容扩展类型必须带有
EditorBrowsable(EditorBrowsableState.Never) - 弃用消息必须明确新的 CQRS 迁移目标与 future-major 移除预期
- 公开兼容方法保留行为兼容,但必须带有
阶段:兼容层正式弃用验证
dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build --filter "FullyQualifiedName~GFramework.Core.Tests.Cqrs.MediatorCompatibilityDeprecationTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Coroutine.CqrsCoroutineExtensionsTests"- 结果:通过
- 明细:
8个测试全部通过
阶段:CQRS source-generator 注册 MVP
- 建立
CQRS-REWRITE-RP-008恢复点 GFramework.Core.Abstractions已新增:ICqrsHandlerRegistryCqrsHandlerRegistryAttribute
CqrsHandlerRegistrar已优先尝试读取程序集级CqrsHandlerRegistryAttribute指向的生成注册器;当生成注册器缺失、类型无效或实例化失败时,会记录 warning 并自动回退到原有反射扫描路径GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已新增:- 为当前消费端程序集中的 concrete request / notification / stream handlers 生成单一程序集级注册器
- 生成注册顺序与 runtime 反射口径对齐,按实现类型与处理器接口名稳定排序
- 当程序集包含生成代码无法合法引用的 concrete handler(例如私有嵌套 handler)时,直接放弃生成,让 runtime 保持完整反射回退
docs/zh-CN/core/cqrs.md与CLAUDE.md已同步记录“生成注册器优先,反射扫描兜底”的当前行为
阶段:CQRS source-generator 注册验证
dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release- 结果:通过
dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-build --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
2个测试全部通过
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build --filter "FullyQualifiedName~GFramework.Core.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorComprehensiveTests"- 结果:通过
- 明细:
41个测试全部通过
阶段:review 收尾修正(并发 lazy 初始化与共享测试运行时)
ArchitectureContext的ICqrsRuntime惰性解析已从??=改为Lazy<ICqrsRuntime>, 并显式指定LazyThreadSafetyMode.ExecutionAndPublication- 新增
ArchitectureContextTests.SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently以回归锁定并发首次访问行为 - 两个测试项目中的
CqrsTestRuntime重复实现已收敛为单一共享源码文件tests/Shared/CqrsTestRuntime.cs - 共享
CqrsTestRuntime已移除GetType(..., throwOnError: true)后不可达的?? throw分支
阶段:review 收尾修正验证
dotnet test GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
49个测试全部通过
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-restore --filter "FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureContextTests|FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests"- 结果:通过
- 明细:
57个测试全部通过
- 并行执行两条
dotnet test时命中过一次project.assets.json文件竞争; 顺序重跑GFramework.Core.Tests --no-restore后通过,确认是 restore 并发噪音而非实现缺陷
阶段:测试公共基础设施模块化
- 已将临时共享源码目录
tests/Shared收敛为正式项目GFramework.Tests.Common CqrsTestRuntime已迁入GFramework.Tests.Common并改为由测试项目通过ProjectReference访问
2026-04-16
阶段:review 收尾修正(线程安全文档、未冻结态去重与 runtime 契约说明)
- 建立
CQRS-REWRITE-RP-020恢复点 GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs已在类级<remarks>中明确“该类型不是线程安全的,必须由外部同步边界串行访问”的设计约束GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs已补齐三个公开方法的 XML 契约:null参数对应ArgumentNullException- handler 缺失或上下文不满足
IArchitectureContext注入前提时对应InvalidOperationException CreateStream(...)额外说明了上下文需覆盖整个异步枚举生命周期
GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs已补充线性去重扫描的性能特征注释,并记录未来若出现大服务集合热点,可在更高层批处理中引入HashSet<(Type, Type)>GFramework.Core/Ioc/MicrosoftDiContainer.cs已将未冻结态GetAll<T>()/GetAll(Type)的引用去重逻辑收窄为:- 仍会折叠“不同
ServiceType指向同一实例”的兼容别名重复 - 不再吞掉“同一
ServiceType对同一实例的重复显式注册” - 当同一实例同时暴露多个服务类型时,优先保留请求类型对应分组,否则保留注册次数最多且首次出现最早的分组,以维持确定性
- 仍会折叠“不同
GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs已新增两个回归测试,分别锁定泛型与非泛型GetAll在未冻结态下的上述语义
阶段:RP-020 验证
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests"- 结果:通过
- 明细:
40个测试全部通过
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-restore --filter "FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests"- 结果:通过
- 明细:
40个测试全部通过
下一步
- 继续评估
CqrsHandlerRegistrar/ generated registry 的命中率提升空间,优先减少需要GetTypes()全量扫描的回退场景 - 若后续
MicrosoftDiContainer继续保留“未冻结时支持按可赋值类型观察实例”的宽语义,可考虑为 mixed alias + duplicate registration 组合场景再补一条更细的回归测试
2026-04-16
阶段:review 收尾修正(CQRS 程序集枚举输入固定与前置校验)
- 建立
CQRS-REWRITE-RP-021恢复点 GFramework.Core/Ioc/MicrosoftDiContainer.cs已将RegisterCqrsHandlersFromAssemblies(...)调整为:- 在进入容器写锁前先
ToArray()固定输入枚举 - 逐项执行
ArgumentNullException.ThrowIfNull(...) - 再把固定后的数组交给
ICqrsRegistrationService
- 在进入容器写锁前先
- 该调整把
null元素和依赖外部可变状态的延迟枚举拦截在容器入口处,避免更深层的反射/注册路径才暴露输入问题,也减少在写锁内枚举外部序列的非确定性 GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs已新增空程序集元素回归测试,锁定“先校验,再委托”的失败边界
阶段:RP-021 验证
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests"- 结果:通过
- 明细:
41个测试全部通过
下一步
- 若后续 review 继续聚焦容器显式注册入口,可考虑补一条“延迟枚举只在入口处物化一次”的行为测试
GFramework.sln已纳入GFramework.Tests.Common,测试公共基础设施不再悬空在 solution 外
阶段:测试公共基础设施模块化验证
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureContextTests|FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests"- 结果:通过
- 明细:
57个测试全部通过
dotnet test GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
49个测试全部通过
阶段:日志入口下沉与剩余 runtime behaviors 迁移
- 建立
CQRS-REWRITE-RP-016恢复点 LoggerFactoryResolver已从GFramework.Core下沉到GFramework.Core.Abstractions,继续保留GFramework.Core.Logging命名空间- 新的抽象层
LoggerFactoryResolver默认会优先反射解析GFramework.Core.Logging.ConsoleLoggerFactoryProvider - 当宿主未加载
GFramework.Core默认日志实现时,LoggerFactoryResolver会退回静默 provider,避免上层模块只为拿日志入口而重新依赖实现层 GFramework.Core已新增 type forward,继续对外暴露LoggerFactoryResolver,降低已编译消费端的运行时兼容风险LoggingBehavior<TRequest, TResponse>与PerformanceBehavior<TRequest, TResponse>已迁移到GFramework.Cqrs,同时继续保留GFramework.Core.Cqrs.Behaviors命名空间- 迁移后
GFramework.Core/Cqrs/*已全部搬空;当前 runtime 物理迁移残项只剩CqrsCoroutineExtensions - 并行 explorer 结论:
ICqrsRuntime的真实阻塞链路是ICqrsRuntime -> IArchitectureContext -> IContextAware / handler Context- 只要 CQRS handler 上下文模型仍直接依赖完整
IArchitectureContext,ICqrsRuntime就不能无损迁到GFramework.Cqrs.Abstractions CqrsCoroutineExtensions依赖TaskCoroutineExtensions与WaitForTask*,本质属于Core协程桥接层,不宜原样迁到GFramework.Cqrs- 若只追求下一步最小可行推进,应优先设计更窄的 CQRS 专用上下文 seam,并继续把协程桥接保留在
GFramework.Core
阶段:RP-016 验证
2026-04-16
阶段:ICqrsRuntime 归属收敛与兼容别名落地
- 建立
CQRS-REWRITE-RP-017恢复点 GFramework.Cqrs.Abstractions/Cqrs/ICqrsContext.cs已新增,作为 CQRS runtime 使用的最小上下文 marker seam:- 该 seam 仅用于切断
ICqrsRuntime -> IArchitectureContext的编译期循环依赖 - 当前 runtime 仍允许在实现层识别更具体的
IArchitectureContext,以兼容现有IContextAwarehandler 注入模型
- 该 seam 仅用于切断
GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs已新增并成为正式 runtime seam 归属GFramework.Core.Abstractions/Cqrs/ICqrsRuntime.cs已改为兼容别名:- 旧接口现在继承新的
GFramework.Cqrs.Abstractions.Cqrs.ICqrsRuntime - 通过
EditorBrowsable(EditorBrowsableState.Never)隐藏历史路径,避免新代码继续绑定旧 namespace
- 旧接口现在继承新的
IArchitectureContext已实现ICqrsContext,继续作为默认架构内的 CQRS 分发上下文CqrsDispatcher已改为按ICqrsContext接收分发上下文:- 对现有
IContextAwarehandler 的注入保留运行时兼容检查 - 若未来引入非架构型 CQRS context,实现层可显式阻止将其注入到仍要求
IArchitectureContext的历史 handler
- 对现有
ArchitectureContext、CqrsRuntimeFactory与默认 runtime 注册路径已切到新的GFramework.Cqrs.Abstractions.Cqrs.ICqrsRuntimeCqrsRuntimeModule与GFramework.Tests.Common/CqrsTestRuntime.cs已同时注册新旧ICqrsRuntime接口:- 主代码路径默认解析新接口
- 历史公开路径仍可解析到同一个 runtime 实例,避免 consumer 或测试基础设施立即断裂
- 本轮结论同步收敛:
- 旧
GFramework.Core.Abstractions.Cqrs*兼容面只保留ICqrsRuntime这一最小公共别名 GFramework.Core.Cqrs.Extensions不再视为需要继续正式维护的旧路径;仓库与CoreGrid-Migration已切到新的GFramework.Cqrs.Extensions入口
- 旧
阶段:迁移目标修正为“Core = App Runtime,CQRS = 集成子系统”
-
在重新评估 Phase 5/7 的边界目标后,确认此前“继续推动
Core尽量不依赖Cqrs”的方向已经偏离本任务的真正目标 -
迁移计划现正式修正为:
GFramework.Core.Abstractions -> GFramework.Cqrs.AbstractionsGFramework.Core -> GFramework.CqrsCore作为 App Runtime,默认集成 CQRS 子系统CQRS作为被集成的正式子系统,继续承接抽象层、实现层、generator 层
-
本次修正特别明确两点:
Core强依赖Cqrs是允许的,不再以“彻底零依赖”为目标- 但
Core不应依赖 CQRS 的细节结构,例如直接new具体 dispatcher、直接依赖 generator 生成类型、硬编码 handler/internal registry 细节
-
因此后续健康依赖标准改为:
- 单向依赖
- 通过 seam / 模块入口装配
- 默认集成,但理论上可替换 runtime
-
CqrsCoroutineExtensions的定位也一并修正:- 它不再是“尚未迁移干净的 CQRS runtime 残项”
- 而是
Core对 CQRS 的协程桥接层,保留在Core是合理结果
-
方向修正后的下一步主线:
- 停止继续为了纯边界推进高成本的上下文/桥接迁移
- 保持
Core -> Cqrs的健康单向依赖,继续避免细节泄漏 - 把精力转向 CQRS 子系统增强,尤其是 generator 覆盖面与低反射路径
-
同时补充一条实现约束:
- 后续 CQRS runtime、pipeline、generator 与低反射路径的设计与实现,应明确参考
Mediator中已经成熟可用的实现 - 目标是吸收其已验证的结构与经验,减少重复踩坑,而不是把这些运行时细节完全从零发明
- 后续 CQRS runtime、pipeline、generator 与低反射路径的设计与实现,应明确参考
-
dotnet build GFramework/GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj -c Release- 结果:通过
-
dotnet build GFramework/GFramework.Cqrs/GFramework.Cqrs.csproj -c Release- 结果:通过
-
dotnet build GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
-
dotnet build GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release- 结果:通过
-
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build --filter "FullyQualifiedName~GFramework.Core.Tests.Logging.LoggerFactoryTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Cqrs.MediatorCompatibilityDeprecationTests"- 结果:通过
- 明细:
20个测试全部通过
-
dotnet test GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --no-build --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Cqrs.Tests.Coroutine.CqrsCoroutineExtensionsTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
54个测试全部通过
阶段:Core 泄漏盘点与 handler 注册协调器下沉
- 建立
CQRS-REWRITE-RP-018恢复点 - 并行 explorer 盘点结论已收敛:
ArchitectureContext -> ICqrsRuntime属于合理的 runtime seam,不视为实现细节泄漏Core当前未直接依赖任何 generator 生成类型名或生成注册器具体类型- 主要值得继续收敛的实现细节泄漏点集中在:
MicrosoftDiContainer里原本维护的 handler 程序集去重状态与 registrar 调度ArchitectureBootstrapper对默认 handler 程序集的硬编码- 更长线的
IIocContainer/IArchitectureCQRS 装配 API 暴露面
- 本轮先完成最小落地收敛:
GFramework.Cqrs/ICqrsRegistrationService.cs已新增,作为 CQRS handler 程序集接入协调入口GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs已新增,将稳定程序集键去重与ICqrsHandlerRegistrar调度统一收敛到 CQRS runtime 内部GFramework.Cqrs/CqrsRuntimeFactory.cs已新增CreateRegistrationService(...)GFramework.Core/Services/Modules/CqrsRuntimeModule.cs现会同时注册:ICqrsRuntime- 旧
GFramework.Core.Abstractions.Cqrs.ICqrsRuntime兼容别名 ICqrsHandlerRegistrarICqrsRegistrationService
GFramework.Core/Ioc/MicrosoftDiContainer.cs已移除本地_registeredCqrsHandlerAssemblyKeys状态与 registrar 直连逻辑,RegisterCqrsHandlersFromAssemblies(...)现仅委托给ICqrsRegistrationServiceGFramework.Tests.Common/CqrsTestRuntime.cs已同步补齐ICqrsRegistrationService接线,保持裸测试容器与生产路径一致
- 这一轮结论是:
Core -> Cqrs的单向依赖可以保留- 但 CQRS handler 注册细节应继续下沉到 CQRS 子系统,而不是分散在容器壳层中
- 下一步主线可开始转向 generator / 低反射增强,而不是继续为边界纯化推进高成本桥接迁移
阶段:RP-018 验证
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureAdditionalCqrsHandlersTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests"- 结果:通过
- 明细:
43个测试全部通过
dotnet test GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
45个测试全部通过
- 在一次并行执行两条
dotnet test的尝试中再次命中GFramework.Cqrs.deps.json文件锁冲突; 顺序重跑后稳定通过,确认属于本地并发构建输出竞争,而不是本轮实现缺陷
阶段:generator 局部回退落地
- 建立
CQRS-REWRITE-RP-019恢复点 - 已将 CQRS handler generator 从“整程序集回退”推进到“局部 generated + 局部 reflection fallback”:
GFramework.Cqrs/CqrsReflectionFallbackAttribute.cs已新增,作为程序集级 fallback markerGFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs现会:- 继续为可由生成代码合法引用的 handlers 生成 registry
- 当程序集内同时存在不可见 handlers 且 runtime 合同支持 marker 时,额外生成
CqrsReflectionFallbackAttribute - 若消费端仍缺少该 marker 合同,则保持旧的整程序集回退行为,避免静默漏掉不可见 handlers
GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs已配套支持新的组合路径:- 优先执行 generated registry
- 若程序集带有
CqrsReflectionFallbackAttribute,则继续补一次 reflection 扫描 - reflection 补扫会按
ServiceType + ImplementationType去重,避免已由 generated registry 注册的映射重复写入
GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs已更新/新增:- 正常生成快照继续覆盖
- “私有嵌套 handler” 场景改为断言“仍生成可见 handler + 输出 fallback marker”
- 新增“旧 runtime 合同缺少 marker 时仍整程序集回退”的兼容回归
GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs已新增组合路径回归:- 当 generated registry 与 reflection fallback 同时参与时,剩余 handlers 会被补齐
- 已由 generated registry 注册的 handler 映射不会重复写入服务集合
阶段:RP-019 验证
dotnet test GFramework/GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
4个测试全部通过
dotnet test GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests"- 结果:通过
- 明细:
5个测试全部通过
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureAdditionalCqrsHandlersTests"- 结果:通过
- 明细:
2个测试全部通过
- 在并行执行三条
dotnet test时,SourceGenerators与Cqrs两条命中过一次本地 restore / deps 文件竞争; 顺序重跑后全部通过,确认属于本地并发构建输出竞争,不是本轮实现缺陷
阶段:runtime 物理迁移(第一批)
- 建立
CQRS-REWRITE-RP-014恢复点 GFramework.Core/Cqrs/Internal/CqrsDispatcher.cs、CqrsHandlerRegistrar.cs与DefaultCqrsHandlerRegistrar.cs已迁移到GFramework.Cqrs项目,保留原GFramework.Core.Cqrs.Internal命名空间,降低消费端源码层面的 breaking changeGFramework.Core/Cqrs/Command/CommandBase.cs、Query/QueryBase.cs、Request/RequestBase.cs与Notification/NotificationBase.cs已迁移到GFramework.CqrsGFramework.Core/Extensions/ContextAwareCqrsExtensions.cs、ContextAwareCqrsCommandExtensions.cs与ContextAwareCqrsQueryExtensions.cs已迁移到GFramework.CqrsICqrsHandlerRegistry与CqrsHandlerRegistryAttribute已从GFramework.Core.Abstractions收敛到GFramework.Cqrs根命名空间,作为 runtime 专属契约:- 这样避免了把依赖
ILogger/IServiceCollection的类型继续塞进GFramework.Cqrs.Abstractions - 同时规避
GFramework.Core.Abstractions <-> GFramework.Cqrs.Abstractions循环引用
- 这样避免了把依赖
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已同步迁移 metadata name:- handler interface 解析改为指向
GFramework.Cqrs.Abstractions.Cqrs - generated registry contract / attribute 改为指向
GFramework.Cqrs
- handler interface 解析改为指向
GFramework.Cqrs/CqrsRuntimeFactory.cs已新增,GFramework.Core/Services/Modules/CqrsRuntimeModule.cs与GFramework.Tests.Common/CqrsTestRuntime.cs现通过公开工厂接线默认 runtime / registrar, 不再跨程序集直接实例化内部实现- 迁移过程中确认
GFramework.Core/Coroutine/Extensions/CqrsCoroutineExtensions.cs仍依赖TaskCoroutineExtensions.AsCoroutineInstruction()等Core协程工具链, 因此本轮暂留GFramework.Core,未强行迁移
阶段:runtime 物理迁移(第一批)验证
dotnet build GFramework/GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release- 结果:通过
dotnet test GFramework/GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-build --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
3个测试全部通过
dotnet build GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release- 结果:通过
dotnet test GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
49个测试全部通过
dotnet build GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureAdditionalCqrsHandlersTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureContextTests"- 结果:通过
- 明细:
63个测试全部通过
- 并行执行两个会触发编译输出写入同一
GFramework.Tests.Common.dll的一次性 copy retry warning; 单次顺序验证通过,确认属于本地并行构建噪音,不是实现缺陷
2026-04-15
阶段:非默认程序集显式 CQRS 接入
- 建立
CQRS-REWRITE-RP-009恢复点 IArchitecture/IIocContainer/Architecture/ArchitectureModules/MicrosoftDiContainer已新增:RegisterCqrsHandlersFromAssembly(Assembly assembly)RegisterCqrsHandlersFromAssemblies(IEnumerable<Assembly> assemblies)
ArchitectureBootstrapper已改为复用容器公开入口完成默认程序集注册, 让“默认启动路径”和“额外程序集显式接入路径”统一走同一套 CQRS handler 注册逻辑MicrosoftDiContainer已按稳定程序集键去重 CQRS handler 注册, 避免同一程序集被默认路径、模块安装或用户初始化阶段重复接入时写入重复 handler 映射ArchitectureAdditionalCqrsHandlersTests已新增并锁定两类行为:- 显式接入扩展程序集时,运行时会通过程序集级
CqrsHandlerRegistryAttribute成功注册 handlers - 同一额外程序集被重复声明时,不会重复注册 handlers
- 显式接入扩展程序集时,运行时会通过程序集级
docs/zh-CN/core/cqrs.md与CLAUDE.md已同步补充新的显式接入入口与行为说明
阶段:非默认程序集显式 CQRS 接入验证
dotnet build GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
- 备注:仅存在既有
MA0048warnings,无新增构建错误
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build --filter "FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureAdditionalCqrsHandlersTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.RegistryInitializationHookBaseTests"- 结果:通过
- 明细:
13个测试全部通过
下一步
- 评估如何进一步降低“显式额外程序集接入”场景中的反射回退占比,让更多程序集直接命中生成注册器
- 评估是否将 CQRS 正式拆分为独立 abstractions 模块与 runtime 实现模块,并明确
GFramework.Core的最终依赖边界 - 为 future-major 版本准备兼容层真正移除时的 API 清理清单与升级说明
当前残留
- 兼容 API、测试目录与部分历史文档仍保留
Mediator前缀,但主入口已新增中性 CQRS 命名,且兼容 API 已进入正式弃用周期 - handler 自动注册当前已具备默认路径与显式扩展路径的统一入口,但仍有一部分程序集只能走反射回退
- solution 级
dotnet build GFramework.sln -c Release仍受既有 Windows NuGet fallback package folder 配置影响
下一步建议
- 优先补齐“非默认程序集”的 CQRS handler generator 接入点,例如显式模块程序集或扩展包程序集
- 在 source-generator 覆盖范围更明确后,评估是否把现有 CQRS runtime 从
GFramework.Core中继续外提为独立模块 - 再规划
RegisterMediatorBehavior、MediatorCoroutineExtensions与ContextAwareMediator*Extensions的最终删除窗口 - 评估是否为兼容层移除提供 analyzer 或 upgrade note,以降低 future-major 迁移成本
阶段:review 跟进微调
ArchitectureAdditionalCqrsHandlersTests已改为复用现有SyncTestArchitecture+AddPostRegistrationHook(...)测试基建,不再维护仅用于注入初始化逻辑的专用AdditionalHandlersTestArchitecture- “显式额外程序集去重”回归用例已加强为两个不同
Assemblymock 实例,但共享相同FullName稳定键, 直接锁定MicrosoftDiContainer的程序集键去重语义,而不是只验证同一 mock 实例的重复注册
下一步
- 运行
ArchitectureAdditionalCqrsHandlersTests定向回归,确认基建复用后显式程序集接入与去重行为保持通过 - 如需继续收敛测试样板,可再盘点
Architecture相关测试里仍然只用于初始化注入的本地架构类型
阶段:CQRS 模块边界评估
- 建立
CQRS-REWRITE-RP-010恢复点 - 已完成 Phase 5 的模块边界再评估,并新增
ai-plan/migration/CQRS_MODULE_SPLIT_PLAN.md - 本轮结论:
- 将 CQRS 拆为独立 abstractions/runtime 模块是成立的
- 但当前不能直接做“搬项目”式拆分,必须先完成
GFramework.Core -> CQRS runtime abstraction的依赖倒置
- 已确认的硬耦合点:
ArchitectureContext直接实例化CqrsDispatcherMicrosoftDiContainer直接调用CqrsHandlerRegistrarArchitectureBootstrapper在默认启动路径内隐含 CQRS runtime 已存在
- 已确认的消费端兼容压力:
CoreGrid-Migration/scripts/cqrs/**大量直接依赖CommandBase、Abstract*Handler与GFramework.Core.Cqrs.ExtensionsGFramework.Godot/Coroutine/ContextAwareCoroutineExtensions.cs直接依赖GFramework.Core.Cqrs.Extensions
- 新拆分草案明确了推荐目标:
GFramework.Cqrs.Abstractions:正式 CQRS 契约 + runtime seamGFramework.Cqrs:dispatcher、handler registrar、base handlers、behaviors、extensionsGFramework.Core.Abstractions:转为依赖GFramework.Cqrs.AbstractionsGFramework.Core:只保留架构集成与兼容壳层
下一步
- 进入 Phase 6,优先为 runtime 建立
ICqrsRuntime/ICqrsHandlerRegistrarseam - 将
ArchitectureContext与MicrosoftDiContainer改为依赖该 seam,而不是直接依赖CqrsDispatcher/CqrsHandlerRegistrar - 在默认启动行为与消费端源码保持兼容的前提下,补齐针对 seam 改造的定向测试
- 待 seam 稳定后,再创建
GFramework.Cqrs.Abstractions/GFramework.Cqrs项目骨架并推进源码迁移
阶段:CQRS runtime seam 落地
- 建立
CQRS-REWRITE-RP-011恢复点 GFramework.Core.Abstractions/Cqrs/ICqrsRuntime.cs与ICqrsHandlerRegistrar.cs已新增,明确 runtime 调度与 handler 接入的依赖倒置 seamCqrsDispatcher已改为实现ICqrsRuntime,并改为在调用时接收IArchitectureContextArchitectureContext已改为解析ICqrsRuntime,不再直接new CqrsDispatcher(...)MicrosoftDiContainer.RegisterCqrsHandlersFromAssemblies(...)已改为解析ICqrsHandlerRegistrar,不再直接调用CqrsHandlerRegistrarDefaultCqrsHandlerRegistrar与CqrsRuntimeModule已落地,使默认架构启动路径继续自动具备 CQRS runtime 与 handler 注册能力CqrsTestRuntime.RegisterInfrastructure(...)已新增,用于为裸MicrosoftDiContainer测试容器补齐与生产路径一致的 seam 基础设施- 针对
Clear()后重新接入 handler 的回归已补上“先恢复测试基础设施再验证 dedup 状态重置”的显式步骤
阶段:CQRS runtime seam 验证
dotnet build GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests|FullyQualifiedName~GFramework.Core.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureAdditionalCqrsHandlersTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.RegistryInitializationHookBaseTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
97个测试全部通过
下一步
- 进入 Phase 7,创建
GFramework.Cqrs.Abstractions/GFramework.Cqrs项目骨架 - 先迁移
GFramework.Core.Abstractions/Cqrs/*,并保持现有命名空间,避免同时引入 namespace breaking change - 再迁移
GFramework.Core/Cqrs/*、GFramework.Core.Cqrs.Extensions与相关协程扩展 - 最后处理
GFramework.SourceGenerators、顶层 meta package 与消费端 transitive 依赖图
阶段:CQRS abstractions 项目骨架与纯契约迁移
- 建立
CQRS-REWRITE-RP-012恢复点 GFramework.Cqrs.Abstractions与GFramework.Cqrs项目骨架已创建,并加入GFramework.slnGFramework.Core.Abstractions已改为引用GFramework.Cqrs.Abstractions- 以下纯 CQRS 契约已迁移到
GFramework.Cqrs.Abstractions,同时保持原命名空间GFramework.Core.Abstractions.Cqrs*不变:IRequest*/IStreamRequest*/INotification*IPipelineBehaviorMessageHandlerDelegateUnitCommand/Query/Request/Notification输入与标记契约ICqrsHandlerRegistrar
- 在实际迁移中确认:
ICqrsRuntime -> IArchitectureContextICqrsHandlerRegistry -> ILogger这两条依赖会导致GFramework.Core.Abstractions <-> GFramework.Cqrs.Abstractions循环引用风险,因此当前暂不迁出这三类类型:ICqrsRuntimeICqrsHandlerRegistryCqrsHandlerRegistryAttribute
阶段:CQRS abstractions 迁移验证
dotnet build GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
- 备注:仅存在既有
MA0048warnings(IStreamCommand/IStreamQuery文件命名)
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build --filter "FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests|FullyQualifiedName~GFramework.Core.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureAdditionalCqrsHandlersTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.RegistryInitializationHookBaseTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Core.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
97个测试全部通过
下一步
- 先为
ICqrsRuntime/ICqrsHandlerRegistry收敛新的边界方案,避免Core.Abstractions与Cqrs.Abstractions形成循环引用 - 再开始迁移
GFramework.Core/Cqrs/*、GFramework.Core.Cqrs.Extensions与协程扩展到GFramework.Cqrs - 迁移 runtime 后,再处理
GFramework.SourceGenerators与 meta package 的依赖图更新
阶段:CQRS 聚焦测试拆分与 CI 接入
- 建立
CQRS-REWRITE-RP-013恢复点 - 已新增
GFramework.Cqrs.Tests项目,并加入GFramework.sln - 以下 CQRS 聚焦测试已从
GFramework.Core.Tests迁移到GFramework.Cqrs.Tests:Cqrs/CqrsHandlerRegistrarTests.csCoroutine/CqrsCoroutineExtensionsTests.csMediator/MediatorAdvancedFeaturesTests.csMediator/MediatorArchitectureIntegrationTests.csMediator/MediatorComprehensiveTests.cs
GFramework.Cqrs.Tests/GlobalUsings.cs已补齐NUnit/Moq/System.*/Microsoft.Extensions.DependencyInjection等基础编译上下文GFramework.Cqrs.Tests/Logging/TestLogger.cs已新增,使新测试项目不再依赖GFramework.Core.Tests/Logging/LoggerTests.cs中的内嵌测试辅助GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs已改为依赖本地ContainerRegistrationFixtures.cs,避免继续编译期引用已迁出的 CQRS 测试类型GFramework/.github/workflows/ci.yml已新增dotnet test GFramework.Cqrs.Tests ...step,确保 PR CI 覆盖新测试项目
阶段:CQRS 聚焦测试拆分验证
dotnet build GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release- 结果:通过
dotnet test GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --no-build- 结果:通过
- 明细:
54个测试全部通过
dotnet build GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release- 结果:通过
dotnet test GFramework/GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build --filter "FullyQualifiedName~MicrosoftDiContainerTests|FullyQualifiedName~ArchitectureAdditionalCqrsHandlersTests|FullyQualifiedName~ArchitectureModulesBehaviorTests|FullyQualifiedName~MediatorCompatibilityDeprecationTests"- 结果:通过
- 明细:
44个测试全部通过
下一步
- 开始迁移
GFramework.Core/Cqrs/*、GFramework.Core.Cqrs.Extensions与相关协程扩展到GFramework.Cqrs - 在 runtime 迁移过程中保持
GFramework.Cqrs.Tests绿灯,持续作为 CQRS 模块的主回归项目 - 等 runtime 物理迁移完成后,再处理 source-generator 引用图与顶层 package/transitive 依赖整理
阶段:轻量 handler 上下文基类与 CoreGrid 兼容性收敛
- 建立
CQRS-REWRITE-RP-015恢复点 GFramework.Cqrs/Cqrs/CqrsContextAwareHandlerBase.cs已新增,作为只依赖IContextAware/IArchitectureContext的轻量 CQRS handler 基类- 各类
Abstract*Handler已改为继承该轻量基类,不再直接依赖GFramework.Core.Rule.ContextAwareBase - 新增
GFramework.Cqrs.Tests/Cqrs/AbstractCqrsHandlerContextTests.cs,回归锁定“未注入前 fail-fast、注入后可访问 Context、OnContextReady()仍生效”的行为 - 真实消费端验证阶段,
CoreGrid-Migration暴露了旧GFramework.Core.Abstractions.Cqrs*与旧GFramework.Core.Cqrs.Extensionsnamespace 已不再自动可用的问题 - 为了先恢复迁移验证链路,本轮先采取 consumer 侧最小修复:
scripts/GlobalUsings.cs已补齐新的GFramework.Cqrs.Abstractions.Cqrs*、GFramework.Cqrs.*与GFramework.Core.Cqrs.*导入scripts/cqrs/**中显式写死旧Unit/INotification/IQuery路径的文件已切到新的GFramework.Cqrs.Abstractions.Cqrs*GlobalInputController.cs、PauseMenu.cs、OptionsMenu.cs与两个组合 handler 已切到GFramework.Cqrs.Extensions.ContextAwareCqrs*Extensions
阶段:RP-015 验证
dotnet build CoreGrid-Migration/CoreGrid.sln- 结果:通过
- 备注:仅存在
CoreGrid-Migration既有 analyzer warnings,无新增 CQRS 编译错误
下一步
- 明确是否正式承诺旧
GFramework.Core.Abstractions.Cqrs*/GFramework.Core.Cqrs.Extensionspublic namespace 兼容 - 若不承诺兼容,补充迁移文档并继续沿
GFramework.Cqrs*命名空间推进 - 若承诺兼容,再单独设计兼容层,而不是让
CoreGrid-Migration这类消费端各自散落修补 - 无论兼容策略如何,下一阶段都应继续收敛
ICqrsRuntime -> IArchitectureContext与CqrsCoroutineExtensions -> TaskCoroutineExtensions的剩余边界
2026-04-16
阶段:review 收尾修正(partial reflection fallback 精确定向补扫)
- 建立
CQRS-REWRITE-RP-022恢复点 GFramework.Cqrs/CqrsReflectionFallbackAttribute.cs已扩展为可携带精确 fallback handler 类型名清单:- 生成器能够把“无法在生成代码中直接引用”的 concrete handler 记录为程序集级 metadata
- 当 metadata 为空时,runtime 仍保持旧版“整程序集补扫”的兼容语义
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已改为:- 对不可直接引用的 concrete handler 生成精确的 runtime type-name 清单
- 若消费端 runtime 仅支持旧版无参 fallback marker,则自动退回旧语义,避免破坏兼容
- 无 unsupported handler 时不再错误输出 fallback marker
GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs已改为:- 生成注册器命中后,优先读取
CqrsReflectionFallbackAttribute中的精确 type-name 清单 - 若清单存在,则按稳定顺序定向
Assembly.GetType(...)解析剩余 handlers,而不是重新GetTypes()扫描整个程序集 - 只有在旧 marker 或手写 marker 未提供清单时,才继续回退到整程序集扫描路径
- 生成注册器命中后,优先读取
GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs已新增/更新回归:- 锁定“partial fallback 通过精确 type-name 补扫”
- 断言该路径不会调用
Assembly.GetTypes()
GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs已新增/更新回归:- 锁定“私有嵌套 handler => 输出精确 type-name fallback marker”
- 锁定“旧版 runtime 仅支持无参 marker 时 => 生成器自动退回旧语义”
阶段:RP-022 验证
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
5个测试全部通过
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests"- 结果:通过
- 明细:
5个测试全部通过
下一步
- 继续扩大 generator 命中面,优先盘点仍会落到“旧 marker / 无精确清单”路径的实际场景
- 评估是否需要为手写/第三方程序集提供更正式的精确 fallback metadata 入口,而不是只依赖 generator 自动产出
- 在 handler 注册路径之外,继续评估 dispatch / invoker 链路可否进一步减少运行时反射
2026-04-16
阶段:review 收尾修正(手写/第三方程序集的精确 fallback metadata 入口)
- 建立
CQRS-REWRITE-RP-023恢复点 GFramework.Cqrs/CqrsReflectionFallbackAttribute.cs已扩展为同时支持:params string[] fallbackHandlerTypeNamesparams Type[] fallbackHandlerTypes- 无参兼容 marker
- 这使手写或第三方程序集在“有 generated registry,但仍需补少量 reflection-only handlers”时,可以直接声明可引用的 handler
Type,避免再走字符串名称回查。 GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs已改为按以下优先级处理 fallback metadata:- 先消费显式
Type集合 - 再消费字符串 type-name 清单
- 只有没有任何精确 metadata 时,才继续回退到整程序集
GetTypes()扫描
- 先消费显式
- registrar 对 direct
Typefallback 的程序集一致性校验已从对象引用比较收敛为稳定程序集键比较,避免代理/测试场景下把语义等价的程序集误判为不一致。 GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs已新增回归:- 锁定“direct
Typefallback 不触发Assembly.GetType()” - 锁定“direct
Typefallback 也不触发Assembly.GetTypes()”
- 锁定“direct
阶段:RP-023 验证
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests"- 结果:通过
- 明细:
6个测试全部通过
下一步
- handler 注册层的“手写 fallback 精确入口”已补齐,后续优先转向
CqrsDispatcher热路径 - 盘点
PublishAsync/SendAsync/CreateStream中每次分发都会发生的MakeGenericType/ service-type 构造,评估是否用稳定缓存进一步减少反射 - 若热路径缓存收益成立,再补一组聚焦
CqrsDispatcher的回归或性能守护测试
2026-04-16
阶段:review 收尾修正(dispatcher 热路径 service-type 缓存)
- 建立
CQRS-REWRITE-RP-024恢复点 GFramework.Cqrs/Internal/CqrsDispatcher.cs已新增三组热路径 service-type 缓存:NotificationHandlerServiceTypesRequestServiceTypesStreamHandlerServiceTypes
- 这些缓存把以下重复工作收敛为“首次构造一次,后续复用”:
PublishAsync(...)中typeof(INotificationHandler<>).MakeGenericType(...)SendAsync(...)中 request handler / pipeline behavior 的服务类型构造CreateStream(...)中 stream handler 的服务类型构造
- 现有 invoker delegate 缓存继续保留;这轮补的是容器 service lookup 前的泛型服务类型构造缓存,而不是替换已有 invoker cache。
GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs已新增回归:- 用唯一的 request / notification / stream 测试类型命中三条 dispatcher 路径
- 通过反射读取 dispatcher 内部缓存字典,锁定“首次分发新增一条缓存,后续同类型分发不再增长”
阶段:RP-024 验证
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsDispatcherCacheTests"- 结果:通过
- 明细:
7个测试全部通过
下一步
- 继续评估 request pipeline / invoker 路径是否还有值得继续缓存或收敛的动态构造
- 若收益有限,再回到 generator 命中面扩张与 legacy fallback 面积压缩
- 若后续要做更强性能守护,可考虑补一个更窄的 benchmark 或轻量性能回归,而不是只依赖功能性缓存测试
2026-04-16
阶段:review 收尾修正(dispatcher invoker method-definition 静态缓存与统一缓存回归)
- 建立
CQRS-REWRITE-RP-025恢复点 GFramework.Cqrs/Internal/CqrsDispatcher.cs已将以下泛型方法定义查找收敛为静态一次解析:InvokeRequestHandlerAsyncInvokeRequestPipelineAsyncInvokeNotificationHandlerAsyncInvokeStreamHandler
- 这样每种新消息类型首次命中 invoker cache 时,只剩
MakeGenericMethod(...) + CreateDelegate(...),不再重复执行GetMethod(...)查找。 GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs已扩展为同时覆盖:- request/no-pipeline 的
RequestInvokers - request/with-pipeline 的
RequestPipelineInvokers - notification 的
NotificationInvokers - stream 的
StreamInvokers - 以及对应的 service-type cache
- request/no-pipeline 的
- 测试通过显式注册
DispatcherPipelineCacheBehavior命中 pipeline 分支,避免当前缓存回归只覆盖无行为请求路径。
阶段:RP-025 验证
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsDispatcherCacheTests"- 结果:通过
- 明细:
7个测试全部通过
下一步
- dispatcher 侧基础低反射缓存已覆盖 service-type 与 invoker 两层,后续优先判断 pipeline delegate 链的每次分发构造是否仍值得继续收敛
- 若 pipeline 链构造收益不大,则回到 generator 命中面扩张与 legacy fallback 面积压缩
- 若需要进一步证明收益,可考虑增加更窄的性能守护而不是继续堆功能性反射缓存测试
2026-04-16
阶段:review 收尾修正(generated registry 内部定向反射注册隐藏 handler)
- 建立
CQRS-REWRITE-RP-026恢复点 GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已将“不可直接typeof(...)引用的 concrete handler”从程序集级 fallback marker 输出收敛为 generated registry 内部的定向反射注册:- 对可见 handler 仍保持
typeof(...)直注册路径 - 对私有/不可直接引用但仍可按元数据名从当前程序集重新定位的 handler,改为生成
Assembly.GetType(...)+GetInterfaces()的本地注册逻辑 - 这类场景不再额外要求 runtime registrar 读取
CqrsReflectionFallbackAttribute
- 对可见 handler 仍保持
- 生成器不再依赖 runtime 是否暴露
CqrsReflectionFallbackAttribute才决定是否产出 registry;隐藏 handler 已由生成代码自身覆盖,因此旧版“无 marker 就整程序集放弃生成”的分支已去除。 GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs已同步更新:- 私有嵌套 handler 快照改为断言 generated registry 自行调用
RegisterReflectedHandler(...) - 旧版无参 marker 合同场景改为断言“不再输出 legacy marker”
- 完全不存在 fallback marker 合同时,仍断言 generator 会继续产出 registry 并覆盖隐藏 handler
- 私有嵌套 handler 快照改为断言 generated registry 自行调用
阶段:RP-026 验证
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
5个测试全部通过
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-restore --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
5个测试全部通过
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsDispatcherCacheTests"- 结果:通过
- 明细:
7个测试全部通过
下一步
- 继续盘点 generator 仍未覆盖的 handler 形态,确认是否还存在必须依赖 runtime fallback metadata 的真实残余场景
- 若 generator 命中面已接近稳定,再回到 dispatcher pipeline delegate 链构造,判断是否值得继续做低反射/低分配收敛
- 若后续继续参考
Mediator,优先找“生成期已知、运行期只做常量时间绑定”的模式,而不是新增另一层宽反射补扫
2026-04-16
阶段:review 收尾修正(隐藏 implementation + 可见 handler interface 的直连接线)
- 建立
CQRS-REWRITE-RP-027恢复点 - 并行/本地盘点结论收敛:
CqrsDispatcher当前剩余开销主要是容器解析、pipeline 链重建与object装箱,不再是优先级最高的“反射缺口”- 因此本轮继续回到 generator 主线,而不是提前做 dispatcher 微优化
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已新增一条更窄的生成路径:- 当 handler implementation 不能被生成代码直接
typeof(...)引用,但 handler interface 仍可直接引用时 - generated registry 现在只会对 implementation 做一次
Assembly.GetType(...) - 随后直接以
typeof(IRequestHandler<...>)/typeof(INotificationHandler<...>)/typeof(IStreamRequestHandler<...>)完成注册 - 不再为这类场景额外生成
GetInterfaces()、IsSupportedHandlerInterface(...)与GetRuntimeTypeDisplayName(...)辅助逻辑
- 当 handler implementation 不能被生成代码直接
- 该调整把“隐藏 handler 的 generated registry 内部处理”继续从“implementation + interface 运行时发现”收敛为“implementation-only lookup + direct interface binding”
GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs已新增快照回归:- 锁定“隐藏 implementation + 可见 interface”场景只生成 implementation lookup + direct service registration
- 同时保持已有“隐藏 implementation + 隐藏 contract”场景仍走旧的本地
RegisterReflectedHandler(...)辅助路径
- 本轮实现过程中命中过一次生成器运行时异常:
- 原因是新增分支后
ImmutableArraybuilder 不再总是满容量,MoveToImmutable()触发Count equals Capacity约束 - 已收敛为
ToImmutable(),并同步修正 generated source 分支顺序与 helper 输出条件
- 原因是新增分支后
阶段:RP-027 验证
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
6个测试全部通过
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests"- 结果:通过
- 明细:
6个测试全部通过
下一步
- 继续盘点 generator 仍会落到
GetInterfaces()或 runtime fallback metadata 的 handler 形态,优先找还能压成“生成期已知 service type + implementation lookup”的场景 - 若 generator 侧残余面积已经很小,再回到 dispatcher,重点考虑是否真的值得为值类型响应装箱与 pipeline 链重建做更复杂的 typed-invoker 优化
- 若要继续参考
Mediator,优先寻找“生成期把接口/handler 绑定静态化”的模式,而不是继续扩大运行时辅助反射工具面
2026-04-16
阶段:review 收尾修正(隐藏 interface 的精确 service type 重建)
- 建立
CQRS-REWRITE-RP-028恢复点 - 在继续盘点 generator 命中面后,本轮把一类仍落到
GetInterfaces()的常见场景继续收窄:- implementation 不可直接
typeof(...) - handler interface 也不可直接
typeof(...) - 但 open generic contract 与闭包 type arguments 仍然能在生成期被精确表达
- implementation 不可直接
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已新增更窄的精确重建路径:- 对
IRequestHandler<,>/INotificationHandler<>/IStreamRequestHandler<,>记录 open generic contract - 对不可直引、但属于当前编译程序集的 type arguments 输出定向
Assembly.GetType(...) - 运行期通过
MakeGenericType(...)重建精确 service type - 再把该 service type 直接绑定到 implementation,而不是先
GetInterfaces()再做支持接口筛选
- 对
- 这一轮已覆盖的典型场景包括:
- 私有嵌套 request + 私有 handler + 可见 response
- 可见 implementation + 隐藏消息类型
- 隐藏 implementation + 隐藏消息类型
- 为避免误把“当前仍无法精确表达的 type 形态”静默漏掉,生成器仍保留旧的本地回退辅助分支:
- 当闭包 type arguments 含有当前 helper 还无法精确重建的形态(本轮用“隐藏元素类型数组”做回归)时
- 仍会退回
RegisterReflectedHandler(...)+GetInterfaces()的安全路径
- 本轮顺手修复了两处实现细节问题:
ImmutableArraybuilder 在分支化后不再总是满容量,MoveToImmutable()已收敛为ToImmutable()- open generic contract 的生成文本已从
IRequestHandler<TRequest, TResponse>修正为合法的IRequestHandler<,>形式
阶段:RP-028 验证
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
7个测试全部通过
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests"- 结果:通过
- 明细:
6个测试全部通过
下一步
- 继续评估
RuntimeTypeReference是否可以递归覆盖数组/更复杂闭包类型,进一步缩小仍需GetInterfaces()的残余场景 - 若 generator 侧只剩极少数复杂形态,再回到 dispatcher,重新判断 typed-invoker 去装箱优化是否值得进入实现阶段
- 若后续继续参考
Mediator,优先找“生成器输出精确 closed service type,运行期只负责常量时间绑定”的对应模式
2026-04-16
阶段:review 收尾修正(递归 generic type reconstruction)
- 建立
CQRS-REWRITE-RP-029恢复点 - 继续按“优先参考 Mediator 的生成期定结构思路,而不是新增运行时宽反射”推进 generator 主线:
- 本轮没有新增任何新的 runtime 接口发现分支
- 而是把
RuntimeTypeReference从“直接类型 + 数组”扩成递归可组合结构
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs现支持递归重建:- 直接可引用类型
- 当前编译程序集内的隐藏类型定向
Assembly.GetType(...) - 数组类型的
MakeArrayType(...) - 构造泛型类型的
MakeGenericType(...)
- 因此以下场景已能直接生成 closed service type,而不再退回
GetInterfaces():HiddenResponse[]List<HiddenResponse>这类“可引用泛型定义 + 隐藏实参”HiddenEnvelope<string>这类“隐藏泛型定义 + 可重建实参”
- 实现过程中额外收敛了两处细节:
- open generic definition 的直接引用改为通过
ConstructUnboundGenericType()输出合法typeof(List<>)/typeof(IRequestHandler<,>)形式 TryCreateRuntimeTypeReference(...)的失败分支改为显式null输出,避免新的递归结构继续引入可空警告
- open generic definition 的直接引用改为通过
GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs已新增/更新快照回归:- 隐藏数组响应场景现在锁定为
MakeArrayType()路径 - 新增“隐藏泛型定义 + 常量实参”场景,锁定递归
MakeGenericType()输出
- 隐藏数组响应场景现在锁定为
阶段:RP-029 验证
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
8个测试全部通过
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests"- 结果:通过
- 明细:
6个测试全部通过
下一步
- 继续盘点仍必须落回
GetInterfaces()的残余类型形态,优先判断是否只剩极少数低价值边角分支 - 若 generator 命中面已足够高,再回到 dispatcher,评估 typed-invoker 去装箱是否值得作为下一条独立优化线
- 若继续参考
Mediator,优先找“生成器直接输出 closed contract 表”的更强静态化模式,而不是继续给 runtime 补更多推断能力
2026-04-16
阶段:review 收尾修正(dispatcher typed invoker cache 去装箱)
- 建立
CQRS-REWRITE-RP-030恢复点 - 在完成
RuntimeTypeReference递归扩展后,本轮先对 dispatcher 做一轮低风险热路径优化:- 重新盘点后确认,当前 C# 可编译的常见 handler interface 形态里,generator 剩余
GetInterfaces()回退已接近低价值尾部 - 因此本轮不再继续堆新的 runtime 类型推断分支,而是转回 dispatcher,落实此前待定的 typed-invoker 去装箱优化
- 重新盘点后确认,当前 C# 可编译的常见 handler interface 形态里,generator 剩余
GFramework.Cqrs/Internal/CqrsDispatcher.cs已将 request 两条调用路径改为按TResponse分层的强类型委托缓存:RequestInvokerCache<TResponse>负责无 pipeline 的 request handler 调用缓存RequestPipelineInvokerCache<TResponse>负责带 pipeline 的 request 调用缓存- 缓存键从
(RequestType, ResponseType)收敛为当前TResponse层内的RequestType InvokeRequestHandlerAsync<TRequest, TResponse>(...)与InvokeRequestPipelineAsync<TRequest, TResponse>(...)现直接返回ValueTask<TResponse>,不再通过ValueTask<object?>桥接 request 结果
- 这一轮的实现约束是:
- 不改变 notification / stream 现有缓存结构
- 不改变公开 runtime 契约与 observable dispatch 语义
- 只减少 request 热路径里 value-type 响应的装箱/拆箱成本
GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs已同步更新:- 原有“一次建缓存,多次复用”的 service-type / invoker 回归已适配新的泛型嵌套缓存结构
- 新增
Dispatcher_Should_Cache_Request_Invokers_Per_Response_Type(),锁定int与string响应会分别命中各自的 request invoker cache SetUp()现在会显式清空 dispatcher 静态缓存,避免跨测试共享进程级状态导致缓存计数断言漂移
阶段:RP-030 验证
dotnet test GFramework/GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsDispatcherCacheTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
47个测试全部通过
下一步
- 回到 generator 主线,确认当前剩余
GetInterfaces()本地回退是否只服务于极少数几乎不可达的边角形态 - 若该尾部分支确实价值有限,优先评估是否直接推进“生成器输出 closed contract 表”的更强静态化方案
- 若后续还要继续做 dispatcher 微优化,再单独评估 notification / stream 路径是否存在同等级别、且有明确收益的可观测热点
2026-04-16
阶段:review 收尾修正(generator mixed registration composition)
- 建立
CQRS-REWRITE-RP-031恢复点 - 在回到 generator 主线后,确认当前更值得优先修正的问题不是继续扩
RuntimeTypeReference,而是生成器输出粒度过粗:TransformHandlerCandidate(...)已能把同一 implementation 上的不同 handler interface 分流到 direct / reflected-implementation / precise-reflected 三条路径- 但原
GenerateSource(...)仍按 implementation 做互斥分支选择 - 因此一旦同一个 implementation 同时命中多种路径,后面的分支会吞掉前面本已可静态绑定的注册
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已将该逻辑收敛为“按 handler interface 组合输出”:- direct-only implementation 仍保持原有直注册输出
- 只要同一 implementation 上存在 reflected-implementation 或 precise-reflected 注册,生成器现在会先把三类注册步骤合并到一个有序列表
- 合并后的步骤继续按
HandlerInterfaceLogName做稳定排序,避免因为内部 bucket 化而偏离原先按接口名排序的生成顺序 - 对可见 implementation,会复用
typeof(ImplementationType)作为统一 implementation 变量 - 对隐藏 implementation,则继续只做一次
Assembly.GetType(...),再在同一块里完成可见接口直绑与精确MakeGenericType(...)注册
- 这一轮的收敛点是:
- 不新增新的 runtime 宽反射分支
- 也不改变“真正 unresolved 形态仍可整实现退回
RegisterReflectedHandler(...)”的安全边界 - 只修正“本可静态绑定的接口被同实现上的另一条更窄路径连带降级”的生成器粒度问题
GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs已新增两条快照回归:Generates_Mixed_Direct_And_Precise_Registrations_For_Same_Implementation()Generates_Mixed_Reflected_Implementation_And_Precise_Registrations_For_Same_Implementation()- 这两条测试分别锁定“可见 implementation”与“隐藏 implementation”上的混合路径输出,防止后续再退回 implementation 级互斥分支
阶段:RP-031 验证
dotnet test GFramework/GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
10个测试全部通过
下一步
- 继续盘点当前剩余必须整实现退回
RegisterReflectedHandler(...)的类型形态,确认是否真的只剩低价值尾部分支 - 若该判断成立,下一步优先评估“生成器直接输出 closed contract 表”的静态化方案,而不是继续给 runtime 增加推断辅助
- 若要继续参考
Mediator,重点比较其生成代码是否已经把“多接口 implementation 的 contract 表”静态化到比当前更细的粒度
2026-04-16
阶段:review 收尾修正(partial full-fallback 与 generated-registry accessibility)
- 建立
CQRS-REWRITE-RP-032恢复点 - 在继续盘点 generator 剩余 full-fallback 后,确认这一轮真正需要同时收敛的是两件事:
- 先前“是否能在生成注册器里直接
typeof(...)某个类型”的判断只看声明可见性,无法区分“当前语义上下文可见”和“生成注册器顶层上下文可直接书写” - 即使某个 implementation 上只剩一条未知接口,旧逻辑也会直接清空此前已收集注册,整实现退回
GetInterfaces()发现
- 先前“是否能在生成注册器里直接
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已将可访问性判断改为:Compilation.IsSymbolAccessibleWithin(symbol, compilation.Assembly, null)- 这使生成器现在按“顶层 generated registry 所在上下文”判断能否直接引用类型,而不再把
protected internal之类的声明可见类型粗暴视为一定可直引 - 同程序集私有/隐藏类型仍继续走 metadata-name lookup,不影响当前已落地的精确定向注册路径
TransformHandlerCandidate(...)已不再在遇到单个未知接口时直接return丢掉已收集注册:- 改为设置
RequiresRuntimeInterfaceDiscovery = true - 继续把同实现上仍可确定的 direct / reflected-implementation / precise-reflected 注册收集完整
- 改为设置
- 生成代码模型已新增“局部补洞”路径:
ImplementationRegistrationSpec现携带RequiresRuntimeInterfaceDiscovery- 当同一 implementation 仍残留未知接口时,生成代码会先建立
knownServiceTypes - 先完成所有已知 service type 的注册,并把这些 service type 加入
knownServiceTypes - 再调用
RegisterRemainingReflectedHandlerInterfaces(...),只对GetInterfaces()中尚未出现在knownServiceTypes的 supported handler interface 做补注册
- 这一轮的结果是:
- full-fallback 仍保留为最后的安全边界
- 但已从“整实现吞掉已知注册”收敛为“implementation 内部局部补洞”
- 同时修正了外部
protected internal嵌套类型这类边界下,旧判断可能误生成不可编译typeof(...)的风险
- 为了覆盖这个真实边界,测试基础设施也做了最小扩展:
GFramework.SourceGenerators.Tests/Core/GeneratorTest.cs新增带AdditionalReferences的重载MetadataReferenceTestBuilder.cs已新增,可把内存源码编成元数据引用
阶段:RP-032 验证
dotnet test GFramework/GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
11个测试全部通过
下一步
- 继续盘点当前仍必须依赖
RegisterRemainingReflectedHandlerInterfaces(...)的真实类型形态,确认是否已经收敛到少量低价值边角路径 - 若该判断成立,下一步优先评估“生成器直接输出 closed contract 表”的更强静态化方案
- 若继续参考
Mediator,重点比较其对“多接口 implementation + 少量未知 contract”的生成期建模是否还比当前更细
2026-04-16
阶段:review 小修(RP-033)
- 接收四条 follow-up 建议后,先确认都命中当前仓库:
- dispatcher 缓存清理遗漏了
RequestPipelineInvokerCache<string> - generator 可访问性判断默认分支缺少显式假设说明
MetadataReferenceTestBuilder每次都会重建运行时元数据引用集合RunGenerator(...)的编译错误断言消息上下文偏少
- dispatcher 缓存清理遗漏了
- 已完成对应实现:
- 在
ClearDispatcherCaches()中补齐stringpipeline invoker cache 清理 - 为
CanReferenceFromGeneratedRegistry(...)默认分支补上“暂按可引用处理,后续可收紧”的注释 - 用
Lazy<ImmutableArray<MetadataReference>>缓存TRUSTED_PLATFORM_ASSEMBLIES解析结果 - 让生成器测试失败消息输出完整
Diagnostic.ToString()列表
- 在
- 本轮属于 review follow-up 小修,没有改动公开 API 或运行时主路径语义;核心目标是减少测试间静态状态泄漏风险,并提升 source-generator 测试的调试效率
- 定向验证已完成:
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过,
11个测试全部通过
- 结果:通过,
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsDispatcherCacheTests"- 结果:通过,
2个测试全部通过
- 结果:通过,
下一步
- 回到 generator 主线,继续盘点当前仍必须依赖
RegisterRemainingReflectedHandlerInterfaces(...)的真实类型形态 - 若该尾部分支价值确实很低,优先评估“生成器直接输出 closed contract 表”的更强静态化方案
2026-04-16
阶段:review 小修(RP-034)
- 建立
CQRS-REWRITE-RP-034恢复点 - 为了把“继续盘点 residual runtime interface discovery 形态”从人工读代码改成可观察输出,
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs现在会在每个仍需RegisterRemainingReflectedHandlerInterfaces(...)的 implementation 注册块前,生成显式注释:// Remaining runtime interface discovery target: ... - 注释内容直接复用对应 closed handler interface 的日志显示名,因此不会引入额外 runtime 逻辑,也能和现有 debug 日志口径保持一致
GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs已补齐断言,锁定当前已知尾部分支案例IRequestHandler<Dep.VisibilityScope.ProtectedRequest, Dep.VisibilityScope.ProtectedResponse[]>会出现在生成注释中,避免后续又退回“只知道走了 fallback,但不知道具体是哪条 contract”的状态- 本轮没有改动公开 API,也没有扩大 runtime 反射面;目标仅是为下一步 closed-contract 评估提供稳定盘点入口
- 补充验证已完成:
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过,
11个测试全部通过
- 结果:通过,
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Ioc.MicrosoftDiContainerTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureAdditionalCqrsHandlersTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.RegistryInitializationHookBaseTests"- 结果:通过,
52个测试全部通过
- 结果:通过,
下一步
- 基于生成注释清单,继续归类当前 residual contract 是否都集中在“外部程序集不可直引类型”这类低频边角
- 若判断成立,下一步直接设计 closed-contract 表最小原型,优先验证能否覆盖外部程序集
protected internal嵌套类型,而不是继续扩大GetInterfaces()补洞
2026-04-16
阶段:主线推进(RP-035)
- 建立
CQRS-REWRITE-RP-035恢复点 - 已将原
GFramework.SourceGenerators继续按目标模块拆分为:GFramework.Core.SourceGeneratorsGFramework.Core.SourceGenerators.AbstractionsGFramework.Cqrs.SourceGeneratorsGFramework.Game.SourceGenerators
GFramework.SourceGenerators.Tests已改为同时引用新的Core/Cqrs/Game生成器项目;GFramework.Core.Tests与GFramework.Game.Tests也已切到新的本地 analyzer 引用链, 其中Game.Tests额外改为导入GFramework.Game.SourceGenerators.targetsGFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已继续收敛 residual tail:RuntimeTypeReferenceSpec现可表达“外部程序集 + metadata name”的定向 lookup- 对外部程序集中的不可直引
protected nested类型,不再只能退回RegisterRemainingReflectedHandlerInterfaces(...) - 当前已验证
IRequestHandler<Dep.VisibilityScope.ProtectedRequest, Dep.VisibilityScope.ProtectedResponse[]>这类案例会生成ResolveReferencedAssemblyType(...)精确查找,而不是保留 residual 注释 +GetInterfaces()补洞
- 已删除不再保留的公开
Mediator兼容层:RegisterMediatorBehavior<TBehavior>()ContextAwareMediatorExtensionsContextAwareMediatorCommandExtensionsContextAwareMediatorQueryExtensionsMediatorCoroutineExtensions
- 相关兼容测试
MediatorCompatibilityDeprecationTests已删除;ArchitectureModulesBehaviorTests与RegistryInitializationHookBaseTests已同步移除对旧别名的断言/测试替身实现 - 文档已做最小同步:
docs/zh-CN/core/cqrs.md不再声明旧Mediator兼容别名CLAUDE.md已改为统一使用Cqrs命名入口
阶段:RP-035 验证
dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release- 结果:通过
dotnet build GFramework.Core.SourceGenerators/GFramework.Core.SourceGenerators.csproj -c Release- 结果:通过
dotnet build GFramework.Game.SourceGenerators/GFramework.Game.SourceGenerators.csproj -c Release- 结果:通过
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
11个测试全部通过
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureModulesBehaviorTests|FullyQualifiedName~GFramework.Core.Tests.Architectures.RegistryInitializationHookBaseTests"- 结果:通过
- 明细:
8个测试全部通过
dotnet build GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release- 结果:通过
- 备注:仍有一条既有
GF_ContextRegistration_003warning,属于测试项目里的静态注册分析提示,不是本轮拆分或 CQRS 主线回归
下一步
- 继续盘点当前 residual
RegisterRemainingReflectedHandlerInterfaces(...)是否还剩下“外部程序集定向 lookup”无法覆盖的真实类型形态 - 若只剩极少数低价值边角,直接评估 closed-contract 表最小原型,优先彻底消掉 generator 里的 implementation 级
GetInterfaces()尾分支 - 视需要再决定是否把现仍保留旧 namespace 的 source-generator abstractions/public docs 一并统一改名到
GFramework.Core.SourceGenerators*
2026-04-17
阶段:主线推进(RP-036)
- 建立
CQRS-REWRITE-RP-036恢复点 GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs已删除 generated registry 内部的 implementation 级GetInterfaces()尾分支:- 不再生成
RegisterRemainingReflectedHandlerInterfaces(...) - 不再生成
knownServiceTypes/Remaining runtime interface discovery target注释 /GetRuntimeTypeDisplayName(...)等仅服务于该尾分支的辅助代码 - 当前合法 C# closed handler contract 统一收敛到 direct / reflected-implementation / precise-reflected 三类注册路径
- 不再生成
- 为保持未来未知 Roslyn 类型形态下的保守正确性,生成器现改为:
- 若仍有无法编码进
RuntimeTypeReferenceSpec的 handler contract,则保留已知静态注册 - 同时通过程序集级
CqrsReflectionFallbackAttribute对具体 handler implementation 输出 targeted fallback metadata - 若当前 runtime 合同不提供该 marker,则直接放弃生成 registry,避免静默漏注册
- 若仍有无法编码进
GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs已为多程序集protected internal嵌套类型场景补齐显式断言:- 锁定不会重新生成
RegisterRemainingReflectedHandlerInterfaces(...) - 锁定不会重新出现
Remaining runtime interface discovery target注释 - 继续保持
ResolveReferencedAssemblyType(...)精确 lookup 输出
- 锁定不会重新生成
阶段:RP-036 验证
dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.SourceGenerators.Tests.Cqrs.CqrsHandlerRegistryGeneratorTests"- 结果:通过
- 明细:
11个测试全部通过
下一步
- 继续收敛 CQRS runtime 热路径里剩余的反射绑定点,优先盘点 dispatcher / registrar 是否还有可转成静态缓存或强类型委托的分支
- 视需要补做 source-generator 命名空间 / 文档收口,决定是否把仍残留旧
GFramework.SourceGenerators*表述的公开文档一并统一到新的模块名
2026-04-17
阶段:主线推进(RP-037)
- 建立
CQRS-REWRITE-RP-037恢复点 GFramework.Cqrs/Internal/CqrsDispatcher.cs已继续收敛 dispatcher 热路径里的首次反射绑定与重复缓存命中:- notification 路径由分散的
NotificationHandlerServiceTypes + NotificationInvokers合并为NotificationDispatchBindings - stream 路径由分散的
StreamHandlerServiceTypes + StreamInvokers合并为StreamDispatchBindings - request 路径由
RequestServiceTypes + RequestInvokerCache<TResponse> + RequestPipelineInvokerCache<TResponse>收敛为RequestDispatchBindingCache<TResponse>
- notification 路径由分散的
- 新的 dispatch binding 会把服务类型与强类型 invoker 委托绑定到同一缓存项:
- 首次命中仍只做一次必要的
MakeGenericType(...)/MakeGenericMethod(...)/CreateDelegate(...) - 后续
SendAsync(...)/PublishAsync(...)/CreateStream(...)会减少热路径上的重复字典查询 - request 绑定继续按
TResponse分层,不回退到object结果桥接
- 首次命中仍只做一次必要的
GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherCacheTests.cs已同步更新:- 断言从旧的 service-type / invoker 分散缓存切换为新的 dispatch binding 缓存结构
- 继续锁定 request/no-pipeline、request/with-pipeline、notification、stream 四条路径都是“一次建绑定,多次复用”
- 继续锁定 request 绑定按
int/string等不同响应类型分层缓存
阶段:RP-037 验证
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsDispatcherCacheTests"- 结果:通过
- 明细:
2个测试全部通过
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --no-restore --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsDispatcherCacheTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
47个测试全部通过
下一步
- 继续盘点
CqrsHandlerRegistrar初始化路径里剩余的 attribute 读取、registry 实例化与 fallback metadata 解析反射,评估是否值得再做进程级静态缓存 - 若 registrar 冷路径收益有限,再回到 source-generator 命名空间 / 文档收口,把仍残留旧
GFramework.SourceGenerators*表述的公开文档统一到新模块名
2026-04-17
阶段:主线推进(RP-038)
- 建立
CQRS-REWRITE-RP-038恢复点 GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs已把 registrar 冷路径里重复出现的程序集反射前置解析收敛为进程级缓存:AssemblyMetadataCache复用 generated registry attribute 与 reflection fallback metadata 的分析结果RegistryActivationMetadataCache复用 registry 类型是否实现ICqrsHandlerRegistry、是否抽象、是否存在可用无参构造等激活分析LoadableTypesCache复用未命中 generated registry 时的GetTypes()/ReflectionTypeLoadException恢复结果
- 为避免
Assembly在 mock/proxy 场景下的自定义相等语义干扰缓存命中,上述程序集级缓存统一改为引用相等键 - 运行时行为保持不变:
- generated registry 仍优先于整程序集扫描
- fallback metadata 仍先消费显式
Type,再消费 type-name lookup - 没有 generated registry 时仍按稳定排序扫描可加载 handlers
GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs已新增两条缓存回归:- 同一程序集对象跨两个容器重复接入时,程序集级 registry/fallback metadata 与
Assembly.GetType(...)只解析一次 - 同一程序集对象在 full-scan 路径下跨两个容器重复接入时,
GetTypes()只执行一次,且两个容器都能复用首次恢复出的可加载 handler 集合
- 同一程序集对象跨两个容器重复接入时,程序集级 registry/fallback metadata 与
阶段:RP-038 验证
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests"- 结果:通过
- 明细:
8个测试全部通过
dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --no-restore --filter "FullyQualifiedName~GFramework.Cqrs.Tests.Cqrs.CqrsHandlerRegistrarTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorComprehensiveTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorArchitectureIntegrationTests|FullyQualifiedName~GFramework.Cqrs.Tests.Mediator.MediatorAdvancedFeaturesTests"- 结果:通过
- 明细:
53个测试全部通过
dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~GFramework.Core.Tests.Architectures.ArchitectureAdditionalCqrsHandlersTests"- 结果:通过
- 明细:
2个测试全部通过
下一步
- 评估 registrar 冷路径里剩余的 registry 实例创建本身是否值得继续压缩;若收益有限,主线可转回 source-generator 命名空间 / 文档收口
- 盘点公开文档和说明文件中仍残留的旧
GFramework.SourceGenerators*/ 旧 CQRS 表述,决定是否在下一恢复点统一收口
2026-04-17
阶段:主线推进(RP-039)
- 建立
CQRS-REWRITE-RP-039恢复点 - 结合 RP-038 后的冷路径现状,判断 registrar 继续下压的边际收益已经明显变小,主线转向公开入口文档收口
- 已完成以下公开入口文档的最小同步:
README.mdCLAUDE.mddocs/zh-CN/core/cqrs.mddocs/zh-CN/source-generators/index.md
- 本轮收口重点:
- 根 README 的模块表、仓库结构与包选择说明已补入
GFramework.Cqrs/GFramework.Cqrs.Abstractions - 根 README 与
CLAUDE.md已从旧的单体GFramework.SourceGenerators模块表述切到当前的Core/Game/Godot/Cqrs SourceGenerators家族 docs/zh-CN/core/cqrs.md的代码示例命名空间已切到当前GFramework.Cqrs*路径,不再继续展示旧GFramework.Core.CQRS*/GFramework.Core.Abstractions.CQRS*docs/zh-CN/core/cqrs.md的迁移说明已收敛为“直接使用RegisterCqrsPipelineBehavior<TBehavior>()”,不再把已删除的RegisterMediatorBehavior<TBehavior>()写成仍可替换的并存入口docs/zh-CN/source-generators/index.md已从“单一GFramework.SourceGenerators包”口径改写为“按模块拆分的 Source Generators 家族”口径,同时保留“旧聚合包不存在”的说明
- 根 README 的模块表、仓库结构与包选择说明已补入
- 期间尝试把
README.md/CLAUDE.md分派给 worker 并行处理,但 subagent 上游接口报错,最终由主 agent 本地完成,不影响结果正确性
阶段:RP-039 验证
- 对以下文件执行定向全文扫描,确认已不存在旧公开入口表述:
README.mdCLAUDE.mddocs/zh-CN/core/cqrs.mddocs/zh-CN/source-generators/index.md
- 扫描结果:
- 已无旧
GFramework.Core.CQRS*/GFramework.Core.Abstractions.CQRS*示例命名空间残留 - 已无旧
GFramework.SourceGenerators聚合模块图或聚合包定位残留 - 保留的旧名仅存在于迁移说明和“不存在旧聚合包”的显式说明中,属于有意保留
- 已无旧
下一步
- 若继续文档主线,扩大扫描范围到
docs/zh-CN/**与根 README 之外的说明文件,逐步清理更多历史GFramework.SourceGenerators*/Mediator表述 - 若回到实现主线,可再次评估 registrar 冷路径是否还值得继续压缩,重点看 registry 实例创建本身的收益是否足以覆盖复杂度
2026-04-18
阶段:规则与参考源收口(RP-040)
- 建立
CQRS-REWRITE-RP-040恢复点 - 已确认用户将当前 CQRS 主线对照用的
Mediator源码放入仓库内ai-libs/Mediator AGENTS.md已新增仓库规则:ai-libs/为第三方源码参考区ai-libs/**默认只读,不允许作为常规实现改动目标- 后续计划、trace、评审与设计说明引用第三方实现时,应优先写明仓库内路径
- CQRS 迁移跟踪文档已同步把“参考 Mediator 成熟实现”的当前执行语义收口为“优先参考
ai-libs/Mediator”
验证
dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release- 结果:通过
- 备注:存在既有
MA0051与MA0158analyzer warnings,无新增构建错误
rg -n "ai-libs/|ai-libs/Mediator|只读|第三方源码参考区|第三方项目源码副本" AGENTS.md ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md- 结果:通过
- 备注:三处文档都已命中
ai-libs只读规则与ai-libs/Mediator参考路径
下一步
- 继续推进 CQRS 子系统增强时,把
ai-libs/Mediator作为唯一仓库内参考源使用 - 若后续需要变更
ai-libs/Mediator内容,单独建“第三方快照同步”任务,不与 GFramework 实现改动共用一个提交
2026-04-18
阶段:文档主线推进(RP-041)
- 建立
CQRS-REWRITE-RP-041恢复点 - 结合
feat/cqrs-optimization当前主线与 RP-039 的文档收口结果,继续扩大扫描范围到docs/zh-CN/** - 盘点确认:
- 旧公开示例主要残留在大量文档代码块中的
using GFramework.SourceGenerators.Abstractions.*; - 当前真实公开命名空间已经是
GFramework.Core.SourceGenerators.Abstractions.* GFramework.SourceGenerators.Common等命名仍对应仓库内部项目,不应作为本轮批量替换目标
- 旧公开示例主要残留在大量文档代码块中的
- 已批量把文档示例命名空间收口到当前公开路径,并额外手工修正三处叙述性旧口径:
docs/zh-CN/source-generators/logging-generator.mddocs/zh-CN/source-generators/context-get-generator.mddocs/zh-CN/api-reference/index.md
验证
- 执行:
rg -n "using GFramework\\.SourceGenerators\\.Abstractions\\.|### GFramework\\.SourceGenerators|GFramework\\.SourceGenerators 自动生成|GFramework\.SourceGenerators现在还会分析" docs/zh-CN
- 结果:
- 通过
docs/zh-CN/**已不再残留上述旧公开命名空间与旧聚合说明
下一步
- 若继续文档主线,优先再扫
docs/zh-CN/api-reference与教程入口页,补齐仍过时的 API / 命名空间表述 - 若切回实现主线,重新盘点
GFramework.Cqrs当前剩余的反射绑定点,并只选择收益明确的优化项推进
2026-04-19
阶段:PR review 技能接入与 PR-253 follow-up(RP-042)
- 建立
CQRS-REWRITE-RP-042恢复点 - 新增项目级 skill
.codex/skills/gframework-pr-review/:- 暗号为
$gframework-pr-review - 使用 Windows Git 解析当前分支,并通过 GitHub PR API 定位当前分支对应的 PR
- 通过 GitHub issue comments / reviews / review comments API 提取
Summary by CodeRabbit、最新 head commit review threads、Failed checks与 CTRF 测试结果 - 不再把重型 PR HTML 页面作为主数据源,只在调试或兼容场景下保留为兜底思路
- 不依赖
ghCLI,也不要求登录态;脚本会显式绕过当前 shell 中失效的代理变量
- 暗号为
- 用新脚本验证了 PR
#253的当前状态:- latest head commit review threads 已可直接从 API 提取;在远端最新提交未更新前,当前仍显示 4 条 open
threads,其中 2 条落在
fetch_current_pr_review.py、2 条落在ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md - PR 页面当前无
Failed Tests,CTRF 测试报告显示2103 passed / 0 failed Failed checks当前可稳定提取到Docstring Coveragewarning;该项属于 PR 级文档注释覆盖率问题,不是 FPR skill 解析链路故障
- latest head commit review threads 已可直接从 API 提取;在远端最新提交未更新前,当前仍显示 4 条 open
threads,其中 2 条落在
- 已按 PR
#253的公开建议完成本地修正:gframework-boot的恢复 heuristics 改为“先检索ai-plan/,再判定resume或recovery”AGENTS.md将ai-libs/**观察写入 active plan/trace 的要求收窄到“多步/复杂任务或已有 active tracking document”Godot模板与IController文档注释中的旧GFramework.SourceGenerators.Abstractions.Rule引用已收口到GFramework.Core.SourceGenerators.Abstractions.Rule
验证
python3 - <<'PY' ... ast.parse(...) ... PY- 结果:通过
- 备注:
fetch_current_pr_review.py语法正确,且避免了只读文件系统下写__pycache__的问题
python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 253- 结果:通过
- 备注:成功通过 API-first 路径解析当前 PR 元数据、latest head commit review threads、
Docstring Coveragewarning 和 CTRF 测试报告
python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --branch feat/cqrs-optimization- 结果:通过
- 备注:验证 branch -> PR 解析也已摆脱 HTML 搜索
dotnet build GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj -c Release- 结果:通过
- 备注:
GFramework.Cqrs.Abstractions与GFramework.Core.Abstractions均成功构建,0 warning / 0 error
rg -n "GFramework\\.SourceGenerators\\.Abstractions\\.Rule" Godot GFramework.Core.Abstractions docs/zh-CN -g '*.cs' -g '*.md'- 结果:通过
- 备注:本轮目标范围内已无旧
Rule命名空间残留
下一步
- 若继续沿用当前 PR 驱动修复流程,可直接用
$gframework-pr-review复查后续 PR 的 CodeRabbit 评论与测试状态 - 若要验证本轮本地修正已经消除远端 latest head review threads,需要在提交并推送当前分支后重新执行
$gframework-pr-review
2026-04-19
阶段:PR review 复核与 FPR 输出澄清(RP-043)
- 建立
CQRS-REWRITE-RP-043恢复点 - 复核 PR
#253时确认:ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md的“下次恢复建议”仍把主线写成Phase 7- 这与 tracking 顶部当前阶段
Phase 8不一致,恢复时会造成执行顺序歧义
- 进一步检查
$gframework-pr-review脚本后确认:- 该评论并非“未覆盖”,而是已出现在 latest head commit 的 open review threads 中
- 我先前误把评论正文里可见的
Addressed in commit ...文案当成了“已经本地验证修复” - 实际脚本只会在 CodeRabbit thread 带有隐藏 marker
<!-- <review_comment_addressed> -->时才将状态归类为addressed
- 已据此完成两项修正:
- 将 tracking 中的恢复主线更新为
Phase 8(当前主线) - 调整
fetch_current_pr_review.py输出:当 open thread 里出现Addressed in commit ...文案但线程并未真正 closed/addressed 时,显式提示“仍需本地验证,不要视为已解决”
- 将 tracking 中的恢复主线更新为
验证
sed -n '469,475p' ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md- 结果:通过
- 备注:恢复建议已切到
Phase 8(当前主线)
python3 -m py_compile .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py- 结果:通过
- 备注:脚本语法正确
下一步
- 推送当前分支后重新执行
$gframework-pr-review,确认 PR#253的 latest head review threads 是否已收敛 - 若后续仍保留 CodeRabbit 的
Addressed in commit ...文案但 thread 继续 open,优先以 latest thread 状态和本地文件事实为准,不再按文案字面判定