Skip to content

Feat/Implement CQRS runtime integration for legacy compatibility#334

Merged
GeWuYou merged 7 commits into
mainfrom
feat/cqrs-optimization
May 7, 2026
Merged

Feat/Implement CQRS runtime integration for legacy compatibility#334
GeWuYou merged 7 commits into
mainfrom
feat/cqrs-optimization

Conversation

@GeWuYou
Copy link
Copy Markdown
Owner

@GeWuYou GeWuYou commented May 7, 2026

Summary by CodeRabbit

发行说明

  • 新特性

    • 旧的 Command/Query 兼容入口现已路由至统一 CQRS 运行时管道,执行路径可选运行时桥接并保留原有 API
  • 测试

    • 大幅增强遗留桥接单元测试,覆盖同步/异步命令/查询、上下文注入、取消语义及调用计数追踪
  • 性能基准

    • 新增请求调度基准,比较不同处理器生命周期下的调度路径
  • 文档

    • 更新架构与 CQRS 文档,说明兼容路径、回退行为与实现注意事项
  • 杂项

    • 暴露 test 访问权限以支持测试套件执行 (InternalsVisibleTo)

GeWuYou added 2 commits May 7, 2026 14:20
- 新增 request handler Singleton 与 Transient 生命周期 benchmark,并说明 Scoped 对照的宿主前置条件

- 更新 benchmark README,补充当前覆盖范围与后续扩展方向

- 更新 cqrs-rewrite active tracking 与 trace,记录 RP-092 验证结果和沙箱外 benchmark 权威结论
- 重构 Core 兼容命令查询入口,使 legacy SendCommand/SendQuery 通过内部 bridge request 复用统一 CQRS runtime

- 新增 legacy bridge handler 与真实启动路径回归测试,验证默认架构初始化会自动接入统一 pipeline

- 更新 Core 与 CQRS 文档及 cqrs-rewrite 跟踪,记录 Mediator 尚未吸收的能力差距与后续收口方向
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Review Change Stack

Warning

Rate limit exceeded

@GeWuYou has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 27 seconds before requesting another review.

To continue reviewing without waiting, purchase usage credits in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: af2373b1-8522-43fa-b180-d2cef54c059f

📥 Commits

Reviewing files that changed from the base of the PR and between cca4130 and ffb0a8a.

📒 Files selected for processing (6)
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
📝 Walkthrough

Walkthrough

PR 将旧的 SendQuery/SendCommand 系列封装为多种 Legacy*DispatchRequest,并通过新增的 LegacyCqrsDispatchHelper 与可选 ICqrsRuntime 运行时将 legacy 请求路由到统一 pipeline;更新 Executors 与 ArchitectureContext 以优先通过 runtime 桥接(无法解析时回退到 legacy 执行);补入大量测试、基准与文档更新。

Changes

Legacy CQRS 运行时桥接

Layer / File(s) Summary
调度请求与基类
GFramework.Core/Cqrs/LegacyCqrsDispatchRequestBase.cs, GFramework.Core/Cqrs/LegacyCqrsDispatchHandlerBase.cs
新增内部基类以承载目标对象与 PrepareTarget/context 注入逻辑。
查询调度(同步 / 异步)
GFramework.Core/Cqrs/LegacyQueryDispatchRequest.cs, GFramework.Core/Cqrs/LegacyQueryDispatchRequestHandler.cs, GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequest.cs, GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequestHandler.cs
将同步与异步 legacy 查询适配为 CQRS IRequest,Handler 在 PrepareTarget 时注入 IArchitectureContext 并返回 boxed 结果。
命令调度(同步 / 异步 / 带结果)
GFramework.Core/Cqrs/LegacyCommandDispatchRequest.cs, GFramework.Core/Cqrs/LegacyCommandDispatchRequestHandler.cs, GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequest.cs, GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequestHandler.cs, GFramework.Core/Cqrs/LegacyCommandResultDispatchRequest.cs, GFramework.Core/Cqrs/LegacyCommandResultDispatchRequestHandler.cs, GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequest.cs, GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequestHandler.cs
将不同种类的 legacy 命令包装为 IRequest,支持取消观察、context 注入与结果 boxing/unboxing。
同步桥 Helper
GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
新增 TryResolveDispatchContext 用于从 legacy target 提取 IArchitectureContext,并新增 SendSynchronously 将 runtime.SendAsync 在后台线程同步等待以避免阻塞调用者 SynchronizationContext。
Executor 运行时集成
GFramework.Core/Query/QueryExecutor.cs, GFramework.Core/Query/AsyncQueryExecutor.cs, GFramework.Core/Command/CommandExecutor.cs
Executors 增加可选 ICqrsRuntime 构造参数与 UsesCqrsRuntime 属性;当 runtime 可用且能解析 dispatch context 时通过 runtime 调度 Legacy*DispatchRequest,否则回退直接 legacy 执行。
ArchitectureContext 路由重构
GFramework.Core/Architectures/ArchitectureContext.cs
将 legacy SendQuery/SendCommand 系列改为通过 SendRequest/SendRequestAsync 与 Legacy*DispatchRequest(或通过 LegacyCqrsDispatchHelper 的同步桥)发送到 runtime,方法参数使用全限定 CQRS 接口以消歧义。
模块注册更新
GFramework.Core/Services/Modules/QueryExecutorModule.cs, GFramework.Core/Services/Modules/AsyncQueryExecutorModule.cs, GFramework.Core/Services/Modules/CommandExecutorModule.cs
Register 方法新增容器 null 检查,并从容器解析 ICqrsRuntime 用于构造并注册带 runtime 的 executor;更新 XML 文档说明。
测试工具与跟踪
GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs, GFramework.Core.Tests/Architectures/LegacyBridgeTrackingPipelineBehavior.cs, GFramework.Core.Tests/Architectures/LegacyArchitectureBridge*.cs
新增 LegacyBridgePipelineTracker 与 LegacyBridgeTrackingPipelineBehavior,用于记录 pipeline 命中;新增 context-aware 测试请求/命令用于断言 ObservedContext 与执行行为。
测试与集成验证
GFramework.Core.Tests/...
新增/扩展多处测试(ArchitectureContextTests、ArchitectureModulesBehaviorTests、Command/Query executor tests、Legacy async handler cancellation tests、AsyncQueryExecutorTests、QueryExecutorTests 等),并改进 teardown(重置 tracker、释放容器、标注 NonParallelizable)。
基准
GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs, GFramework.Cqrs.Benchmarks/README.md
新增基准比较直接 handler、GFramework.Cqrs 运行时与 MediatR 在 Singleton/Transient 下的调度开销,并更新 README。
文档与迁移追踪
GFramework.Core/README.md, docs/zh-CN/core/*.md, ai-plan/public/cqrs-rewrite/*
更新说明 legacy Command/Query 在标准 Architecture 启动路径中通过 ICqrsRuntime 路由的行为,并补入迁移追踪与验证步骤记录。

Sequence Diagram

sequenceDiagram
  participant Caller
  participant Arch as ArchitectureContext
  participant Helper as LegacyCqrsDispatchHelper
  participant Runtime as ICqrsRuntime
  Caller->>Arch: SendQuery/SendCommand(legacy)
  Arch->>Helper: SendRequest / SendSynchronously(Legacy*DispatchRequest)
  Helper->>Runtime: SendAsync(dispatchRequest)
  Runtime->>Handler: pipeline -> Handle(request)
  Handler-->>Runtime: 返回 boxed 结果
  Arch-->>Caller: 转换并返回
Loading

估计审查工作量

🎯 4 (Complex) | ⏱️ ~50 分钟

可能相关的 PR

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Pull request title clearly describes the main objective: implementing CQRS runtime integration for legacy compatibility layer, which matches the primary focus of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 97.89% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cqrs-optimization

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2305    ↑23 2305    ↑23 0 0 0 0 37.7s    ↓180ms

Test Results

passed 2305 passed ↑23

Details

tests 2305 tests ↑23
clock 37.7s ↓180ms
tool nunit
build CI - Build & Test arrow-right build-and-test link #1077
pull-request Feat/cqrs optimization link #334

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2198 0 0 4.8s

build-and-test: Run #1077

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2305 2305 0 0 0 0 0 37.7s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
CreateStream_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 13 4.3s 4.8s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 28 2.2s 4.7s
Does_Not_Report_When_FieldInjectedModel_Is_Registered 28 2.2s 2.3s
Generates_Scene_Behavior_Boilerplate 28 1.9s 2.0s
CleanupDuringAcquire_Should_NotCauseRaceCondition 28 1.1s 1.1s
Append_ShouldNotBlock 28 1.0s 1.0s
Context_Caching_Should_Improve_Performance 28 784ms 795ms
PendingCount_ShouldReflectQueuedEntries 28 501ms 501ms
Cleanup_Should_NotRemoveActiveLocks 28 404ms 405ms
Cleanup_Should_RemoveUnusedLocks 28 401ms 402ms

± Comparison with run #1063 at 984c144 | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 28 runs.

Github Test Reporter by CTRF 💚

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

⚠️MegaLinter analysis: Success with warnings

Descriptor Linter Files Fixed Errors Warnings Elapsed time
⚠️ CSHARP dotnet-format yes 1 no 4.97s
✅ REPOSITORY gitleaks yes no no 8.28s
✅ REPOSITORY trufflehog yes no no 7.08s

Detailed Issues

⚠️ CSHARP / dotnet-format - 1 error
Welcome to .NET 9.0!
---------------------
SDK Version: 9.0.114

----------------
Installed an ASP.NET Core HTTPS development certificate.
To trust the certificate, run 'dotnet dev-certs https --trust'
Learn about HTTPS: https://aka.ms/dotnet-https

----------------
Write your first app: https://aka.ms/dotnet-hello-world
Find out what's new: https://aka.ms/dotnet-whats-new
Explore documentation: https://aka.ms/dotnet-docs
Report issues and find source on GitHub: https://github.com/dotnet/core
Use 'dotnet --help' to see available commands or visit: https://aka.ms/dotnet-cli
--------------------------------------------------------------------------------------
Unhandled exception: System.Exception: Restore operation failed.
   at Microsoft.CodeAnalysis.Tools.CodeFormatter.OpenMSBuildWorkspaceAsync(String solutionOrProjectPath, WorkspaceType workspaceType, Boolean noRestore, Boolean requiresSemantics, String binaryLogPath, Boolean logWorkspaceWarnings, ILogger logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.CodeFormatter.FormatWorkspaceAsync(FormatOptions formatOptions, ILogger logger, CancellationToken cancellationToken, String binaryLogPath)
   at Microsoft.CodeAnalysis.Tools.FormatCommandCommon.FormatAsync(FormatOptions formatOptions, ILogger`1 logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.Commands.RootFormatCommand.FormatCommandDefaultHandler.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)
   at System.CommandLine.Invocation.InvocationPipeline.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)

See detailed reports in MegaLinter artifacts
Set VALIDATE_ALL_CODEBASE: true in mega-linter.yml to validate all sources, not only the diff

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 7, 2026

Greptile Summary

This PR routes legacy ICommand/IQuery entry points through the unified CQRS runtime pipeline, enabling IPipelineBehavior instrumentation on previously bypassed sync/async paths. A new LegacyCqrsDispatchHelper bridges the sync/async gap via Task.Run to avoid synchronization-context deadlocks, and six internal bridge handlers wrap legacy execution in the standard handler contract.

  • Six new LegacyXxxDispatchRequestHandler types implement the bridge, with LegacyCqrsDispatchHandlerBase.PrepareTarget injecting architecture context into IContextAware targets before execution; async handlers uniformly apply ThrowIfCancellationRequested and WaitAsync(cancellationToken).
  • CommandExecutor, QueryExecutor, and AsyncQueryExecutor now accept an optional ICqrsRuntime and conditionally bridge through it when the target exposes an architecture context; the three module registrations are updated to inject the runtime at container-registration time.
  • LegacyCqrsDispatchHelper.TryResolveDispatchContext narrows the previously broad InvalidOperationException catch to only two known "context not set" message strings, and SendSynchronously uses Task.Run to dispatch on a thread-pool thread and avoid deadlocks with ambient synchronization contexts.

Confidence Score: 5/5

Safe to merge; the bridge correctly uses Task.Run to avoid sync-context deadlocks and the exception filter covers all production GetContext throw sites.

All sync-over-async paths now go through Task.Run-backed SendSynchronously, removing the deadlock risk. The IsMissingContextException filter's two hardcoded strings match the actual messages thrown by GameContext.GetFirstArchitectureContext() and the state-base implementations, so the bridge falls back safely for every production no-context case. The async handlers uniformly apply ThrowIfCancellationRequested and WaitAsync. The only concern is fragility of those string literals on future rename, which is not a current defect.

Keep LegacyCqrsDispatchHelper.IsMissingContextException in sync with the throw sites in GameContext.cs, ContextAwareStateBase.cs, and AsyncContextAwareStateBase.cs whenever those messages are changed.

Important Files Changed

Filename Overview
GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs Core bridge helper: TryResolveDispatchContext narrows exception catch to two hardcoded message strings (fragile); SendSynchronously uses Task.Run to avoid sync-context deadlocks correctly.
GFramework.Core/Command/CommandExecutor.cs Adds optional ICqrsRuntime bridge path to all four send overloads; sync overloads go through Task.Run-backed SendSynchronously, async overloads pass the ValueTask directly.
GFramework.Core/Architectures/ArchitectureContext.cs Routes all legacy sync/async command and query entry points through LegacyCqrsDispatchHelper; SendRequest now uses Task.Run-backed sync wait instead of direct GetAwaiter().GetResult().
GFramework.Core/Cqrs/LegacyCqrsDispatchHandlerBase.cs Shared base for bridge handlers; PrepareTarget injects architecture context into IContextAware targets and throws clearly when context is unavailable.
GFramework.Core/Services/Modules/CommandExecutorModule.cs Now calls container.GetRequired<ICqrsRuntime>() at register time; hard dependency on CqrsRuntimeModule is documented in XML remarks but there is no runtime guard if the runtime is absent.
GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs Thorough test double for ICqrsRuntime that mirrors real bridge-handler semantics including context injection and cancellation.
GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs Static shared counter with Volatile/Interlocked for thread safety; guarded by [NonParallelizable] and Reset() calls but remains process-wide shared state.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs:65-77
**Fragile string-literal guards in `IsMissingContextException`**

The two hardcoded message strings are the sole mechanism for distinguishing "no context available" from any other `InvalidOperationException`. Both strings currently match the messages thrown by `GameContext.GetFirstArchitectureContext()` and `ContextAwareStateBase.GetContext()`, but they are duplicated across this helper and the test's `MissingContextLegacyCommand` stub with no compile-time link to the originating throw sites. If either source message is ever edited during a refactor, `IsMissingContextException` will silently return `false` for genuine "no context" cases, turning a safe fallback into a propagated exception that breaks all non-context-aware bridge callers.

Consider extracting the sentinel strings to `internal static readonly` constants defined alongside the places that throw them, or introducing a dedicated `MissingArchitectureContextException` that `GetFirstArchitectureContext()` and the state bases throw instead of `InvalidOperationException`.

```suggestion
    // These message strings MUST stay in sync with:
    //   • GFramework.Core/State/ContextAwareStateBase.cs      – _context ?? throw new IOE(MissingContextMessage)
    //   • GFramework.Core/State/AsyncContextAwareStateBase.cs – _context ?? throw new IOE(MissingContextMessage)
    //   • GFramework.Core/Architectures/GameContext.cs         – throw new IOE(NoActiveContextMessage)
    //
    // TODO: replace these literals with shared constants (or a dedicated MissingArchitectureContextException)
    //       so a future rename is caught at compile time.
    internal const string MissingContextMessage =
        "Architecture context has not been set. Call SetContext before accessing the context.";

    internal const string NoActiveContextMessage =
        "No active architecture context is currently bound.";

    private static bool IsMissingContextException(InvalidOperationException exception)
    {
        ArgumentNullException.ThrowIfNull(exception);

        return string.Equals(exception.Message, MissingContextMessage, StringComparison.Ordinal)
               || string.Equals(exception.Message, NoActiveContextMessage, StringComparison.Ordinal);
    }
```

Reviews (6): Last reviewed commit: "fix(core): 收窄 legacy bridge 上下文回退异常边界" | Re-trigger Greptile

Comment thread GFramework.Core/Cqrs/LegacyCommandDispatchRequest.cs Outdated
Comment thread GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequest.cs Outdated
Comment thread GFramework.Core/Services/Modules/CommandExecutorModule.cs Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
GFramework.Core/Services/Modules/AsyncQueryExecutorModule.cs (1)

33-40: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Register 的 XML 注释建议补齐异常与运行时依赖约束

这里已经引入显式 null 校验和 ICqrsRuntime 解析依赖,建议在 Register 的 XML 文档中补充 <exception><remarks>,明确失败路径与前置注册条件。

📝 建议补充
 /// <summary>
 ///     注册异步查询执行器到依赖注入容器。
 ///     创建异步查询执行器实例并将其注册为多例服务。
 /// </summary>
 /// <param name="container">依赖注入容器实例。</param>
+/// <exception cref="ArgumentNullException">当 <paramref name="container"/> 为 null 时抛出。</exception>
+/// <exception cref="Exception">当容器无法解析 <see cref="ICqrsRuntime"/> 时,抛出容器实现定义的异常。</exception>
+/// <remarks>
+///     该模块依赖容器中已注册 <see cref="ICqrsRuntime"/>。
+/// </remarks>
 public void Register(IIocContainer container)

As per coding guidelines, **/*.cs: XML documentation MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable, and explain intent, contract, and usage constraints.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Services/Modules/AsyncQueryExecutorModule.cs` around lines 33
- 40, 为 Register 方法补全 XML 文档:在现有 <summary> 和 <param> 之外加入 <exception> 标记说明当
container 为 null 时会抛出 ArgumentNullException,以及当无法解析 ICqrsRuntime 时可能抛出的
InvalidOperationException(或容器特定的解析异常);在 <remarks> 中说明该方法会从容器解析 ICqrsRuntime
并以多例/瞬态形式注册 AsyncQueryExecutor,强调调用方必须先在容器中注册
ICqrsRuntime(或等效运行时)以避免解析失败,并注明注册语义(多例/Transient)。
GFramework.Core/Services/Modules/CommandExecutorModule.cs (1)

33-40: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Register 建议补充异常与依赖约束的 XML 注释

这里已引入 ThrowIfNullcontainer.Get<ICqrsRuntime>() 的前置条件,建议在文档里明确,提升 API 合同可读性与可维护性。

As per coding guidelines, **/*.cs: XML documentation MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable, and explain intent, contract, and usage constraints.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Services/Modules/CommandExecutorModule.cs` around lines 33 -
40, 为 Register(IIocContainer) 方法补充完整 XML 注释,说明方法行为、参数约束和可能抛出的异常:在 <summary>
里描述“将 CommandExecutor 注册为多例服务”;在 <param name="container"> 中说明必须非空且实现
IIocContainer;新增 <exception cref="ArgumentNullException"> 说明当 container 为 null
时会抛出(因内部使用 ArgumentNullException.ThrowIfNull);新增 <remarks> 或
<returns>(如适用)说明内部会通过 container.Get<ICqrsRuntime>() 获取依赖并因此要求容器能解析
ICqrsRuntime。确保引用的方法/类型名为 Register, IIocContainer, CommandExecutor,
ArgumentNullException.ThrowIfNull, container.Get<ICqrsRuntime>() 以便在文档中清晰指出调用契约。
GFramework.Core/Services/Modules/QueryExecutorModule.cs (1)

33-40: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

建议为 Register 增加 <exception> / <remarks>,显式声明 ICqrsRuntime 依赖

这次改动引入了运行时解析依赖和明确异常路径,建议把方法契约写进 XML 注释,避免调用方只看签名时遗漏前置条件。

As per coding guidelines, **/*.cs: XML documentation MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable, and explain intent, contract, and usage constraints.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Services/Modules/QueryExecutorModule.cs` around lines 33 -
40, Update the XML documentation for QueryExecutorModule.Register to include an
<exception> that documents ArgumentNullException thrown when the container is
null and to explicitly state that this method resolves an ICqrsRuntime from the
container; in the <remarks> describe the precondition that an ICqrsRuntime
implementation must be registered in the IIocContainer before calling Register
(since the method constructs new QueryExecutor(container.Get<ICqrsRuntime>())
and registers it via container.RegisterPlurality). Ensure <summary> and <param
name="container"> remain, and mention the behavior of creating and registering a
QueryExecutor instance.
GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs (1)

35-40: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

[TearDown] 未重置 LegacyBridgePipelineTracker

现有 TearDown 已正确重置 TrackingPipelineBehavior,但遗漏了 LegacyBridgePipelineTracker。测试完成后残留的计数可能影响后续测试的断言。

🔧 建议修复
 public void TearDown()
 {
     GameContext.Clear();
     TrackingPipelineBehavior<ModuleBehaviorRequest, string>.InvocationCount = 0;
+    LegacyBridgePipelineTracker.Reset();
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs`
around lines 35 - 40, TearDown currently clears GameContext and resets
TrackingPipelineBehavior<ModuleBehaviorRequest, string>.InvocationCount but
forgets to reset LegacyBridgePipelineTracker; update the TearDown method to also
reset the LegacyBridgePipelineTracker's count/state (the static counter or
relevant reset method on LegacyBridgePipelineTracker) so tests don't leak state
between runs.
🧹 Nitpick comments (10)
GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequest.cs (1)

8-11: ⚡ Quick win

补充主构造函数参数的 <param>ExecuteAsync<returns> XML 文档

LegacyAsyncCommandResultDispatchRequest 存在相同的文档缺失问题:类级别 XML 注释未包含 targetexecuteAsync<param> 标签,ExecuteAsync() 也缺少 <returns> 说明。

✏️ 建议修复
 /// <summary>
 ///     包装 legacy 异步查询,使其能够通过自有 CQRS runtime 调度。
 /// </summary>
+/// <param name="target">bridge request 所代理的 legacy 目标对象,不可为 <see langword="null"/>。</param>
+/// <param name="executeAsync">封装 legacy 查询执行逻辑的异步委托,不可为 <see langword="null"/>。</param>
 internal sealed class LegacyAsyncQueryDispatchRequest(object target, Func<Task<object?>> executeAsync)
     /// <summary>
     ///     异步执行底层 legacy 查询并返回装箱后的结果。
     /// </summary>
+    /// <returns>legacy 查询执行完成后装箱的返回值;若查询无返回值则为 <see langword="null"/>。</returns>
     public Task<object?> ExecuteAsync() => _executeAsync();

As per coding guidelines: "XML documentation MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequest.cs` around lines 8 - 11,
为 LegacyAsyncQueryDispatchRequest 的主构造函数补充 XML 文档中的 <param> 标签,分别说明
target(被包装的目标对象或处理者)和 executeAsync(执行查询的委托,返回 Task<object?>)的含义;同时在 ExecuteAsync
方法的 XML 注释中添加 <returns>,明确返回值是 Task<object?>(表示异步查询结果或 null);参照
LegacyAsyncCommandResultDispatchRequest 的注释样式确保使用 <summary>、<param> 和 <returns>
并在注释中使用类名 LegacyAsyncQueryDispatchRequest 和方法名 ExecuteAsync 作为定位参考。
GFramework.Core/Cqrs/LegacyCqrsDispatchHandlerBase.cs (1)

14-17: ⚡ Quick win

PrepareTarget 缺少 <param><exception> XML 文档

PrepareTarget 的 XML 注释缺少对参数和可抛异常的说明。该方法对 target 为 null 抛 ArgumentNullException,对上下文不可用时抛 InvalidOperationException——调用方需要这些契约信息。

✏️ 建议修复
     /// <summary>
     ///     在执行 legacy 命令或查询前,把当前架构上下文显式注入给支持 <see cref="IContextAware" /> 的目标对象。
     /// </summary>
+    /// <param name="target">待注入上下文的目标对象,不可为 <see langword="null"/>。</param>
+    /// <exception cref="ArgumentNullException"><paramref name="target"/> 为 <see langword="null"/>。</exception>
+    /// <exception cref="InvalidOperationException">目标实现了 <see cref="IContextAware"/> 但当前 handler 尚无可用的架构上下文。</exception>
     protected void PrepareTarget(object target)

As per coding guidelines: "XML documentation MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Cqrs/LegacyCqrsDispatchHandlerBase.cs` around lines 14 - 17,
The PrepareTarget method is missing XML doc tags for its parameter and possible
exceptions; add <param name="target"> describing the target object and when it
must be non-null, and add <exception cref="System.ArgumentNullException"> and
<exception cref="System.InvalidOperationException"> entries describing the
conditions under which each is thrown (null target and missing/invalid context
respectively), keeping the existing <summary> intact and following the project's
XML-doc guidelines; reference the PrepareTarget method and the IContextAware
interface in the comments to clarify the contract.
GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequest.cs (1)

8-11: ⚡ Quick win

补充主构造函数参数的 <param>ExecuteAsync<returns> XML 文档

类级别 XML 注释缺少 targetexecuteAsync 两个主构造函数参数的 <param> 标签;ExecuteAsync() 方法也缺少 <returns> 说明。

✏️ 建议修复
 /// <summary>
 ///     包装 legacy 异步带返回值命令,使其能够通过自有 CQRS runtime 调度。
 /// </summary>
+/// <param name="target">bridge request 所代理的 legacy 目标对象,不可为 <see langword="null"/>。</param>
+/// <param name="executeAsync">封装 legacy 命令执行逻辑的异步委托,不可为 <see langword="null"/>。</param>
 internal sealed class LegacyAsyncCommandResultDispatchRequest(object target, Func<Task<object?>> executeAsync)
     /// <summary>
     ///     异步执行底层 legacy 命令并返回装箱后的结果。
     /// </summary>
+    /// <returns>legacy 命令执行完成后装箱的返回值;若命令无返回值则为 <see langword="null"/>。</returns>
     public Task<object?> ExecuteAsync() => _executeAsync();

As per coding guidelines: "XML documentation MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequest.cs` around lines
8 - 11, Add XML documentation for the primary constructor parameters and the
ExecuteAsync method: update the class-level comment for
LegacyAsyncCommandResultDispatchRequest to include <param name="target">
describing the wrapped legacy command target and <param name="executeAsync">
describing the Func<Task<object?>> execution delegate, and add a <returns> tag
to the ExecuteAsync() method describing the returned Task<object?> (what the
task represents and nullability). Ensure the tags follow existing XML doc style
used in the file.
GFramework.Core/Cqrs/LegacyCqrsDispatchRequestBase.cs (1)

6-9: ⚡ Quick win

补充主构造函数参数的 <param> XML 文档

类级别 XML 注释中缺少对主构造函数参数 target<param> 说明。根据编码规范,所有 public/protected/internal 成员均须包含完整的 XML 文档(<summary><param><exception> 等适用标签)。

✏️ 建议修复
 /// <summary>
 ///     为 legacy Command / Query 到自有 CQRS runtime 的桥接请求提供共享的目标对象封装。
 /// </summary>
+/// <param name="target">bridge request 所代理的 legacy 目标对象,不可为 <see langword="null"/>。</param>
+/// <exception cref="ArgumentNullException"><paramref name="target"/> 为 <see langword="null"/>。</exception>
 internal abstract class LegacyCqrsDispatchRequestBase(object target)

As per coding guidelines: "XML documentation MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Cqrs/LegacyCqrsDispatchRequestBase.cs` around lines 6 - 9,
The class XML docs for LegacyCqrsDispatchRequestBase(object target) are missing
a <param> entry for the primary constructor parameter; update the class-level
XML comment to include a <param name="target">...</param> that briefly describes
what the target represents (e.g., the wrapped legacy command/query target
object) so the internal abstract class LegacyCqrsDispatchRequestBase and its
constructor parameter `target` meet the project's XML documentation
requirements.
GFramework.Core.Tests/Architectures/LegacyArchitectureBridgeCommand.cs (1)

31-31: 💤 Low value

在文件顶部添加 using 指令,避免在方法体中使用完全限定类型名

第 31 行对 IContextAware 使用了完全限定名 GFramework.Core.Abstractions.Rule.IContextAware,但该命名空间并未在文件顶部导入。添加一个 using 可以提升可读性。

✏️ 建议修复
 using GFramework.Core.Abstractions.Architectures;
 using GFramework.Core.Abstractions.Command;
+using GFramework.Core.Abstractions.Rule;
 using GFramework.Core.Rule;
-        ObservedContext = ((GFramework.Core.Abstractions.Rule.IContextAware)this).GetContext();
+        ObservedContext = ((IContextAware)this).GetContext();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core.Tests/Architectures/LegacyArchitectureBridgeCommand.cs` at
line 31, Add a using directive for the GFramework.Core.Abstractions.Rule
namespace at the top of the file so the cast in the ObservedContext assignment
can use the short interface name instead of the fully-qualified
GFramework.Core.Abstractions.Rule.IContextAware; update the code line using the
IContextAware symbol (the cast currently on ObservedContext =
((GFramework.Core.Abstractions.Rule.IContextAware)this).GetContext();) to rely
on the imported type for readability.
GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs (1)

31-39: ⚡ Quick win

Record 方法使用字符串名称匹配识别 bridge request,存在脆弱性。

通过 requestType.Name.Contains("Legacy", StringComparison.Ordinal) 来判断请求类型,若将来 GFramework.Core.Cqrs 命名空间中新增包含 "Legacy" 字样但与 bridge 无关的类型,将产生误计数。建议使用 marker interface 或共同基类进行检测:

-if (string.Equals(requestType.Namespace, "GFramework.Core.Cqrs", StringComparison.Ordinal) &&
-    requestType.Name.Contains("Legacy", StringComparison.Ordinal))
+// 推荐:改为检查 marker interface 或公共基类,以替代字符串名称匹配
+if (typeof(ILegacyCqrsBridgeRequest).IsAssignableFrom(requestType))

LegacyCqrsDispatchRequestBase 已是公共基类,也可直接用 IsAssignableFrom(requestType) 检测。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs` around
lines 31 - 39, The current Record method misidentifies bridge requests by
string-matching requestType.Name for "Legacy", causing false positives; update
the detection to use a type-based check instead: after
ArgumentNullException.ThrowIfNull(requestType) replace the namespace+name string
condition with an assignability check against a dedicated marker/interface or
base class (e.g.
typeof(LegacyCqrsDispatchRequestBase).IsAssignableFrom(requestType) or an
ILegacyBridgeRequest marker), and only call Interlocked.Increment(ref
_invocationCount) when that type-based check succeeds so detection is robust and
accurate.
GFramework.Core/Query/AsyncQueryExecutor.cs (1)

33-85: ⚡ Quick win

建议同样为 TryResolveDispatchContext[MemberNotNullWhen(true, nameof(_runtime))],顺便去掉 _runtime! 的强抑制。

QueryExecutor 同构。第 33 行的 && _runtime is not null 仅为 nullable 分析,第 52 行的 _runtime! 也是因为编译器无法跨方法跟踪 TryResolveDispatchContext 已经验证过 _runtime 非空。把判空语义沉到 TryResolveDispatchContext 上后,这两处都可以自然简化。

♻️ 建议的改动
+using System.Diagnostics.CodeAnalysis;
 using GFramework.Core.Abstractions.Query;
+using GFramework.Core.Abstractions.Architectures;
 using GFramework.Core.Abstractions.Rule;
 using GFramework.Core.Cqrs;
 using GFramework.Cqrs.Abstractions.Cqrs;
-        if (TryResolveDispatchContext(query, out var context) && _runtime is not null)
+        if (TryResolveDispatchContext(query, out var context))
         {
             return BridgeAsyncQueryAsync<TResult>(context, query);
         }
     private async Task<TResult> BridgeAsyncQueryAsync<TResult>(
-        GFramework.Core.Abstractions.Architectures.IArchitectureContext context,
+        IArchitectureContext context,
         IAsyncQuery<TResult> query)
     {
-        var boxedResult = await _runtime!.SendAsync(
+        // Caller guarantees _runtime is non-null via TryResolveDispatchContext.
+        var boxedResult = await _runtime!.SendAsync(
-    private bool TryResolveDispatchContext(object query, out GFramework.Core.Abstractions.Architectures.IArchitectureContext context)
+    [MemberNotNullWhen(true, nameof(_runtime))]
+    private bool TryResolveDispatchContext(object query, [NotNullWhen(true)] out IArchitectureContext? context)
     {
-        context = null!;
+        context = null;
         ...
     }

As per coding guidelines: "Write null-safe code that respects nullable annotations instead of suppressing warnings by default in C#".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Query/AsyncQueryExecutor.cs` around lines 33 - 85, Add the
nullable annotation to TryResolveDispatchContext so the compiler knows _runtime
is non-null when it returns true: annotate the method with
[MemberNotNullWhen(true, nameof(_runtime))] (import
System.Diagnostics.CodeAnalysis), keep its behavior, then remove the redundant
null-check "&& _runtime is not null" at the call site and drop the null-forcing
operator from _runtime! inside BridgeAsyncQueryAsync so calls use _runtime
directly (refer to TryResolveDispatchContext, BridgeAsyncQueryAsync, and the
_runtime field).
GFramework.Core/Query/QueryExecutor.cs (1)

38-78: ⚡ Quick win

建议为 TryResolveDispatchContext 加上 [MemberNotNullWhen(true, nameof(_runtime))],以消除调用点的重复 _runtime is not null 判空。

TryResolveDispatchContext_runtime is null 时已经返回 false(第 64 行),因此 38 行的 && _runtime is not null 实际上只是为了配合 nullable flow 分析,让编译器在第 40 行不报警。用 MemberNotNullWhen 把这个语义显式声明出来,既能去掉重复判空,也能让后续别的调用点直接从 TryResolveDispatchContext 拿到 _runtime 已经非空的事实。

♻️ 建议的改动
+using System.Diagnostics.CodeAnalysis;
 using GFramework.Core.Abstractions.Query;
+using GFramework.Core.Abstractions.Architectures;
 using GFramework.Core.Abstractions.Rule;
 using GFramework.Core.Cqrs;
 using GFramework.Cqrs.Abstractions.Cqrs;
-        if (TryResolveDispatchContext(query, out var context) && _runtime is not null)
+        if (TryResolveDispatchContext(query, out var context))
         {
             var boxedResult = _runtime.SendAsync(
                     context,
                     ...
-    private bool TryResolveDispatchContext(object query, out GFramework.Core.Abstractions.Architectures.IArchitectureContext context)
+    [MemberNotNullWhen(true, nameof(_runtime))]
+    private bool TryResolveDispatchContext(object query, [NotNullWhen(true)] out IArchitectureContext? context)
     {
-        context = null!;
+        context = null;
 
         if (_runtime is null || query is not IContextAware contextAware)
         {
             return false;
         }
 
         try
         {
             context = contextAware.GetContext();
             return true;
         }
         catch (InvalidOperationException)
         {
             return false;
         }
     }

As per coding guidelines: "Write null-safe code that respects nullable annotations instead of suppressing warnings by default in C#".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Query/QueryExecutor.cs` around lines 38 - 78, Add the
nullable flow attribute to TryResolveDispatchContext and remove the redundant
check at the call site: annotate the method TryResolveDispatchContext with
[MemberNotNullWhen(true, nameof(_runtime))] so the compiler knows that when it
returns true _runtime is non-null, then update the caller in the method that
currently checks "if (TryResolveDispatchContext(query, out var context) &&
_runtime is not null)" to just "if (TryResolveDispatchContext(query, out var
context))" (remove the && _runtime is not null) so the nullable analysis no
longer requires the duplicate null check.
GFramework.Core/Command/CommandExecutor.cs (1)

80-202: ⚡ Quick win

建议把 _runtime 非空语义沉到 TryResolveDispatchContext,统一收敛四处重复判空与一处 null-forgiving。

第 80 / 99 / 121 / 147 行都重复了 TryResolveDispatchContext 已经覆盖过的 _runtime is null 判断,BridgeAsyncCommandWithResultAsync(第 169 行)也只能借助 _runtime! 跨方法抑制 nullable 警告。给 TryResolveDispatchContext[MemberNotNullWhen(true, nameof(_runtime))] 后,所有 if (TryResolveDispatchContext(...) && _runtime is not null) 都可以收敛为单条件,helper 内的负向分支也可以简化。

♻️ 建议的改动
+using System.Diagnostics.CodeAnalysis;
 using GFramework.Core.Abstractions.Command;
+using GFramework.Core.Abstractions.Architectures;
 using GFramework.Core.Abstractions.Rule;
 using GFramework.Core.Cqrs;
 using GFramework.Cqrs.Abstractions.Cqrs;
-        if (TryResolveDispatchContext(command, out var context) && _runtime is not null)
+        if (TryResolveDispatchContext(command, out var context))
         {
             return _runtime.SendAsync(context, new LegacyAsyncCommandDispatchRequest(command)).AsTask();
         }
-    private bool TryExecuteThroughCqrsRuntime<TTarget, TRequest>(
+    private bool TryExecuteThroughCqrsRuntime<TTarget, TRequest>(
         TTarget target,
         Func<TTarget, TRequest> requestFactory)
         where TTarget : class
         where TRequest : IRequest<Unit>
     {
-        if (!TryResolveDispatchContext(target, out var context) || _runtime is null)
+        if (!TryResolveDispatchContext(target, out var context))
         {
             return false;
         }

         _runtime.SendAsync(context, requestFactory(target)).AsTask().GetAwaiter().GetResult();
         return true;
     }
-    private bool TryResolveDispatchContext(object target, out GFramework.Core.Abstractions.Architectures.IArchitectureContext context)
+    [MemberNotNullWhen(true, nameof(_runtime))]
+    private bool TryResolveDispatchContext(object target, [NotNullWhen(true)] out IArchitectureContext? context)
     {
-        context = null!;
+        context = null;
         ...
     }

类比修改也适用于 TryExecuteThroughCqrsRuntime<TTarget, TResult, TRequest>BridgeAsyncCommandWithResultAsync(可去掉 _runtime!)。As per coding guidelines: "Write null-safe code that respects nullable annotations instead of suppressing warnings by default in C#".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Command/CommandExecutor.cs` around lines 80 - 202, The helper
TryResolveDispatchContext currently duplicates null checks for _runtime and
forces null-forgiving on usages; annotate TryResolveDispatchContext with
[MemberNotNullWhen(true, nameof(_runtime))] (import
System.Diagnostics.CodeAnalysis), adjust its signature/logic to assert _runtime
non-null when it returns true, then remove redundant "_runtime is not null"
guards in callers (SendAsync, SendAsync<TResult>,
TryExecuteThroughCqrsRuntime<TTarget,TRequest>,
TryExecuteThroughCqrsRuntime<TTarget,TResult,TRequest>) so each just calls
TryResolveDispatchContext(...) and uses _runtime without the null-forgiving
operator (e.g. remove _runtime! and simplify conditions to a single
TryResolveDispatchContext check).
GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs (1)

31-31: 💤 Low value

外层 benchmark 类可以加 sealed

仓库中其它 benchmark 模式(以及 Config 内嵌类自身)都用了 sealedRequestLifetimeBenchmarks 不需要被继承,封闭后既能与已有约定保持一致,又能让运行时省掉一次虚分发候选检查。

-public class RequestLifetimeBenchmarks
+public sealed class RequestLifetimeBenchmarks
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs` at line
31, 将公有基准类 RequestLifetimeBenchmarks 标记为 sealed:在类声明处添加 sealed
关键字以阻止继承并与仓库中其它基准类/内嵌 Config 类保持一致,从而消除不必要的虚调用开销(修改类 RequestLifetimeBenchmarks
的声明即可)。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/zh-CN/core/command.md`:
- Around line 108-110: 在这段文档中补充一行关于回退条件的说明,明确指出尽管标准架构入口会走
ICqrsRuntime,但在隔离测试或未注入 runtime 的场景(例如直接 new CommandExecutor() 而未提供 runtime
实例)会回退到 legacy
直接执行语义;请在描述中使用相同术语(ICqrsRuntime、CommandExecutor、pipeline/上下文注入)并说明行为一致性与副作用(pipeline
不被注入、使用旧的执行路径)。

In `@docs/zh-CN/core/context.md`:
- Around line 114-116: Augment the paragraph to explicitly state that
AsyncQueryExecutor (and the SendQueryAsync compatibility entry) follows the same
fallback rule: when you directly instantiate AsyncQueryExecutor without
providing an ICqrsRuntime it will fall back to legacy direct execution just like
new CommandExecutor() / new QueryExecutor(); update the text to mention
AsyncQueryExecutor and SendQueryAsync by name so readers know the same “no
runtime => legacy direct execution” boundary applies to all three executors.

In `@GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs`:
- Around line 264-289: RegisterLegacyBridgeHandlers currently uses string-based
reflection and Activator.CreateInstance for the six handler types
(LegacyCommandDispatchRequestHandler, LegacyCommandResultDispatchRequestHandler,
LegacyAsyncCommandDispatchRequestHandler,
LegacyAsyncCommandResultDispatchRequestHandler,
LegacyQueryDispatchRequestHandler, LegacyAsyncQueryDispatchRequestHandler),
which is brittle; add an InternalsVisibleTo("GFramework.Core.Tests") attribute
in GFramework.Core/Properties/AssemblyInfo.cs so the test assembly can access
internal types, then replace the reflection/Activator logic in
RegisterLegacyBridgeHandlers (in ArchitectureContextTests.cs) with direct
instantiation and container.RegisterPlurality(new
LegacyCommandDispatchRequestHandler()) etc. to get compile-time safety against
renames.

In `@GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs`:
- Around line 89-113: The test leaves the architecture initialized if any
assertion fails because await architecture.DestroyAsync() runs after
Assert.Multiple; wrap the assertion block in a try/finally (or
try/catch/finally) so that await architecture.DestroyAsync() is always executed
in the finally block; keep the existing LegacyBridgeArchitecture instantiation
and calls to InitializeAsync, SendQuery, and SendCommand, but move the cleanup
call (architecture.DestroyAsync()) into the finally to guarantee teardown even
on assertion failures.

In `@GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs`:
- Around line 11-41: The static field _invocationCount in
LegacyBridgePipelineTracker creates cross-test shared mutable state leading to
flaky parallel tests; update LegacyBridgePipelineTracker by adding a <remarks>
XML doc on the class describing its thread-safety (uses Volatile.Read/Write and
Interlocked.Increment) and lifecycle (process-wide counter used by tests), and
ensure all test fixtures (e.g., ArchitectureContextTests and
ArchitectureModulesBehaviorTests) call LegacyBridgePipelineTracker.Reset() in
their TearDown/OneTimeTearDown to deterministically clear state; also consider
documenting that InvocationCount is safe for concurrent reads/writes because
Record uses Interlocked and Reset uses Volatile.Write.

In `@GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequest.cs`:
- Around line 12-18: The null check in the auto-property initializer for Command
is unreachable because LegacyCqrsDispatchRequestBase's constructor already
throws for a null target; remove the "= command ?? throw new
ArgumentNullException(nameof(command))" initializer and instead assign the
parameter directly to the Command auto-property (or rely on the base check) so
you don't duplicate unreachable validation, and add the missing XML
documentation param tag for "command" on the LegacyAsyncCommandDispatchRequest
record-like declaration to match the fix applied in
LegacyCommandDispatchRequest.cs.

In `@GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequestHandler.cs`:
- Around line 15-22: Handle currently ignores the CancellationToken; mirror the
fix from LegacyAsyncQueryDispatchRequestHandler by calling
cancellationToken.ThrowIfCancellationRequested() before executing and awaiting
request.ExecuteAsync() with cancellation support via
.WaitAsync(cancellationToken); update
LegacyAsyncCommandResultDispatchRequestHandler.Handle (which calls
PrepareTarget(request.Target) and request.ExecuteAsync()) to await
request.ExecuteAsync().WaitAsync(cancellationToken) (and keep ConfigureAwait if
used) so the operation respects cancellation.

In `@GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequestHandler.cs`:
- Around line 15-22: The Handle method in LegacyAsyncQueryDispatchRequestHandler
ignores the CancellationToken; before awaiting request.ExecuteAsync() add a
cancellation check (e.g., cancellationToken.ThrowIfCancellationRequested()) and,
where appropriate, await request.ExecuteAsync().WaitAsync(cancellationToken) so
the caller's await can observe cancellation earlier (note this won't cancel the
underlying Task), and update any downstream calls (e.g., PrepareTarget or any
IAsyncQuery<T>.DoAsync() overloads if they can accept a token) to accept and
forward the cancellationToken; if downstream cannot accept a token, ensure you
poll/throw on cancellation before invoking them.

In `@GFramework.Core/Cqrs/LegacyCommandDispatchRequest.cs`:
- Around line 12-18: The Command property initializer in
LegacyCommandDispatchRequest contains an unreachable null-check and misleading
exception name because the base constructor
LegacyCqrsDispatchRequestBase(command) already throws for null (using "target");
remove the redundant "command ?? throw..." check from the Command get; instead
rely on the base validation (or, if you prefer derived-class validation, move
the null check into the LegacyCommandDispatchRequest primary constructor and
remove it from the base), and add a class-level XML <param name="command"> entry
to document the constructor parameter; refer to LegacyCommandDispatchRequest,
LegacyCqrsDispatchRequestBase, and the Command property when making the change.

In `@GFramework.Core/Cqrs/LegacyCommandResultDispatchRequest.cs`:
- Around line 11-14: Add XML documentation to the primary constructor of
LegacyCommandResultDispatchRequest: include a <summary> describing the purpose
of this constructor and add <param name="target"> and <param name="execute">
tags that explain the target object and the delegate used to execute the command
(mention nullability/behaviour if relevant); also add any applicable <returns>
or <remarks> if the constructor's behaviour warrants it. Locate the constructor
on the LegacyCommandResultDispatchRequest type and update its XML comments
accordingly.

In `@GFramework.Core/Cqrs/LegacyQueryDispatchRequest.cs`:
- Around line 16-19: The Execute() method on LegacyQueryDispatchRequest lacks a
<returns> XML doc tag; add an XML <returns> element to the Execute() method
summary that succinctly states it returns the boxed legacy query result
(object?), e.g. describe that it returns the boxed/nullable result of the
underlying legacy query produced by _execute(); update the XML comment above
public object? Execute() => _execute(); accordingly.

---

Outside diff comments:
In `@GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs`:
- Around line 35-40: TearDown currently clears GameContext and resets
TrackingPipelineBehavior<ModuleBehaviorRequest, string>.InvocationCount but
forgets to reset LegacyBridgePipelineTracker; update the TearDown method to also
reset the LegacyBridgePipelineTracker's count/state (the static counter or
relevant reset method on LegacyBridgePipelineTracker) so tests don't leak state
between runs.

In `@GFramework.Core/Services/Modules/AsyncQueryExecutorModule.cs`:
- Around line 33-40: 为 Register 方法补全 XML 文档:在现有 <summary> 和 <param> 之外加入
<exception> 标记说明当 container 为 null 时会抛出 ArgumentNullException,以及当无法解析
ICqrsRuntime 时可能抛出的 InvalidOperationException(或容器特定的解析异常);在 <remarks>
中说明该方法会从容器解析 ICqrsRuntime 并以多例/瞬态形式注册 AsyncQueryExecutor,强调调用方必须先在容器中注册
ICqrsRuntime(或等效运行时)以避免解析失败,并注明注册语义(多例/Transient)。

In `@GFramework.Core/Services/Modules/CommandExecutorModule.cs`:
- Around line 33-40: 为 Register(IIocContainer) 方法补充完整 XML
注释,说明方法行为、参数约束和可能抛出的异常:在 <summary> 里描述“将 CommandExecutor 注册为多例服务”;在 <param
name="container"> 中说明必须非空且实现 IIocContainer;新增 <exception
cref="ArgumentNullException"> 说明当 container 为 null 时会抛出(因内部使用
ArgumentNullException.ThrowIfNull);新增 <remarks> 或 <returns>(如适用)说明内部会通过
container.Get<ICqrsRuntime>() 获取依赖并因此要求容器能解析 ICqrsRuntime。确保引用的方法/类型名为 Register,
IIocContainer, CommandExecutor, ArgumentNullException.ThrowIfNull,
container.Get<ICqrsRuntime>() 以便在文档中清晰指出调用契约。

In `@GFramework.Core/Services/Modules/QueryExecutorModule.cs`:
- Around line 33-40: Update the XML documentation for
QueryExecutorModule.Register to include an <exception> that documents
ArgumentNullException thrown when the container is null and to explicitly state
that this method resolves an ICqrsRuntime from the container; in the <remarks>
describe the precondition that an ICqrsRuntime implementation must be registered
in the IIocContainer before calling Register (since the method constructs new
QueryExecutor(container.Get<ICqrsRuntime>()) and registers it via
container.RegisterPlurality). Ensure <summary> and <param name="container">
remain, and mention the behavior of creating and registering a QueryExecutor
instance.

---

Nitpick comments:
In `@GFramework.Core.Tests/Architectures/LegacyArchitectureBridgeCommand.cs`:
- Line 31: Add a using directive for the GFramework.Core.Abstractions.Rule
namespace at the top of the file so the cast in the ObservedContext assignment
can use the short interface name instead of the fully-qualified
GFramework.Core.Abstractions.Rule.IContextAware; update the code line using the
IContextAware symbol (the cast currently on ObservedContext =
((GFramework.Core.Abstractions.Rule.IContextAware)this).GetContext();) to rely
on the imported type for readability.

In `@GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs`:
- Around line 31-39: The current Record method misidentifies bridge requests by
string-matching requestType.Name for "Legacy", causing false positives; update
the detection to use a type-based check instead: after
ArgumentNullException.ThrowIfNull(requestType) replace the namespace+name string
condition with an assignability check against a dedicated marker/interface or
base class (e.g.
typeof(LegacyCqrsDispatchRequestBase).IsAssignableFrom(requestType) or an
ILegacyBridgeRequest marker), and only call Interlocked.Increment(ref
_invocationCount) when that type-based check succeeds so detection is robust and
accurate.

In `@GFramework.Core/Command/CommandExecutor.cs`:
- Around line 80-202: The helper TryResolveDispatchContext currently duplicates
null checks for _runtime and forces null-forgiving on usages; annotate
TryResolveDispatchContext with [MemberNotNullWhen(true, nameof(_runtime))]
(import System.Diagnostics.CodeAnalysis), adjust its signature/logic to assert
_runtime non-null when it returns true, then remove redundant "_runtime is not
null" guards in callers (SendAsync, SendAsync<TResult>,
TryExecuteThroughCqrsRuntime<TTarget,TRequest>,
TryExecuteThroughCqrsRuntime<TTarget,TResult,TRequest>) so each just calls
TryResolveDispatchContext(...) and uses _runtime without the null-forgiving
operator (e.g. remove _runtime! and simplify conditions to a single
TryResolveDispatchContext check).

In `@GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequest.cs`:
- Around line 8-11: Add XML documentation for the primary constructor parameters
and the ExecuteAsync method: update the class-level comment for
LegacyAsyncCommandResultDispatchRequest to include <param name="target">
describing the wrapped legacy command target and <param name="executeAsync">
describing the Func<Task<object?>> execution delegate, and add a <returns> tag
to the ExecuteAsync() method describing the returned Task<object?> (what the
task represents and nullability). Ensure the tags follow existing XML doc style
used in the file.

In `@GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequest.cs`:
- Around line 8-11: 为 LegacyAsyncQueryDispatchRequest 的主构造函数补充 XML 文档中的 <param>
标签,分别说明 target(被包装的目标对象或处理者)和 executeAsync(执行查询的委托,返回 Task<object?>)的含义;同时在
ExecuteAsync 方法的 XML 注释中添加 <returns>,明确返回值是 Task<object?>(表示异步查询结果或 null);参照
LegacyAsyncCommandResultDispatchRequest 的注释样式确保使用 <summary>、<param> 和 <returns>
并在注释中使用类名 LegacyAsyncQueryDispatchRequest 和方法名 ExecuteAsync 作为定位参考。

In `@GFramework.Core/Cqrs/LegacyCqrsDispatchHandlerBase.cs`:
- Around line 14-17: The PrepareTarget method is missing XML doc tags for its
parameter and possible exceptions; add <param name="target"> describing the
target object and when it must be non-null, and add <exception
cref="System.ArgumentNullException"> and <exception
cref="System.InvalidOperationException"> entries describing the conditions under
which each is thrown (null target and missing/invalid context respectively),
keeping the existing <summary> intact and following the project's XML-doc
guidelines; reference the PrepareTarget method and the IContextAware interface
in the comments to clarify the contract.

In `@GFramework.Core/Cqrs/LegacyCqrsDispatchRequestBase.cs`:
- Around line 6-9: The class XML docs for LegacyCqrsDispatchRequestBase(object
target) are missing a <param> entry for the primary constructor parameter;
update the class-level XML comment to include a <param name="target">...</param>
that briefly describes what the target represents (e.g., the wrapped legacy
command/query target object) so the internal abstract class
LegacyCqrsDispatchRequestBase and its constructor parameter `target` meet the
project's XML documentation requirements.

In `@GFramework.Core/Query/AsyncQueryExecutor.cs`:
- Around line 33-85: Add the nullable annotation to TryResolveDispatchContext so
the compiler knows _runtime is non-null when it returns true: annotate the
method with [MemberNotNullWhen(true, nameof(_runtime))] (import
System.Diagnostics.CodeAnalysis), keep its behavior, then remove the redundant
null-check "&& _runtime is not null" at the call site and drop the null-forcing
operator from _runtime! inside BridgeAsyncQueryAsync so calls use _runtime
directly (refer to TryResolveDispatchContext, BridgeAsyncQueryAsync, and the
_runtime field).

In `@GFramework.Core/Query/QueryExecutor.cs`:
- Around line 38-78: Add the nullable flow attribute to
TryResolveDispatchContext and remove the redundant check at the call site:
annotate the method TryResolveDispatchContext with [MemberNotNullWhen(true,
nameof(_runtime))] so the compiler knows that when it returns true _runtime is
non-null, then update the caller in the method that currently checks "if
(TryResolveDispatchContext(query, out var context) && _runtime is not null)" to
just "if (TryResolveDispatchContext(query, out var context))" (remove the &&
_runtime is not null) so the nullable analysis no longer requires the duplicate
null check.

In `@GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs`:
- Line 31: 将公有基准类 RequestLifetimeBenchmarks 标记为 sealed:在类声明处添加 sealed
关键字以阻止继承并与仓库中其它基准类/内嵌 Config 类保持一致,从而消除不必要的虚调用开销(修改类 RequestLifetimeBenchmarks
的声明即可)。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 911e6939-d992-4be9-a36a-850606ec4ce2

📥 Commits

Reviewing files that changed from the base of the PR and between 2c58d8b and d7293aa.

📒 Files selected for processing (38)
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs
  • GFramework.Core.Tests/Architectures/LegacyArchitectureBridgeAsyncQuery.cs
  • GFramework.Core.Tests/Architectures/LegacyArchitectureBridgeCommand.cs
  • GFramework.Core.Tests/Architectures/LegacyArchitectureBridgeCommandWithResult.cs
  • GFramework.Core.Tests/Architectures/LegacyArchitectureBridgeQuery.cs
  • GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs
  • GFramework.Core.Tests/Architectures/LegacyBridgeTrackingPipelineBehavior.cs
  • GFramework.Core/Architectures/ArchitectureContext.cs
  • GFramework.Core/Command/CommandExecutor.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyCommandDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyCommandDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyCommandResultDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyCommandResultDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHandlerBase.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchRequestBase.cs
  • GFramework.Core/Cqrs/LegacyQueryDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyQueryDispatchRequestHandler.cs
  • GFramework.Core/Query/AsyncQueryExecutor.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core/README.md
  • GFramework.Core/Services/Modules/AsyncQueryExecutorModule.cs
  • GFramework.Core/Services/Modules/CommandExecutorModule.cs
  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs
  • GFramework.Cqrs.Benchmarks/README.md
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
  • docs/zh-CN/core/command.md
  • docs/zh-CN/core/context.md
  • docs/zh-CN/core/cqrs.md
  • docs/zh-CN/core/query.md

Comment thread docs/zh-CN/core/command.md
Comment thread docs/zh-CN/core/context.md Outdated
Comment thread GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
Comment thread GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs
Comment thread GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequestHandler.cs
Comment thread GFramework.Core/Cqrs/LegacyCommandDispatchRequest.cs Outdated
Comment thread GFramework.Core/Cqrs/LegacyCommandResultDispatchRequest.cs
Comment thread GFramework.Core/Cqrs/LegacyQueryDispatchRequest.cs
@GeWuYou GeWuYou changed the title Feat/cqrs optimization Feat/Implement CQRS runtime integration for legacy compatibility May 7, 2026
- 修复 legacy bridge 测试装配与清理流程,改用 InternalsVisibleTo 和显式 handler 注册,补齐共享计数器重置与生命周期说明

- 优化 CommandExecutor、QueryExecutor 与相关模块的 runtime 契约,补充 XML 文档、nullable 注解和显式依赖解析

- 更新 legacy 异步 bridge 的取消语义、兼容文档回退边界以及 cqrs-rewrite active tracking/trace
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2305 2305 0 0 0 0 36.6s    ↓1.1s

Test Results

passed 2305 passed

Details

tests 2305 tests
clock 36.6s ↓1.1s
tool nunit
build CI - Build & Test arrow-right build-and-test link #1078
pull-request Feat/Implement CQRS runtime integration for legacy compatibility link #334

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2202 0 0 4.8s

build-and-test: Run #1078

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2305 2305 0 0 0 0 0 36.6s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
CreateStream_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 14 4.2s 4.8s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 29 2.1s 4.7s
Does_Not_Report_When_FieldInjectedModel_Is_Registered 29 2.2s 2.3s
Generates_Scene_Behavior_Boilerplate 29 1.9s 2.0s
CleanupDuringAcquire_Should_NotCauseRaceCondition 29 1.1s 1.1s
Append_ShouldNotBlock 29 1.0s 1.0s
Context_Caching_Should_Improve_Performance 29 783ms 795ms
PendingCount_ShouldReflectQueuedEntries 29 501ms 501ms
Cleanup_Should_NotRemoveActiveLocks 29 404ms 405ms
Cleanup_Should_RemoveUnusedLocks 29 401ms 402ms

± Comparison with run #1077 at 277d3a5 | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 29 runs.

Github Test Reporter by CTRF 💚

Comment thread GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequestHandler.cs
Comment thread GFramework.Core/Command/CommandExecutor.cs
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
GFramework.Core/Query/QueryExecutor.cs (1)

62-82: ⚡ Quick win

TryResolveDispatchContextCommandExecutor 中存在完全相同的副本

两个密封类各自维护一份逻辑完全相同的私有辅助方法,违反 DRY 原则。未来任一侧的改动(例如新增对 OperationCanceledException 的处理)都需要同步到另一处,存在静默漂移的风险。

建议提取为共享的静态辅助类,例如 LegacyCqrsDispatchHelper

♻️ 提取到共享静态辅助类
// GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
internal static class LegacyCqrsDispatchHelper
{
    /// <summary>解析 legacy 对象所绑定的架构上下文,供 CQRS runtime bridge 使用。</summary>
    [MemberNotNullWhen(true, "runtime")]  // 字符串形式,因为是静态方法参数而非成员
    internal static bool TryResolveDispatchContext(
        ICqrsRuntime? runtime,
        object target,
        out IArchitectureContext context)
    {
        context = null!;
        if (runtime is null || target is not IContextAware contextAware)
            return false;
        try
        {
            context = contextAware.GetContext();
            return true;
        }
        catch (InvalidOperationException)
        {
            return false;
        }
    }
}

然后在 QueryExecutorCommandExecutor 中统一调用:

-    [MemberNotNullWhen(true, nameof(_runtime))]
-    private bool TryResolveDispatchContext(object query, out IArchitectureContext context)
-    { ... }
+    // 委托给共享辅助方法
+    private bool TryResolveDispatchContext(object query, out IArchitectureContext context)
+        => LegacyCqrsDispatchHelper.TryResolveDispatchContext(_runtime, query, out context);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Query/QueryExecutor.cs` around lines 62 - 82, There are
duplicate private implementations of TryResolveDispatchContext in QueryExecutor
and CommandExecutor; extract the logic into a single internal static helper
(e.g., LegacyCqrsDispatchHelper) with a signature like
TryResolveDispatchContext(ICqrsRuntime? runtime, object target, out
IArchitectureContext context) and [MemberNotNullWhen(true, "runtime")] on the
method, move the try/catch and type check there, and replace the private methods
in QueryExecutor and CommandExecutor to call
LegacyCqrsDispatchHelper.TryResolveDispatchContext(runtime, queryOrCommand, out
context) so both classes share the same implementation.
GFramework.Core/Command/CommandExecutor.cs (1)

188-208: ⚡ Quick win

TryResolveDispatchContextQueryExecutor 中的私有辅助方法逻辑完全相同

两处实现逐行一致,存在同步漂移风险。此处与 QueryExecutor.cs 中提出的提取建议为同一根因,建议统一提取到 LegacyCqrsDispatchHelper 静态类中(详见 QueryExecutor.cs 的 review 注释)。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core/Command/CommandExecutor.cs` around lines 188 - 208, Extract
the duplicated logic in TryResolveDispatchContext from CommandExecutor.cs and
the identical helper in QueryExecutor.cs into a single static helper class
LegacyCqrsDispatchHelper with a method like TryResolveDispatchContext(object
target, object? runtime, out
GFramework.Core.Abstractions.Architectures.IArchitectureContext context);
implement the same behavior: set context = null!, return false if runtime is
null or target is not IContextAware, otherwise call
((IContextAware)target).GetContext() in a try/catch that returns false on
InvalidOperationException and true on success; then replace the private helpers
in CommandExecutor and QueryExecutor to call
LegacyCqrsDispatchHelper.TryResolveDispatchContext passing their _runtime and
target.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs`:
- Around line 149-160: The test relies on the shared static
LegacyBridgePipelineTracker.InvocationCount which causes race conditions when
tests run in parallel; to fix this, mark the test fixture (the class containing
SendQuery_Should_Bridge_Through_CqrsRuntime_And_Preserve_Context) with the NUnit
[NonParallelizable] attribute so the fixture runs sequentially; update the class
declaration that contains ArchitectureContextTests (and ensure the NUnit
attribute namespace is available) rather than changing the individual test,
leaving the existing TearDown Reset() in place.
- Around line 263-272: CreateFrozenBridgeContext currently instantiates a
MicrosoftDiContainer and wraps it in an ArchitectureContext without exposing or
disposing the container, leaking IDisposable registrations; modify the API so
the created container is owned and disposed by tests or ArchitectureContext:
either change CreateFrozenBridgeContext to return both the ArchitectureContext
and the underlying MicrosoftDiContainer (e.g., via an out parameter) so callers
can call Dispose on the container after the test, or update
ArchitectureContext's constructor to accept ownership and implement IDisposable
forwarding to dispose the inner MicrosoftDiContainer; update tests to acquire
the container (or rely on ArchitectureContext.Dispose) and ensure it's disposed
in a finally/TearDown block.

In `@GFramework.Core/Command/CommandExecutor.cs`:
- Around line 116-157: Both overloads TryExecuteThroughCqrsRuntime (the two
methods that call _runtime.SendAsync(...).AsTask().GetAwaiter().GetResult())
perform sync-over-async and risk deadlock under a SynchronizationContext; fix
both occurrences by either changing the ICqrsRuntime.SendAsync contract to
guarantee ConfigureAwait(false) is applied through the call chain, or wrap the
SendAsync call in Task.Run(...) and block on that task to isolate it from the
current SynchronizationContext (e.g., replace direct
.AsTask().GetAwaiter().GetResult() with Task.Run(() =>
_runtime.SendAsync(...).AsTask()).GetAwaiter().GetResult()); apply the same fix
to both TryExecuteThroughCqrsRuntime<TTarget,TRequest> and
TryExecuteThroughCqrsRuntime<TTarget,TResult,TRequest> to match the mitigation
used in QueryExecutor.

In `@GFramework.Core/Query/QueryExecutor.cs`:
- Line 49: The XML docs for the method in class QueryExecutor that returns
"(TResult)boxedResult!" must be expanded: update the <returns> to state the
method returns the unboxed TResult on success and add two <exception> tags
documenting that a NullReferenceException may be thrown when boxedResult is null
and TResult is a value type, and an InvalidCastException may be thrown when the
actual type of boxedResult cannot be cast to TResult; modify the XML comment
immediately above the method containing the cast to include these <returns> and
<exception> entries referencing QueryExecutor and that specific method.
- Around line 41-49: The current sync-over-async call in QueryExecutor (the call
to _runtime.SendAsync(...).AsTask().GetAwaiter().GetResult() that constructs
LegacyQueryDispatchRequest with query.Do()) can deadlock when a
SynchronizationContext is present; either update the XML <remarks> for
ICqrsRuntime to explicitly require all implementers and handlers to use
ConfigureAwait(false) throughout the async chain, or change QueryExecutor to
offload the blocking wait to the thread pool (e.g., wrap the async call in
Task.Run and await its result synchronously) to prevent capturing the caller's
sync context; locate the SendAsync usage in QueryExecutor and apply one of these
fixes, and also document the chosen contract on ICqrsRuntime and related handler
interfaces (mentioning ICqrsRuntime, QueryExecutor, LegacyQueryDispatchRequest,
and query.Do) so implementers are aware.

---

Nitpick comments:
In `@GFramework.Core/Command/CommandExecutor.cs`:
- Around line 188-208: Extract the duplicated logic in TryResolveDispatchContext
from CommandExecutor.cs and the identical helper in QueryExecutor.cs into a
single static helper class LegacyCqrsDispatchHelper with a method like
TryResolveDispatchContext(object target, object? runtime, out
GFramework.Core.Abstractions.Architectures.IArchitectureContext context);
implement the same behavior: set context = null!, return false if runtime is
null or target is not IContextAware, otherwise call
((IContextAware)target).GetContext() in a try/catch that returns false on
InvalidOperationException and true on success; then replace the private helpers
in CommandExecutor and QueryExecutor to call
LegacyCqrsDispatchHelper.TryResolveDispatchContext passing their _runtime and
target.

In `@GFramework.Core/Query/QueryExecutor.cs`:
- Around line 62-82: There are duplicate private implementations of
TryResolveDispatchContext in QueryExecutor and CommandExecutor; extract the
logic into a single internal static helper (e.g., LegacyCqrsDispatchHelper) with
a signature like TryResolveDispatchContext(ICqrsRuntime? runtime, object target,
out IArchitectureContext context) and [MemberNotNullWhen(true, "runtime")] on
the method, move the try/catch and type check there, and replace the private
methods in QueryExecutor and CommandExecutor to call
LegacyCqrsDispatchHelper.TryResolveDispatchContext(runtime, queryOrCommand, out
context) so both classes share the same implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7c094ef7-cd81-47b5-817f-b5d5129f4d75

📥 Commits

Reviewing files that changed from the base of the PR and between d7293aa and 6056159.

📒 Files selected for processing (24)
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs
  • GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs
  • GFramework.Core/Command/CommandExecutor.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyCommandDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyCommandResultDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHandlerBase.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchRequestBase.cs
  • GFramework.Core/Cqrs/LegacyQueryDispatchRequest.cs
  • GFramework.Core/Properties/AssemblyInfo.cs
  • GFramework.Core/Query/AsyncQueryExecutor.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core/Services/Modules/AsyncQueryExecutorModule.cs
  • GFramework.Core/Services/Modules/CommandExecutorModule.cs
  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
  • docs/zh-CN/core/command.md
  • docs/zh-CN/core/context.md
✅ Files skipped from review due to trivial changes (6)
  • GFramework.Core/Cqrs/LegacyCqrsDispatchRequestBase.cs
  • docs/zh-CN/core/context.md
  • GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequest.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequest.cs
  • GFramework.Core/Properties/AssemblyInfo.cs
🚧 Files skipped from review as they are similar to previous changes (12)
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHandlerBase.cs
  • GFramework.Core/Cqrs/LegacyCommandDispatchRequest.cs
  • GFramework.Core.Tests/Architectures/LegacyBridgePipelineTracker.cs
  • GFramework.Core/Services/Modules/AsyncQueryExecutorModule.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandResultDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyCommandResultDispatchRequest.cs
  • GFramework.Core/Services/Modules/CommandExecutorModule.cs
  • GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs
  • GFramework.Core/Cqrs/LegacyAsyncQueryDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyQueryDispatchRequest.cs
  • GFramework.Core/Query/AsyncQueryExecutor.cs
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (C#)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Apply [Log] attribute for automatic logging field and logging helper method generation
Apply [Priority] attribute for automatic priority comparison implementation generation
Apply [GenerateEnumExtensions] attribute to generate enumeration extension capabilities
Apply [ContextAware] attribute to automatically implement IContextAware boilerplate logic

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///) in C#
XML documentation MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable, and explain intent, contract, and usage constraints instead of restating syntax
If a C# member participates in lifecycle, threading, registration, or disposal behavior, document that behavior explicitly
Core framework components (Architecture, Module, System, Context, Registry, Service Module, Lifecycle types) MUST include high-level explanations of responsibilities, lifecycle, interaction with other components, why abstraction exists, and when to use instead of alternatives
Generated logic and source generator pipelines MUST explain what is generated, why it is generated, semantic assumptions the generator relies on, and any diagnostics or fallback behavior
Do not rely on implicit imports. Declare every required using explicitly in C#
Write null-safe code that respects nullable annotations instead of suppressing warnings by default in C#
Use namespace pattern GFramework.{Module}.{Feature} with PascalCase segments in C#
Follow standard C# naming: Types/methods/properties/events/constants use PascalCase, Interfaces use I prefix, Parameters and locals use camelCase, Private fields use _camelCase
Use Allman braces style for C#
Keep using directives at the top of the file and sort them consistently in C#
Prefer one primary type per file unless surrounding project already uses different local pattern
Prefer explicit, readable code over clever shorthand in framework internals
M...

Files:

  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*[!.]*

📄 CodeRabbit inference engine (AGENTS.md)

For files with shebang lines, keep shebang as first line and place license header immediately after it

Files:

  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core/Command/CommandExecutor.cs
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
  • docs/zh-CN/core/command.md
**/*.{cs,ts,tsx,js,jsx,py,sh}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{cs,ts,tsx,js,jsx,py,sh}: All generated or modified code MUST include clear and meaningful comments where required by documentation rules
Comments MUST NOT be trivial, redundant, or misleading. Prefer explaining why and when, not just what. Code should remain understandable without requiring external context
Avoid obvious comments such as // increment i

Files:

  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{cs,ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{cs,ts,tsx,js,jsx,py}: Add inline comments for non-trivial logic, concurrency/threading behavior, performance-sensitive paths, workarounds/compatibility constraints/edge cases, and registration order/lifecycle sequencing/generated code assumptions
Methods with non-trivial logic MUST document core idea, key decisions, and edge case handling
Separate logical blocks with blank lines when it improves readability
Unless there is clear and documented reason to keep file large, keep single source file under roughly 800-1000 lines
Validate external or user-controlled input before it reaches file system, serialization, reflection, code generation, or process boundaries
Do not build command strings, file paths, type names, or generated code from untrusted input without strict validation or allow-listing
Avoid logging secrets, tokens, credentials, or machine-specific sensitive data
Prefer least-privilege behavior for file, process, and environment access

Files:

  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{csproj,cs}

📄 CodeRabbit inference engine (AGENTS.md)

Framework runtime, abstractions, and meta-package projects MUST NOT reference *.SourceGenerators* projects or packages, and MUST NOT use source-generator attributes

Files:

  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{cs,ts,tsx,js,jsx,py,sh,xml,csproj,props,targets}

📄 CodeRabbit inference engine (AGENTS.md)

Use 4 spaces for indentation. Do not use tabs

Files:

  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{cs,ts,tsx,js,jsx,py,sh,xml}

📄 CodeRabbit inference engine (AGENTS.md)

Keep line length readable. Around 120 characters is preferred upper bound

Files:

  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{md,mdx}: Keep code samples, package names, and command examples aligned with current repository state in documentation
When public page references XML docs or API coverage, convert evidence into reader-facing guidance: explain which types/namespaces/entry points readers should inspect and why
For integration-oriented features such as AI-First config system, documentation MUST cover: project directory layout/file conventions, required project/package wiring, minimal working example, migration/compatibility notes
When examples are rewritten, preserve only parts that remain true. Delete or replace speculative examples instead of lightly editing into another inaccurate form

Files:

  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
  • docs/zh-CN/core/command.md
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Documentation should be organized with Chinese content in docs/zh-CN/ and structured to include getting started, module-specific capabilities (Core, Game, Godot, ECS), source generator usage, tutorials, best practices, and troubleshooting

Files:

  • docs/zh-CN/core/command.md
🧠 Learnings (1)
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.Core/Services/Modules/QueryExecutorModule.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core/Command/CommandExecutor.cs
🪛 LanguageTool
docs/zh-CN/core/command.md

[uncategorized] ~110-~110: 您的意思是“"不"上下文”?
Context: ...会回退到 legacy 直接执行;此时不会注入统一 pipeline,也不会额外补上下文桥接链路。 在 IContextAware 对象内,通常直接通过扩展...

(BU)

🔇 Additional comments (4)
GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs (1)

278-288: RegisterLegacyBridgeHandlers 已改为直接构造——解决了上一轮反馈的维护风险

之前通过字符串字面量反射实例化 handler 的脆弱做法已替换为类型安全的直接构造,重命名时可由编译器感知。

docs/zh-CN/core/command.md (1)

108-111: "发送入口"fallback 说明已补全——解决了上一轮反馈

Lines 108–110 现在清晰描述了标准路径走 ICqrsRuntime,以及直接 new CommandExecutor() 隔离场景下回退 legacy 直执行的行为与限制,与代码实现保持一致。

ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md (1)

5-35: RP-094 迁移追踪与本 PR 实际改动一致

追踪记录准确反映了本轮决策:直接构造 bridge handler、TearDown 清理、GetRequired<ICqrsRuntime>() 前置约束文档化,以及 [MemberNotNullWhen] 的引入。

GFramework.Core/Services/Modules/QueryExecutorModule.cs (1)

45-49: 注册顺序已正确保证。CqrsRuntimeModule 的 Priority 值为 15,低于 QueryExecutorModule 的 30,框架会确保 CqrsRuntimeModule 优先完成注册。因此 container.GetRequired<ICqrsRuntime>() 在注册阶段能安全获取依赖项,无需额外的错误处理或验证逻辑。XML 文档已清楚说明此约束。

Comment thread GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
Comment thread GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs Outdated
Comment thread GFramework.Core/Command/CommandExecutor.cs
Comment thread GFramework.Core/Query/QueryExecutor.cs Outdated
Comment thread GFramework.Core/Query/QueryExecutor.cs
- 修复 legacy 同步 bridge 的 runtime 等待方式,统一通过共享 helper 隔离同步上下文并收口重复 dispatch-context 解析逻辑

- 补充 legacy async command bridge 的取消可见性,并更新 ICqrsRuntime 与相关入口的契约说明

- 新增 bridge 回归测试并更新 cqrs-rewrite active tracking,覆盖同步上下文隔离、测试容器释放与取消语义
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2311    ↑6 2311    ↑6 0 0 0 0 38.7s    ↑2.1s

Test Results

passed 2311 passed ↑6

Details

tests 2311 tests ↑6
clock 38.7s ↑2.1s
tool nunit
build CI - Build & Test arrow-right build-and-test link #1079
pull-request Feat/Implement CQRS runtime integration for legacy compatibility link #334

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2205 0 0 4.8s

build-and-test: Run #1079

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2311 2311 0 0 0 0 0 38.7s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
CreateStream_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 15 4.2s 4.8s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 30 2.1s 4.7s
Does_Not_Report_When_FieldInjectedModel_Is_Registered 30 2.2s 2.3s
Generates_Scene_Behavior_Boilerplate 30 1.9s 2.0s
CleanupDuringAcquire_Should_NotCauseRaceCondition 30 1.1s 1.1s
Append_ShouldNotBlock 30 1.0s 1.0s
Context_Caching_Should_Improve_Performance 30 783ms 795ms
PendingCount_ShouldReflectQueuedEntries 30 501ms 501ms
Cleanup_Should_NotRemoveActiveLocks 30 404ms 405ms
Cleanup_Should_RemoveUnusedLocks 30 401ms 402ms

± Comparison with run #1078 at e9aad4a | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 30 runs.

Github Test Reporter by CTRF 💚

Comment thread GFramework.Core/Architectures/ArchitectureContext.cs
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 7, 2026
- 更新 active tracking 与 trace 到 RP-096,记录 latest-head review 的最新权威结论

- 补充 PR #334 当前 stale open thread、CI 测试与 MegaLinter 噪音的本地复核结果
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2311 2311 0 0 0 0 36.0s    ↓2.7s

Test Results

passed 2311 passed

Details

tests 2311 tests
clock 36.0s ↓2.7s
tool nunit
build CI - Build & Test arrow-right build-and-test link #1080
pull-request Feat/Implement CQRS runtime integration for legacy compatibility link #334

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2209 0 0 4.8s

build-and-test: Run #1080

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2311 2311 0 0 0 0 0 36.0s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
CreateStream_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 16 4.2s 4.8s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 31 2.0s 4.7s
Does_Not_Report_When_FieldInjectedModel_Is_Registered 31 2.2s 2.3s
Generates_Scene_Behavior_Boilerplate 31 1.9s 2.0s
CleanupDuringAcquire_Should_NotCauseRaceCondition 31 1.1s 1.1s
Append_ShouldNotBlock 31 1.0s 1.0s
Context_Caching_Should_Improve_Performance 31 783ms 795ms
PendingCount_ShouldReflectQueuedEntries 31 501ms 501ms
Cleanup_Should_NotRemoveActiveLocks 31 404ms 405ms
Cleanup_Should_RemoveUnusedLocks 31 401ms 402ms

± Comparison with run #1079 at 3fa3f2c | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 31 runs.

Github Test Reporter by CTRF 💚

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md (1)

100-103: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

建议将非当前锚点验证记录迁移到归档段落。

这里仍保留了“确认对应 PR #331”的记录,与当前活跃锚点 `PR `#334 并置,容易让“最近权威验证”被误读为多锚点状态。建议移动到历史归档或明确标注“历史验证”。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md` around
lines 100 - 103, The note listing verification for "PR `#331`" is mixing a
historical check with the active anchor "PR `#334`"; move the non-current anchor
verification line (the bullet containing `确认当前分支对应 PR `#331`` and its related
remarks) out of the active verification area into a clearly marked "历史归档" or
prepend an explicit "历史验证" label so the active anchor section only contains
items for PR `#334`; ensure the moved text preserves the original command context
(the `python3 .agents/...fetch_current_pr_review.py` bullet) and any
result/notes but is relocated to an archive subsection.
🧹 Nitpick comments (3)
GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs (1)

145-163: ⚡ Quick win

测试名声明“保留上下文”,但断言未覆盖该行为。

当前只校验了返回值与 request 类型,建议再补一条上下文保留断言(例如断言 query 的观测上下文或 runtime 记录的 context 等于 expectedContext),避免该回归点失守。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs` around lines 145 -
163, The test SendAsync_Should_Bridge_Through_Runtime_And_Preserve_Context
currently omits asserting that the context passed into
ContextAwareLegacyAsyncQuery is preserved; update the Assert.Multiple block to
include an assertion that the context on the dispatched request or the query's
observed context equals expectedContext (e.g., assert that
runtime.LastRequest.Context or whatever property RecordingCqrsRuntime records
matches expectedContext or that the ContextAwareLegacyAsyncQuery instance
reports expectedContext after SetContext); this ensures AsyncQueryExecutor and
RecordingCqrsRuntime actually preserve and forward the context.
GFramework.Core.Tests/Command/CommandExecutorTests.cs (1)

112-130: ⚡ Quick win

“保留上下文注入”应增加可观察断言。

该用例标题与注释都强调 context preservation,但目前仅验证返回值和请求类型。建议补充对上下文注入结果的断言,确保该行为有回归保护。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core.Tests/Command/CommandExecutorTests.cs` around lines 112 -
130, Add an assertion that verifies the context was actually preserved/passed
through: after calling executor.Send(command) assert that the runtime/dispatch
request captured by RecordingCqrsRuntime (inspect runtime.LastRequest or the
specific GFramework.Core.Cqrs.LegacyCommandResultDispatchRequest instance)
contains the same TestArchitectureContextBaseStub instance set via
((GFramework.Core.Abstractions.Rule.IContextAware)command).SetContext(expectedContext);
update the test
Send_WithResult_Should_Bridge_Through_Runtime_And_Preserve_Context to include
this context-equality/assertion so the context preservation behavior is covered.
GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs (1)

39-46: ⚡ Quick win

建议对响应解包增加显式类型校验,提升测试失败可诊断性。

当前直接强转在工厂返回类型不匹配时错误信息不够聚焦,建议先做 null/类型检查后抛出带上下文的异常。

可参考的最小改动
         object? response = request switch
         {
             IRequest<Unit> => Unit.Value,
             _ => _responseFactory(request)
         };
-
-        return ValueTask.FromResult((TResponse)response!);
+        if (response is null)
+        {
+            if (default(TResponse) is null)
+            {
+                return ValueTask.FromResult((TResponse)response!);
+            }
+
+            throw new InvalidOperationException(
+                $"RecordingCqrsRuntime 无法将 null 转换为值类型 {typeof(TResponse).FullName}。");
+        }
+
+        if (response is not TResponse typedResponse)
+        {
+            throw new InvalidOperationException(
+                $"RecordingCqrsRuntime 期望响应类型 {typeof(TResponse).FullName},实际为 {response.GetType().FullName}。");
+        }
+
+        return ValueTask.FromResult(typedResponse);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs` around lines 39 - 46,
The test runtime method in RecordingCqrsRuntime currently casts the factory
result directly ((TResponse)response!) which yields poor diagnostics on failure;
update the logic in the method that computes response (the switch returning
Unit.Value or _responseFactory(request)) to perform an explicit null and type
check before casting: if response is null throw an ArgumentNullException with
context (include request type and expected TResponse), if response is not
TResponse throw an InvalidCastException or custom InvalidOperationException with
a message that includes the request type, actual response type and expected
TResponse; use the symbols _responseFactory and the containing method in
RecordingCqrsRuntime to locate where to add these checks and then return
ValueTask.FromResult((TResponse)response) after validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md`:
- Around line 100-103: The note listing verification for "PR `#331`" is mixing a
historical check with the active anchor "PR `#334`"; move the non-current anchor
verification line (the bullet containing `确认当前分支对应 PR `#331`` and its related
remarks) out of the active verification area into a clearly marked "历史归档" or
prepend an explicit "历史验证" label so the active anchor section only contains
items for PR `#334`; ensure the moved text preserves the original command context
(the `python3 .agents/...fetch_current_pr_review.py` bullet) and any
result/notes but is relocated to an archive subsection.

---

Nitpick comments:
In `@GFramework.Core.Tests/Command/CommandExecutorTests.cs`:
- Around line 112-130: Add an assertion that verifies the context was actually
preserved/passed through: after calling executor.Send(command) assert that the
runtime/dispatch request captured by RecordingCqrsRuntime (inspect
runtime.LastRequest or the specific
GFramework.Core.Cqrs.LegacyCommandResultDispatchRequest instance) contains the
same TestArchitectureContextBaseStub instance set via
((GFramework.Core.Abstractions.Rule.IContextAware)command).SetContext(expectedContext);
update the test
Send_WithResult_Should_Bridge_Through_Runtime_And_Preserve_Context to include
this context-equality/assertion so the context preservation behavior is covered.

In `@GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs`:
- Around line 39-46: The test runtime method in RecordingCqrsRuntime currently
casts the factory result directly ((TResponse)response!) which yields poor
diagnostics on failure; update the logic in the method that computes response
(the switch returning Unit.Value or _responseFactory(request)) to perform an
explicit null and type check before casting: if response is null throw an
ArgumentNullException with context (include request type and expected
TResponse), if response is not TResponse throw an InvalidCastException or custom
InvalidOperationException with a message that includes the request type, actual
response type and expected TResponse; use the symbols _responseFactory and the
containing method in RecordingCqrsRuntime to locate where to add these checks
and then return ValueTask.FromResult((TResponse)response) after validation.

In `@GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs`:
- Around line 145-163: The test
SendAsync_Should_Bridge_Through_Runtime_And_Preserve_Context currently omits
asserting that the context passed into ContextAwareLegacyAsyncQuery is
preserved; update the Assert.Multiple block to include an assertion that the
context on the dispatched request or the query's observed context equals
expectedContext (e.g., assert that runtime.LastRequest.Context or whatever
property RecordingCqrsRuntime records matches expectedContext or that the
ContextAwareLegacyAsyncQuery instance reports expectedContext after SetContext);
this ensures AsyncQueryExecutor and RecordingCqrsRuntime actually preserve and
forward the context.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d1e5babd-708d-4b71-818c-08995ca5ee48

📥 Commits

Reviewing files that changed from the base of the PR and between 6056159 and cca4130.

📒 Files selected for processing (21)
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Command/ContextAwareLegacyCommand.cs
  • GFramework.Core.Tests/Command/ContextAwareLegacyCommandWithResult.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyAsyncQuery.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs
  • GFramework.Core.Tests/Query/QueryExecutorTests.cs
  • GFramework.Core/Architectures/ArchitectureContext.cs
  • GFramework.Core/Command/CommandExecutor.cs
  • GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequestHandler.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core/Query/AsyncQueryExecutor.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
✅ Files skipped from review due to trivial changes (3)
  • GFramework.Core.Tests/Command/ContextAwareLegacyCommandWithResult.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyAsyncQuery.cs
  • GFramework.Core.Tests/Command/ContextAwareLegacyCommand.cs
🚧 Files skipped from review as they are similar to previous changes (6)
  • GFramework.Core/Cqrs/LegacyAsyncCommandDispatchRequestHandler.cs
  • GFramework.Core/Query/QueryExecutor.cs
  • GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core/Query/AsyncQueryExecutor.cs
  • GFramework.Core/Architectures/ArchitectureContext.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (C#)
🧰 Additional context used
📓 Path-based instructions (10)
**/*Abstractions/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Abstractions projects should only contain interfaces and contract definitions without any runtime implementation logic

Files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
**/Cqrs/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Use CQRS (Command Query Responsibility Segregation) pattern with the Cqrs naming entry point instead of the historical Mediator alias

Files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Apply [Log] attribute for automatic logging field and logging helper method generation
Apply [Priority] attribute for automatic priority comparison implementation generation
Apply [GenerateEnumExtensions] attribute to generate enumeration extension capabilities
Apply [ContextAware] attribute to automatically implement IContextAware boilerplate logic

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///) in C#
XML documentation MUST use <summary>, <param>, <returns>, <exception>, and <remarks> where applicable, and explain intent, contract, and usage constraints instead of restating syntax
If a C# member participates in lifecycle, threading, registration, or disposal behavior, document that behavior explicitly
Core framework components (Architecture, Module, System, Context, Registry, Service Module, Lifecycle types) MUST include high-level explanations of responsibilities, lifecycle, interaction with other components, why abstraction exists, and when to use instead of alternatives
Generated logic and source generator pipelines MUST explain what is generated, why it is generated, semantic assumptions the generator relies on, and any diagnostics or fallback behavior
Do not rely on implicit imports. Declare every required using explicitly in C#
Write null-safe code that respects nullable annotations instead of suppressing warnings by default in C#
Use namespace pattern GFramework.{Module}.{Feature} with PascalCase segments in C#
Follow standard C# naming: Types/methods/properties/events/constants use PascalCase, Interfaces use I prefix, Parameters and locals use camelCase, Private fields use _camelCase
Use Allman braces style for C#
Keep using directives at the top of the file and sort them consistently in C#
Prefer one primary type per file unless surrounding project already uses different local pattern
Prefer explicit, readable code over clever shorthand in framework internals
M...

Files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs
  • GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Query/QueryExecutorTests.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*[!.]*

📄 CodeRabbit inference engine (AGENTS.md)

For files with shebang lines, keep shebang as first line and place license header immediately after it

Files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs
  • GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Query/QueryExecutorTests.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core/Command/CommandExecutor.cs
  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
**/*.{cs,ts,tsx,js,jsx,py,sh}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{cs,ts,tsx,js,jsx,py,sh}: All generated or modified code MUST include clear and meaningful comments where required by documentation rules
Comments MUST NOT be trivial, redundant, or misleading. Prefer explaining why and when, not just what. Code should remain understandable without requiring external context
Avoid obvious comments such as // increment i

Files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs
  • GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Query/QueryExecutorTests.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{cs,ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{cs,ts,tsx,js,jsx,py}: Add inline comments for non-trivial logic, concurrency/threading behavior, performance-sensitive paths, workarounds/compatibility constraints/edge cases, and registration order/lifecycle sequencing/generated code assumptions
Methods with non-trivial logic MUST document core idea, key decisions, and edge case handling
Separate logical blocks with blank lines when it improves readability
Unless there is clear and documented reason to keep file large, keep single source file under roughly 800-1000 lines
Validate external or user-controlled input before it reaches file system, serialization, reflection, code generation, or process boundaries
Do not build command strings, file paths, type names, or generated code from untrusted input without strict validation or allow-listing
Avoid logging secrets, tokens, credentials, or machine-specific sensitive data
Prefer least-privilege behavior for file, process, and environment access

Files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs
  • GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Query/QueryExecutorTests.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{csproj,cs}

📄 CodeRabbit inference engine (AGENTS.md)

Framework runtime, abstractions, and meta-package projects MUST NOT reference *.SourceGenerators* projects or packages, and MUST NOT use source-generator attributes

Files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs
  • GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Query/QueryExecutorTests.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{cs,ts,tsx,js,jsx,py,sh,xml,csproj,props,targets}

📄 CodeRabbit inference engine (AGENTS.md)

Use 4 spaces for indentation. Do not use tabs

Files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs
  • GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Query/QueryExecutorTests.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{cs,ts,tsx,js,jsx,py,sh,xml}

📄 CodeRabbit inference engine (AGENTS.md)

Keep line length readable. Around 120 characters is preferred upper bound

Files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs
  • GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Query/QueryExecutorTests.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core/Command/CommandExecutor.cs
**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{md,mdx}: Keep code samples, package names, and command examples aligned with current repository state in documentation
When public page references XML docs or API coverage, convert evidence into reader-facing guidance: explain which types/namespaces/entry points readers should inspect and why
For integration-oriented features such as AI-First config system, documentation MUST cover: project directory layout/file conventions, required project/package wiring, minimal working example, migration/compatibility notes
When examples are rewritten, preserve only parts that remain true. Delete or replace speculative examples instead of lightly editing into another inaccurate form

Files:

  • ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md
  • ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md
🧠 Learnings (1)
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs
  • GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs
  • GFramework.Core.Tests/Query/AsyncQueryExecutorTests.cs
  • GFramework.Core.Tests/Command/CommandExecutorTests.cs
  • GFramework.Core.Tests/Query/QueryExecutorTests.cs
  • GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
  • GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs
  • GFramework.Core.Tests/Command/RecordingCqrsRuntime.cs
  • GFramework.Core/Command/CommandExecutor.cs
🪛 LanguageTool
ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md

[grammar] ~48-~48: Ensure spelling is correct
Context: ...、QueryExecutor 的同步 CQRS/legacy bridge 入口不再直接在调用线程上阻塞 SendAsync(...).GetAwaiter().GetResult() - GFramework.Core.Tests 现通过 `InternalsVisibleTo("GFramework.Core.Te...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md

[grammar] ~5-~5: Ensure spelling is correct
Context: ... 2026-05-07 ### 阶段:PR #334 latest-head review 复核(CQRS-REWRITE-RP-096) - 再次使用 `$gframework-pr...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~22-~22: Ensure spelling is correct
Context: ...## 阶段:PR #334 legacy bridge sync follow-up(CQRS-REWRITE-RP-095) - 再次使用 `$gframework-pr...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~30-~30: Ensure spelling is correct
Context: ... bridge 对 ICqrsRuntime.SendAsync(...) 的线程池隔离等待 - 将 QueryExecutorCommandExecutor、`Asyn...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~31-~31: Ensure spelling is correct
Context: ...elper,并把 ArchitectureContext 的同步 CQRS 包装入口一并切换到同一阻塞策略,避免留下半修状态 - 为 ICqrsRuntime.SendAsync(...) 补充 ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (7)
GFramework.Core.Tests/Command/TestLegacySynchronizationContext.cs (1)

6-11: 实现清晰,符合测试占位用途。

该占位 SynchronizationContext 类型足够轻量,且注释说明了使用场景。

GFramework.Core.Tests/Query/ContextAwareLegacyQuery.cs (1)

13-25: 测试替身设计合理。

通过 ObservedContext 暴露执行期上下文,能有效支撑 bridge 上下文注入断言。

GFramework.Core.Tests/Cqrs/LegacyAsyncCommandDispatchRequestHandlerTests.cs (1)

21-61: 取消语义回归覆盖到位。

两条用例分别锁定“执行前取消”和“执行中取消”,对 bridge handler 的行为约束很有价值。

GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs (1)

31-34: 契约备注补充准确。

把 legacy 同步入口的等待策略与 SynchronizationContext 约束写进接口文档,能减少实现偏差。

GFramework.Core.Tests/Query/QueryExecutorTests.cs (1)

67-98: 测试对同步桥接行为的回归保护很完整。

这里同时验证了返回值、runtime 请求类型、以及 SynchronizationContext 未被复用,覆盖点准确。

GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs (1)

12-19: 同步桥接辅助的设计与文档说明一致,落地清晰。

上下文解析与同步等待策略职责划分明确,便于在 legacy 入口复用统一 pipeline。

Also applies to: 63-93

GFramework.Core/Command/CommandExecutor.cs (1)

38-67: runtime 桥接与 legacy 回退的执行路径拆分得很干净。

同步/异步两条链路都先尝试统一 runtime,再安全回退 legacy,整体可维护性和兼容性都不错。

Also applies to: 79-107, 110-185

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 7, 2026
Comment thread GFramework.Core/Cqrs/LegacyCqrsDispatchHelper.cs
Comment thread GFramework.Core/Services/Modules/CommandExecutorModule.cs
- 补充 AsyncQueryExecutor 与 CommandExecutor bridge 测试的上下文保留断言

- 优化 RecordingCqrsRuntime 的 bridge 执行模拟与响应类型诊断

- 更新 cqrs-rewrite active tracking 与 trace 的 RP-097 验证记录
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 7, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2311 2311 0 0 0 0 37.5s    ↑1.5s

Test Results

passed 2311 passed

Details

tests 2311 tests
clock 37.5s ↑1.5s
tool nunit
build CI - Build & Test arrow-right build-and-test link #1081
pull-request Feat/Implement CQRS runtime integration for legacy compatibility link #334

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2212 0 0 4.8s

build-and-test: Run #1081

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2311 2311 0 0 0 0 0 37.5s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
CreateStream_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 17 4.1s 4.8s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 32 1.9s 4.7s
Does_Not_Report_When_FieldInjectedModel_Is_Registered 32 2.2s 2.3s
Generates_Scene_Behavior_Boilerplate 32 1.9s 2.0s
CleanupDuringAcquire_Should_NotCauseRaceCondition 32 1.1s 1.1s
Append_ShouldNotBlock 32 1.0s 1.0s
Context_Caching_Should_Improve_Performance 32 783ms 795ms
PendingCount_ShouldReflectQueuedEntries 32 501ms 501ms
Cleanup_Should_NotRemoveActiveLocks 32 404ms 405ms
Cleanup_Should_RemoveUnusedLocks 32 401ms 402ms

± Comparison with run #1080 at 006fbd4 | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 32 runs.

Github Test Reporter by CTRF 💚

- 修复 LegacyCqrsDispatchHelper 仅在上下文缺失时回退,避免吞掉真实 InvalidOperationException

- 补充 CommandExecutor 与 QueryExecutor 相关回归测试,覆盖 fallback 与异常冒泡语义

- 更新 cqrs-rewrite 跟踪与追踪文档,记录 PR #334 本轮复核与验证结果
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2313    ↑2 2313    ↑2 0 0 0 0 37.4s    ↓145ms

Test Results

passed 2313 passed ↑2

Details

tests 2313 tests ↑2
clock 37.4s ↓145ms
tool nunit
build CI - Build & Test arrow-right build-and-test link #1082
pull-request Feat/Implement CQRS runtime integration for legacy compatibility link #334

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2215 0 0 4.8s

build-and-test: Run #1082

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
2313 2313 0 0 0 0 0 37.4s

🎉 All tests passed!

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
CreateStream_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 18 4.1s 4.8s
SendRequestAsync_Should_ResolveCqrsRuntime_OnlyOnce_When_AccessedConcurrently 33 1.9s 4.7s
Does_Not_Report_When_FieldInjectedModel_Is_Registered 33 2.2s 2.3s
Generates_Scene_Behavior_Boilerplate 33 1.9s 2.0s
CleanupDuringAcquire_Should_NotCauseRaceCondition 33 1.1s 1.1s
Append_ShouldNotBlock 33 1.0s 1.0s
Context_Caching_Should_Improve_Performance 33 783ms 795ms
PendingCount_ShouldReflectQueuedEntries 33 501ms 501ms
Cleanup_Should_NotRemoveActiveLocks 33 404ms 405ms
Cleanup_Should_RemoveUnusedLocks 33 401ms 402ms

± Comparison with run #1081 at 78f0ca6 | 🎉 No failed tests detected across all runs. | 🍂 No flaky tests detected across all runs. | ⏱️ Measured over 33 runs.

Github Test Reporter by CTRF 💚

@GeWuYou GeWuYou merged commit 54b79d9 into main May 7, 2026
7 checks passed
@GeWuYou GeWuYou deleted the feat/cqrs-optimization branch May 7, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant