GFramework/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
gewuyou e746fede7e chore(cqrs-rewrite): 修复PR349评审遗留问题
- 更新 stream benchmark 的 XML 返回值契约

- 修复通知发布器缓存回归测试的误导性安全网

- 同步 ai-plan 中的当前 PR 锚点与验证结果
2026-05-12 11:15:13 +08:00

206 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
Copyright (c) 2025-2026 GeWuYou
SPDX-License-Identifier: Apache-2.0
-->
# CQRS 重写迁移追踪
## 2026-05-12
### 阶段PR #349 latest-head review 收口CQRS-REWRITE-RP-136
- 重新执行 `$gframework-pr-review`,按 GitHub 当前分支状态确认 `feat/cqrs-optimization``2026-05-12` 对应的是 `PR #349`,不再沿用 active tracking 中的 `PR #348` 锚点。
- 本轮 latest-head open AI thread 复核结论:
- `StreamPipelineBenchmarks``Stream_Baseline``Stream_GFrameworkCqrs``Stream_MediatR` 缺少 `<returns>` XML 契约,接受修复
- `StreamingBenchmarks.Stream_Mediator` 缺少 `<returns>` XML 契约,接受修复
- `CqrsNotificationPublisherTests` 的 fallback publisher 缓存回归测试用“第二次解析返回另一个 publisher”充当安全网和断言消息表达不一致接受收口为“首次后任何再次解析都直接失败”
- active tracking / trace 的当前 PR 锚点与下一步入口仍停留在 `PR #348`,接受同步到 `PR #349`
- 本轮主线程实施:
- `StreamPipelineBenchmarks`
- 为 3 个公开 benchmark 方法补齐 `<returns>` XML 文档
- `StreamingBenchmarks`
-`Stream_Mediator()` 补齐 `<returns>` XML 文档
- `CqrsNotificationPublisherTests`
- 把 fallback publisher 缓存回归测试改为“首次返回空数组,后续任何再次解析立即抛 `AssertionException`”,避免测试安全网与失败消息自相矛盾
- `ai-plan/public/cqrs-rewrite/**`
- 将 active tracking / trace 的当前 PR 锚点与下一步入口同步到 `PR #349`
- 本轮权威验证:
- `dotnet build GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsNotificationPublisherTests"`
- 结果:通过,`Passed: 9, Failed: 0`
- `python3 scripts/license-header.py --check --paths GFramework.Cqrs.Benchmarks/Messaging/StreamPipelineBenchmarks.cs GFramework.Cqrs.Benchmarks/Messaging/StreamingBenchmarks.cs GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md`
- 结果:通过
### 阶段:多波 batch 继续收口CQRS-REWRITE-RP-135
-`$gframework-batch-boot 50` 恢复当前 topic并把基线固定为
`origin/main @ ef4d3d5d (2026-05-11 17:33:43 +0800)`
- 启动时确认当前工作树干净branch diff 为 `0 files / 0 lines`;旧 tracking 中“未提交收尾切片”已不再反映真实仓库状态。
- 第 1 波 accepted delegated scope
- `CqrsRegistrationServiceTests`
- 补空输入不触发 registrar、忽略空项后按稳定程序集键排序并去重、跨调用跳过已注册键时继续处理剩余新程序集
- `CqrsHandlerRegistrarTests` + `CqrsHandlerRegistrarFallbackFailureTests`
- 补 abstract registry 与缺少无参构造器 registry 在程序集级回退路径和 direct activation 入口的告警 / 抛错覆盖
- `StreamPipelineBenchmarks` + `GFramework.Cqrs.Benchmarks/README.md`
- 新增 `0 / 1 / 4` 个 stream pipeline 行为与 `FirstItem / DrainAll` 观测矩阵
- README 补齐 stream pipeline coverage、运行示例与 gap 说明
- 第 2 波 accepted delegated scope
- `CqrsNotificationPublisherTests`
- 补“容器未注册 publisher 时回退到 `SequentialNotificationPublisher`,且首次解析后缓存结果”回归
- `StreamingBenchmarks` + `GFramework.Cqrs.Benchmarks/README.md`
- 补 steady-state stream 的 `Mediator` 对照
- README 将 stream steady-state gap 收口为“lifetime / startup 仍缺 `Mediator` parity”
- 主线程验收与修正:
- 审核 5 个 worker 提交均未越出 ownership 边界
-`StreamPipelineBenchmarks.cs` 修掉 `git diff --check` 报出的 1 处 trailing whitespace
- 更新 active tracking / trace 到当前 branch 事实,避免下次 `boot` 继续落到过期恢复点
- 本轮权威验证:
- `dotnet build GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release`
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsRegistrationServiceTests|FullyQualifiedName~CqrsHandlerRegistrarTests|FullyQualifiedName~CqrsHandlerRegistrarFallbackFailureTests|FullyQualifiedName~CqrsNotificationPublisherTests"`
- `python3 scripts/license-header.py --check --paths ...`
- `git diff --check origin/main...HEAD`
- 当前停点判断:
- 当前 branch diff 约为 `9 files / 1111 lines`
- 明显低于 `50 files` 阈值
- 本轮停止信号来自 `context-budget / reviewability`,不是文件预算耗尽
- 当前下一步:
- 先按需要运行 `$gframework-pr-review`,确认 `PR #349` latest-head open thread 是否已随当前修复提交收敛
- 若继续扩 benchmark优先补 `StreamLifetimeBenchmarks``StreamStartupBenchmarks` 的单文件 `Mediator` parity
- 若切回文档收尾,把 `GFramework.Cqrs/README.md``docs/zh-CN/core/command.md``docs/zh-CN/core/query.md` 单独作为 docs-only 下一波
## 2026-05-11
### 阶段PR #348 latest-head review 再收口CQRS-REWRITE-RP-134
- 重新执行 `$gframework-pr-review` 抓取当前分支 `feat/cqrs-optimization` 对应的 `PR #348`
- 本轮 latest-head open AI thread 复核结论:
- `NotificationLifetimeBenchmarks.HandlerLifetime``[GenerateEnumExtensions]` 仍判定为泛化误报
- 仓库没有“产品/benchmark 枚举默认都启用该特性”的现行约定
- benchmark 项目也未接入 `GFramework.Core.SourceGenerators.Abstractions`,不应为局部对照枚举平白扩大 generator 依赖面
- `NotificationLifetimeBenchmarks``_scopedContainer` 释放缺口与公开 benchmark API 的 XML 契约缺口仍成立,接受修复
- `CqrsHandlerRegistrar` 中 generated descriptor 的“先去重后校验”缺陷仍成立,接受修复并补测试
- `CqrsHandlerRegistrar``MethodInfo` 使用 `ReferenceEquals` 的过严比较仍成立,接受修复
- active tracking / trace 的当前 PR 锚点仍停留在 `PR #347`,接受同步到 `PR #348`
- 本轮主线程实施:
- `NotificationLifetimeBenchmarks`
- `Cleanup()``_scopedContainer` 一并交给 `BenchmarkCleanupHelper.DisposeAll(...)`
- 为公开 benchmark 方法与公开 handler 方法补齐缺失的 `<returns>` / `<param>` XML 契约
- `CqrsHandlerRegistrar`
- request / stream generated descriptor 预热路径改为“先 `TryValidate...`,后写入 `registeredKeys`
- descriptor 对齐判断从 `ReferenceEquals(resolvedDescriptor.InvokerMethod, ...)` 调整为 `resolvedDescriptor.InvokerMethod.Equals(...)`
- `CqrsGeneratedRequestInvokerProviderTests`
- 新增 request / stream 两个回归用例,锁定“首条同键 descriptor 无效、后条有效时,仍应接受后条有效 generated descriptor”
- `ai-plan/public/cqrs-rewrite/**`
- 将 active tracking / trace 的当前 PR 锚点同步到 `PR #348`
### 阶段PR #347 latest-head review 收口CQRS-REWRITE-RP-132
- 使用 `$gframework-pr-review` 重新抓取当前分支 `feat/cqrs-optimization` 对应的 `PR #347`
- 抓取结果显示当前 latest-head 仍有 `CodeRabbit 6``Greptile 2` open thread但本地复核后只接受以下仍成立的结论
- `Program.cs` 只在命令行 `--artifacts-suffix` 下重启隔离宿主,未覆盖环境变量触发的隔离路径
- `Program.cs` 缺少“目标隔离宿主目录位于当前宿主输出目录内”的防守式校验
- `RequestLifetimeBenchmarks` / `StreamLifetimeBenchmarks``Scoped` 路径每次 benchmark 调用都会新建 runtime污染生命周期矩阵公平性
- `ScopedBenchmarkContainer` 的公共/关键成员 XML 契约说明不完整
- active tracking / trace 已经偏离“快速恢复入口”,需要归档瘦身
- 本轮实现选择:
- `Program.cs`
- 把“是否需要重启隔离宿主”统一收敛到 `ArtifactsPath != null`
- 为隔离宿主目录补充“不得等于或嵌套在当前宿主输出目录内”的校验
- `BenchmarkHostFactory.cs`
- scoped request / stream helper 改为复用单个 runtime只在调用边界进入和释放 scope
- `ScopedBenchmarkContainer.cs`
- 从“构造时绑定单次 scope”改为“可重复进入的作用域适配器 + `ScopeLease`
- 补齐只读适配器与作用域租约的 XML 合同说明
- `RequestLifetimeBenchmarks.cs`
- `Scoped` 路径改为 `GlobalSetup` 时创建单个 scoped runtime
- `StreamLifetimeBenchmarks.cs`
- `Scoped` reflection / generated 路径改为 `GlobalSetup` 时各自创建单个 scoped runtime
- 按语义阶段拆分 `Setup()`,同时清掉 `MA0051`
- `README.md`
-`RequestLifetimeBenchmarks` 的 scoped 语义更新为“复用 runtime仅每次创建真实 scope”
- `ai-plan/public/cqrs-rewrite/**`
- 将旧 active tracking / trace 复制归档到
`archive/todos/cqrs-rewrite-migration-tracking-history-through-rp131.md`
`archive/traces/cqrs-rewrite-migration-trace-history-through-rp131.md`
- 重写 active tracking / trace只保留当前恢复点、关键结论、风险与验证
### 本轮验证
- `dotnet build GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release`
- 结果:通过,`0 warning / 0 error`
- `dotnet run --project GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release --no-build -- --artifacts-suffix pr347-req-scoped --filter "*RequestLifetimeBenchmarks.SendRequest_GFrameworkCqrs*" --job short --warmupCount 1 --iterationCount 1 --launchCount 1`
- 结果:通过
- 备注:独立宿主目录位于 `BenchmarkDotNet.Artifacts/pr347-req-scoped/host/...`
- 结果摘要:`Singleton 52.69 ns / 32 B``Transient 57.88 ns / 56 B``Scoped 144.72 ns / 368 B`
- `dotnet run --project GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release --no-build -- --artifacts-suffix pr347-stream-scoped --filter "*StreamLifetimeBenchmarks.Stream_GFramework*" --job short --warmupCount 1 --iterationCount 1 --launchCount 1`
- 结果:通过
- 备注:独立宿主目录位于 `BenchmarkDotNet.Artifacts/pr347-stream-scoped/host/...`
- 结果摘要:
- `Singleton + FirstItem`reflection `108.7 ns / 216 B`generated `110.1 ns / 216 B`
- `Scoped + FirstItem`reflection `266.7 ns / 792 B`generated `267.0 ns / 792 B`
- `Scoped + DrainAll`reflection `331.6 ns / 856 B`generated `332.2 ns / 856 B`
### 当前结论
- `Program.cs` 已不再依赖“命令行后缀”这一单一来源决定宿主隔离,环境变量生效路径也会进入隔离宿主。
- scoped benchmark 的公平性问题已经实质收口runtime 构造成本不再按每次调用重复计入生命周期矩阵。
- active tracking / trace 已恢复到可供 `boot` 和后续 PR review 快速进入的体量;历史细节仍可通过新的 archive 文件追溯。
### 当前下一步
- 推送本轮变更后,重新运行 `$gframework-pr-review`,确认 `PR #347` 的 latest-head open thread 是否已随着新 head 收敛。
### 阶段:多波 batch 收口与 benchmark / docs 扩面CQRS-REWRITE-RP-133
-`$gframework-batch-boot` 启动多波 non-conflicting subagent基线固定为
`origin/main @ 3b2e6899d5ffdcfb634b28f3846f57528fbf9196 (2026-05-11T12:25:00+08:00)`
- 启动前分支累计 diff 为 `0 files / 0 lines`;自然停点时累计 branch diff 约为 `12 files`
- 主线程把 stop decision 明确交给 `reviewability / context-budget`,没有在仍有文件预算时继续机械追到 `50 files`
- 本轮 accepted delegated scope
- runtime / tests
- `CqrsNotificationPublisherTests`:补“多 publisher 报错”与“publisher 缓存复用”回归
- `CqrsGeneratedRequestInvokerProviderTests` + `CqrsHandlerRegistrar`:补 generated descriptor 坏元数据、异常枚举、重复 pair 回退契约
- `CqrsDispatcherCacheTests`:补 request / stream pipeline presence、executor cache 与上下文重新注入组合分支
- `CqrsRegistrationServiceTests`:补稳定程序集键 fallback 到 `AssemblyName.Name` / `ToString()` 的回归
- benchmarks
- `RequestStartupBenchmarks`:补 `Mediator` startup 对照
- `StreamStartupBenchmarks`
- `NotificationStartupBenchmarks`
- `NotificationLifetimeBenchmarks`
- `GFramework.Cqrs.Benchmarks/README.md`:收口当前 coverage / gap / smoke 解释边界
- docs / recovery
- `GFramework.Cqrs/README.md`
- `docs/zh-CN/core/cqrs.md`
- `docs/zh-CN/source-generators/cqrs-handler-registry-generator.md`
- `docs/zh-CN/core/command.md`
- `docs/zh-CN/core/query.md`
- `ai-plan/public/cqrs-rewrite/archive/**` 顶部导航与跳转约定
- 本轮权威验证:
- `dotnet build GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release`
- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`
- `dotnet build GFramework.Core/GFramework.Core.csproj -c Release`
- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsRegistrationServiceTests"`
- `dotnet run --project GFramework.Cqrs.Benchmarks/GFramework.Cqrs.Benchmarks.csproj -c Release --no-build -- --artifacts-suffix notif-lifetime --filter "*NotificationLifetimeBenchmarks*"`
- 本轮 benchmark 结果摘要:
- `RequestStartupBenchmarks`
- `ColdStart_GFrameworkCqrs 61.648 us / 25336 B`
- `ColdStart_Mediator 110.867 us / 57872 B`
- `ColdStart_MediatR 679.103 us / 606256 B`
- `StreamStartupBenchmarks`
- `ColdStart_GFrameworkReflection 71.13 us / 25504 B`
- `ColdStart_GFrameworkGenerated 82.12 us / 28280 B`
- `ColdStart_MediatR 933.87 us / 678992 B`
- `NotificationStartupBenchmarks`
- `ColdStart_GFrameworkCqrs 85.09 us / 24752 B`
- `ColdStart_Mediator 136.08 us / 62512 B`
- `ColdStart_MediatR 1.379 ms / 719056 B`
- `NotificationLifetimeBenchmarks`
- `Singleton``GFramework 295.48 ns / 360 B``MediatR 77.99 ns / 288 B`
- `Scoped``GFramework 410.92 ns / 640 B``MediatR 213.49 ns / 632 B`
- `Transient``GFramework 311.21 ns / 416 B``MediatR 74.36 ns / 288 B`
- 当前收尾判断:
- branch diff 仍远低于 `50` 文件阈值,但 active 未提交面与 benchmark 运行输出已经足够构成自然 stop boundary
- 下一步不继续扩 batch先提交当前收尾切片并回到干净工作树再按 PR review 结果决定后续波次