From 0ac53a4ceec23a80ffd8b8a6b9a1841f6e9a41bf Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Mon, 4 May 2026 18:49:26 +0800 Subject: [PATCH 1/7] =?UTF-8?q?test(cqrs):=20=E8=A1=A5=E9=BD=90=20request?= =?UTF-8?q?=20invoker=20=E5=90=88=E5=90=8C=E5=9B=9E=E5=BD=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 request invoker descriptor 缺失时的 generator 回归覆盖 - 新增 request invoker descriptor entry 缺失时的 generator 回归覆盖 - 更新 CQRS 恢复文档与本轮验证记录 --- ...HandlerRegistryGenerator.SourceEmission.cs | 8 +-- .../Cqrs/CqrsHandlerRegistryGeneratorTests.cs | 52 +++++++++++++++++++ .../todos/cqrs-rewrite-migration-tracking.md | 15 ++++-- .../traces/cqrs-rewrite-migration-trace.md | 32 ++++++++++++ 4 files changed, 99 insertions(+), 8 deletions(-) diff --git a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.SourceEmission.cs b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.SourceEmission.cs index 80926f1b..0bc762fb 100644 --- a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.SourceEmission.cs +++ b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.SourceEmission.cs @@ -79,8 +79,8 @@ public sealed partial class CqrsHandlerRegistryGenerator /// 从可直接表达 handler 接口的注册描述中提取 request invoker 发射计划。 /// /// - /// 指示当前 runtime 是否同时暴露 ICqrsRequestInvokerProvider 与 - /// IEnumeratesCqrsRequestInvokerDescriptors 契约;若不支持,则本方法必须返回空结果并让后续发射路径整体跳过。 + /// 指示当前 runtime 是否完整暴露 request invoker provider、descriptor 与 descriptor entry 契约; + /// 若不支持,则本方法必须返回空结果并让后续发射路径整体跳过。 /// /// 已按稳定顺序整理完成的 handler 注册描述。 /// @@ -136,8 +136,8 @@ public sealed partial class CqrsHandlerRegistryGenerator /// 从可直接表达 handler 接口的注册描述中提取 stream invoker 发射计划。 /// /// - /// 指示当前 runtime 是否同时暴露 ICqrsStreamInvokerProvider 与 - /// IEnumeratesCqrsStreamInvokerDescriptors 契约;若不支持,则本方法必须返回空结果并让后续发射路径整体跳过。 + /// 指示当前 runtime 是否完整暴露 stream invoker provider、descriptor 与 descriptor entry 契约; + /// 若不支持,则本方法必须返回空结果并让后续发射路径整体跳过。 /// /// 已按稳定顺序整理完成的 handler 注册描述。 /// diff --git a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs index 77185834..ce391657 100644 --- a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs +++ b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs @@ -2998,6 +2998,58 @@ public class CqrsHandlerRegistryGeneratorTests }); } + /// + /// 验证当 runtime 缺少 CqrsRequestInvokerDescriptor 时, + /// 生成器不会继续发射依赖描述符类型的 request provider 元数据。 + /// + [Test] + public void Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Type() + { + var source = RenameTypeIdentifier( + RequestInvokerProviderSource, + "CqrsRequestInvokerDescriptor", + "MissingCqrsRequestInvokerDescriptor"); + var generatedSource = RunGenerator(source); + + Assert.Multiple(() => + { + Assert.That( + generatedSource, + Does.Contain( + "internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry")); + Assert.That(generatedSource, Does.Not.Contain("ICqrsRequestInvokerProvider")); + Assert.That(generatedSource, Does.Not.Contain("IEnumeratesCqrsRequestInvokerDescriptors")); + Assert.That(generatedSource, Does.Not.Contain("CqrsRequestInvokerDescriptorEntry(")); + Assert.That(generatedSource, Does.Not.Contain("InvokeRequestHandler0")); + }); + } + + /// + /// 验证当 runtime 缺少 CqrsRequestInvokerDescriptorEntry 时, + /// 生成器不会继续保留 request provider 的枚举接口或静态 invoker 元数据。 + /// + [Test] + public void Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Entry_Type() + { + var source = RenameTypeIdentifier( + RequestInvokerProviderSource, + "CqrsRequestInvokerDescriptorEntry", + "MissingCqrsRequestInvokerDescriptorEntry"); + var generatedSource = RunGenerator(source); + + Assert.Multiple(() => + { + Assert.That( + generatedSource, + Does.Contain( + "internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry")); + Assert.That(generatedSource, Does.Not.Contain("ICqrsRequestInvokerProvider")); + Assert.That(generatedSource, Does.Not.Contain("IEnumeratesCqrsRequestInvokerDescriptors")); + Assert.That(generatedSource, Does.Not.Contain("CqrsRequestInvokerDescriptorEntry(")); + Assert.That(generatedSource, Does.Not.Contain("InvokeRequestHandler0")); + }); + } + /// /// 验证当 request handler 仍需走 precise reflected 注册时, /// 生成器即使检测到 request invoker provider runtime 合同,也不会错误发射无法稳定表达隐藏请求/响应类型的 provider 元数据。 diff --git a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md index fff5461f..1ceb403a 100644 --- a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md +++ b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md @@ -7,13 +7,13 @@ CQRS 迁移与收敛。 ## 当前恢复点 -- 恢复点编号:`CQRS-REWRITE-RP-076` +- 恢复点编号:`CQRS-REWRITE-RP-077` - 当前阶段:`Phase 8` - 当前 PR 锚点:`PR #307` - 当前结论: - `GFramework.Cqrs` 已完成对外部 `Mediator` 的生产级替代,当前主线已从“是否可替代”转向“仓库内部收口与能力深化顺序” - - `dispatch/invoker` 生成前移已扩展到 request / stream 路径,当前 `RP-076` 已补齐 stream invoker provider gate 的四项 runtime 合同分支 - - `ai-plan` active 入口现以 `PR #307` 和 `RP-076` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 + - `dispatch/invoker` 生成前移已扩展到 request / stream 路径,当前 `RP-077` 已补齐 request invoker provider gate 与 stream gate 对称的 descriptor / descriptor entry runtime 合同回归 + - `ai-plan` active 入口现以 `PR #307` 和 `RP-077` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 ## 当前活跃事实 @@ -37,11 +37,18 @@ CQRS 迁移与收敛。 - 结果:通过,`0 warning / 0 error` - `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Entry_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"` - 结果:通过,`5/5` passed +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Entry_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Enumerator"` + - 结果:通过,`4/4` passed +- `dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release` + - 结果:通过,`0 warning / 0 error` +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行,避免脚本内部 plain `git ls-files` 误判仓库上下文 ## 下一推荐步骤 1. 继续处理 `PR #307` 的剩余 review 收尾,优先保持 `ai-plan` active 入口与 trace 的单一锚点一致 -2. 若继续推进代码切片,优先复核 request 侧是否存在与 stream gate 对称的生成合同遗漏,再决定是否补同批 generator 回归 +2. 若继续推进代码切片,优先复核 request / stream invoker provider runtime 合同以外是否还有同类对称测试缺口 3. 在进入下一批 runtime / generator 收敛前,保持最小 Release build 或 targeted test 作为权威验证 ## 活跃文档 diff --git a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md index b46a73ea..7b5950db 100644 --- a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md +++ b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md @@ -30,3 +30,35 @@ 1. 继续按 `PR #307` 的 latest-head review 收尾,优先保持 active tracking 与 active trace 的单一锚点一致 2. 若继续推进代码切片,先复核 request 侧是否仍存在与 stream invoker gate 对称的生成合同遗漏 3. 进入下一批前继续使用最小 Release build 或 targeted test 作为权威验证,避免把环境噪音误判为代码问题 + +## 2026-05-04 + +### 阶段:request invoker provider gate 对称回归(CQRS-REWRITE-RP-077) + +- 使用 `$gframework-batch-boot 25` 继续 `feat/cqrs-optimization` 的 CQRS 收口批次 +- 批次目标:在 branch diff 相对 `origin/main` 接近 `25` 个文件前,补齐低风险的 generator 合同回归切片 +- 本轮先确认当前 worktree 已无 `local-plan` 遗留恢复入口,随后转入 `cqrs-rewrite` 的 request / stream invoker provider gate 对称性复核 +- 结论: + - 生产代码已经同时检查 request provider、enumerator、descriptor 与 descriptor entry 四项 runtime 合同 + - request 侧测试只覆盖缺少 provider / enumerator,缺少 descriptor / descriptor entry 的回归覆盖落后于 stream 侧 +- 已补齐: + - `Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Type` + - `Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Entry_Type` + - source emission XML 文档同步说明 provider gate 依赖完整 descriptor / descriptor entry 合同 + +### 验证(RP-077) + +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Entry_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Enumerator"` + - 结果:通过,`4/4` passed +- `dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release` + - 结果:通过,`0 warning / 0 error` +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行,避免脚本内部 plain `git ls-files` 误判仓库上下文 +- `git diff --check` + - 结果:通过 + +### 当前下一步(RP-077) + +1. 继续使用 `origin/main` 作为 `$gframework-batch-boot 25` 的基线,复算 branch diff 后决定是否还能接下一批 +2. 若继续推进代码切片,优先查找 request / stream invoker provider runtime 合同之外的同类对称测试缺口 From 857ce08edba60f12c0e1ce008b7588beb7533a58 Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Mon, 4 May 2026 18:55:04 +0800 Subject: [PATCH 2/7] =?UTF-8?q?test(cqrs):=20=E8=A1=A5=E9=BD=90=20fallback?= =?UTF-8?q?=20=E5=85=83=E6=95=B0=E6=8D=AE=E5=9B=9E=E5=BD=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 mixed fallback 禁用多实例 attribute 时的字符串回退覆盖 - 补充 runtime AttributeUsage 变体测试辅助方法 - 更新 CQRS 恢复文档与本轮验证记录 --- .../Cqrs/CqrsHandlerRegistryGeneratorTests.cs | 85 +++++++++++++++++++ .../todos/cqrs-rewrite-migration-tracking.md | 16 +++- .../traces/cqrs-rewrite-migration-trace.md | 25 ++++++ 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs index ce391657..d5653dc3 100644 --- a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs +++ b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs @@ -2870,6 +2870,50 @@ public class CqrsHandlerRegistryGeneratorTests }); } + /// + /// 验证当 runtime 同时支持直接 与字符串 fallback 元数据、但不允许多个 fallback 特性实例时, + /// mixed 场景会整体回退到单个字符串特性,避免生成会违反 runtime attribute usage 的多实例元数据。 + /// + [Test] + public void + Emits_String_Fallback_Metadata_For_Mixed_Fallback_When_Runtime_Disallows_Multiple_Fallback_Attributes() + { + var source = ReplaceAttributeUsageForType( + AssemblyLevelMixedFallbackMetadataSource, + "CqrsReflectionFallbackAttribute", + "[AttributeUsage(AttributeTargets.Assembly)]"); + var execution = ExecuteGenerator( + source, + allowUnsafe: true); + var inputCompilationErrors = execution.InputCompilationDiagnostics + .Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) + .ToArray(); + var generatedCompilationErrors = execution.GeneratedCompilationDiagnostics + .Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) + .ToArray(); + var generatorErrors = execution.GeneratorDiagnostics + .Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) + .ToArray(); + Assert.Multiple(() => + { + Assert.That(inputCompilationErrors.Select(static diagnostic => diagnostic.Id), Does.Contain("CS0306")); + Assert.That(generatedCompilationErrors, Is.Empty); + Assert.That(generatorErrors, Is.Empty); + Assert.That(execution.GeneratedSources, Has.Length.EqualTo(1)); + var generatedSource = execution.GeneratedSources[0].content; + Assert.That( + generatedSource, + Does.Contain( + "[assembly: global::GFramework.Cqrs.CqrsReflectionFallbackAttribute(\"TestApp.Container+AlphaHandler\", \"TestApp.Container+BetaHandler\")]")); + Assert.That(generatedSource, Does.Not.Contain("CqrsReflectionFallbackAttribute(typeof(")); + Assert.That( + CountOccurrences( + generatedSource, + "[assembly: global::GFramework.Cqrs.CqrsReflectionFallbackAttribute"), + Is.EqualTo(1)); + }); + } + /// /// 验证当 runtime 暴露 request invoker provider 契约时,生成器会让 generated registry 同时发射 /// request invoker 描述符与对应的开放静态 invoker 方法。 @@ -3425,6 +3469,47 @@ public class CqrsHandlerRegistryGeneratorTests return !char.IsLetterOrDigit(character) && character != '_'; } + /// + /// 替换指定测试类型紧邻的 AttributeUsage 声明,用于构造 runtime contract 的 attribute usage 变体。 + /// + /// 原始测试源码。 + /// 需要定位的类型名。 + /// 替换后的完整 AttributeUsage 声明。 + /// 完成 attribute usage 替换后的源码。 + private static string ReplaceAttributeUsageForType( + string source, + string typeName, + string replacementAttributeUsage) + { + ArgumentNullException.ThrowIfNull(source); + ArgumentNullException.ThrowIfNull(typeName); + ArgumentNullException.ThrowIfNull(replacementAttributeUsage); + + var typeIndex = source.IndexOf($"public sealed class {typeName}", StringComparison.Ordinal); + if (typeIndex < 0) + { + throw new InvalidOperationException("The requested type declaration was not found in the generator test input."); + } + + const string attributeUsagePrefix = "[AttributeUsage("; + var attributeUsageStartIndex = source.LastIndexOf(attributeUsagePrefix, typeIndex, StringComparison.Ordinal); + if (attributeUsageStartIndex < 0) + { + throw new InvalidOperationException("The requested AttributeUsage declaration was not found in the generator test input."); + } + + var attributeUsageEndIndex = source.IndexOf(']', attributeUsageStartIndex); + if (attributeUsageEndIndex < 0 || attributeUsageEndIndex > typeIndex) + { + throw new InvalidOperationException("The requested AttributeUsage declaration is malformed."); + } + + return source.Remove( + attributeUsageStartIndex, + attributeUsageEndIndex - attributeUsageStartIndex + 1) + .Insert(attributeUsageStartIndex, replacementAttributeUsage); + } + /// /// 统计生成源码中某个固定片段的出现次数,用于锁定程序集级 fallback 特性的发射个数。 /// diff --git a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md index 1ceb403a..dddc1be6 100644 --- a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md +++ b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md @@ -7,13 +7,14 @@ CQRS 迁移与收敛。 ## 当前恢复点 -- 恢复点编号:`CQRS-REWRITE-RP-077` +- 恢复点编号:`CQRS-REWRITE-RP-078` - 当前阶段:`Phase 8` - 当前 PR 锚点:`PR #307` - 当前结论: - `GFramework.Cqrs` 已完成对外部 `Mediator` 的生产级替代,当前主线已从“是否可替代”转向“仓库内部收口与能力深化顺序” - - `dispatch/invoker` 生成前移已扩展到 request / stream 路径,当前 `RP-077` 已补齐 request invoker provider gate 与 stream gate 对称的 descriptor / descriptor entry runtime 合同回归 - - `ai-plan` active 入口现以 `PR #307` 和 `RP-077` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 + - `dispatch/invoker` 生成前移已扩展到 request / stream 路径,`RP-077` 已补齐 request invoker provider gate 与 stream gate 对称的 descriptor / descriptor entry runtime 合同回归 + - 当前 `RP-078` 已补齐 mixed fallback metadata 在 runtime 不允许多个 fallback attribute 实例时的单字符串 attribute 回退回归 + - `ai-plan` active 入口现以 `PR #307` 和 `RP-078` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 ## 当前活跃事实 @@ -44,11 +45,18 @@ CQRS 迁移与收敛。 - `python3 scripts/license-header.py --check` - 结果:通过 - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行,避免脚本内部 plain `git ls-files` 误判仓库上下文 +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_String_Fallback_Metadata_For_Mixed_Fallback_When_Runtime_Disallows_Multiple_Fallback_Attributes"` + - 结果:通过,`1/1` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 ## 下一推荐步骤 1. 继续处理 `PR #307` 的剩余 review 收尾,优先保持 `ai-plan` active 入口与 trace 的单一锚点一致 -2. 若继续推进代码切片,优先复核 request / stream invoker provider runtime 合同以外是否还有同类对称测试缺口 +2. 若继续推进代码切片,优先复核 fallback metadata 与 generated invoker provider 之外是否还有同类 runtime contract gate 回归缺口 3. 在进入下一批 runtime / generator 收敛前,保持最小 Release build 或 targeted test 作为权威验证 ## 活跃文档 diff --git a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md index 7b5950db..c617dcae 100644 --- a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md +++ b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md @@ -62,3 +62,28 @@ 1. 继续使用 `origin/main` 作为 `$gframework-batch-boot 25` 的基线,复算 branch diff 后决定是否还能接下一批 2. 若继续推进代码切片,优先查找 request / stream invoker provider runtime 合同之外的同类对称测试缺口 + +### 阶段:mixed fallback attribute usage 回归(CQRS-REWRITE-RP-078) + +- 继续沿用 `$gframework-batch-boot 25`,当前 branch diff 仍低于阈值 +- 复核 fallback metadata runtime contract 后确认: + - mixed fallback 在 runtime 允许多个 fallback attribute 实例时已有直接 `Type` + 字符串拆分回归 + - runtime 同时支持 `params Type[]` / `params string[]` 但不允许多个 fallback attribute 实例时,缺少锁定“整体回退到单个字符串 attribute”的回归 +- 已补齐: + - `Emits_String_Fallback_Metadata_For_Mixed_Fallback_When_Runtime_Disallows_Multiple_Fallback_Attributes` + - `ReplaceAttributeUsageForType` 测试辅助方法,用于构造 runtime attribute usage 变体而不复制大型 source fixture + +### 验证(RP-078) + +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_String_Fallback_Metadata_For_Mixed_Fallback_When_Runtime_Disallows_Multiple_Fallback_Attributes"` + - 结果:通过,`1/1` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 + +### 当前下一步(RP-078) + +1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 +2. 下一批优先查看 fallback metadata 与 generated invoker provider 之外是否还有同类 runtime contract gate 回归缺口 From e17fa15a01300a4ccfed13f8a91224dd99a105e2 Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Mon, 4 May 2026 19:01:47 +0800 Subject: [PATCH 3/7] =?UTF-8?q?test(cqrs):=20=E8=A1=A5=E9=BD=90=20registry?= =?UTF-8?q?=20gate=20=E5=9B=9E=E5=BD=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增缺少 ICqrsHandlerRegistry 时的 generator 静默跳过覆盖 - 更新 CQRS 恢复文档与本轮验证记录 --- .../Cqrs/CqrsHandlerRegistryGeneratorTests.cs | 31 +++++++++++++++++++ .../todos/cqrs-rewrite-migration-tracking.md | 16 +++++++--- .../traces/cqrs-rewrite-migration-trace.md | 22 +++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs index d5653dc3..5cdb81ea 100644 --- a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs +++ b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs @@ -2332,6 +2332,37 @@ public class CqrsHandlerRegistryGeneratorTests ("CqrsHandlerRegistry.g.cs", AssemblyLevelCqrsHandlerRegistryExpected)); } + /// + /// 验证当 runtime 缺少 generated registry 需要实现的基础注册接口时, + /// 生成器会整体跳过发射,避免产出无法承载运行时注册合同的半成品源码。 + /// + [Test] + public void Does_Not_Generate_Registry_When_Runtime_Lacks_Handler_Registry_Interface() + { + var source = RemoveBlock( + HiddenNestedHandlerSelfRegistrationSource, + "public interface ICqrsHandlerRegistry", + "[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]"); + var execution = ExecuteGenerator(source); + var inputCompilationErrors = execution.InputCompilationDiagnostics + .Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) + .ToArray(); + var generatedCompilationErrors = execution.GeneratedCompilationDiagnostics + .Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) + .ToArray(); + var generatorErrors = execution.GeneratorDiagnostics + .Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(inputCompilationErrors, Is.Empty); + Assert.That(generatedCompilationErrors, Is.Empty); + Assert.That(generatorErrors, Is.Empty); + Assert.That(execution.GeneratedSources, Is.Empty); + }); + } + /// /// 验证当程序集包含生成代码无法合法引用的私有嵌套处理器时,生成器会在生成注册器内部执行定向反射注册, /// 不再依赖程序集级 fallback marker。 diff --git a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md index dddc1be6..5dd0cdfe 100644 --- a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md +++ b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md @@ -7,14 +7,15 @@ CQRS 迁移与收敛。 ## 当前恢复点 -- 恢复点编号:`CQRS-REWRITE-RP-078` +- 恢复点编号:`CQRS-REWRITE-RP-079` - 当前阶段:`Phase 8` - 当前 PR 锚点:`PR #307` - 当前结论: - `GFramework.Cqrs` 已完成对外部 `Mediator` 的生产级替代,当前主线已从“是否可替代”转向“仓库内部收口与能力深化顺序” - `dispatch/invoker` 生成前移已扩展到 request / stream 路径,`RP-077` 已补齐 request invoker provider gate 与 stream gate 对称的 descriptor / descriptor entry runtime 合同回归 - - 当前 `RP-078` 已补齐 mixed fallback metadata 在 runtime 不允许多个 fallback attribute 实例时的单字符串 attribute 回退回归 - - `ai-plan` active 入口现以 `PR #307` 和 `RP-078` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 + - `RP-078` 已补齐 mixed fallback metadata 在 runtime 不允许多个 fallback attribute 实例时的单字符串 attribute 回退回归 + - 当前 `RP-079` 已补齐 runtime 缺少 generated handler registry interface 时的 generator 静默跳过回归 + - `ai-plan` active 入口现以 `PR #307` 和 `RP-079` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 ## 当前活跃事实 @@ -52,11 +53,18 @@ CQRS 迁移与收敛。 - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 - `git diff --check` - 结果:通过 +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Generate_Registry_When_Runtime_Lacks_Handler_Registry_Interface"` + - 结果:通过,`1/1` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 ## 下一推荐步骤 1. 继续处理 `PR #307` 的剩余 review 收尾,优先保持 `ai-plan` active 入口与 trace 的单一锚点一致 -2. 若继续推进代码切片,优先复核 fallback metadata 与 generated invoker provider 之外是否还有同类 runtime contract gate 回归缺口 +2. 若继续推进代码切片,优先复核基础 generation gate 中其他必需 runtime contracts 是否也需要同类回归覆盖 3. 在进入下一批 runtime / generator 收敛前,保持最小 Release build 或 targeted test 作为权威验证 ## 活跃文档 diff --git a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md index c617dcae..33f9909a 100644 --- a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md +++ b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md @@ -87,3 +87,25 @@ 1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 2. 下一批优先查看 fallback metadata 与 generated invoker provider 之外是否还有同类 runtime contract gate 回归缺口 + +### 阶段:基础 generated registry contract gate 回归(CQRS-REWRITE-RP-079) + +- 继续沿用 `$gframework-batch-boot 25`,当前 branch diff 仍低于阈值 +- 复核 generator 基础启用条件后确认:缺少 `ICqrsHandlerRegistry` 时,runtime 不具备承载 generated registry 的基础接口合同,应整体跳过发射 +- 已补齐: + - `Does_Not_Generate_Registry_When_Runtime_Lacks_Handler_Registry_Interface` + +### 验证(RP-079) + +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Generate_Registry_When_Runtime_Lacks_Handler_Registry_Interface"` + - 结果:通过,`1/1` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 + +### 当前下一步(RP-079) + +1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 +2. 下一批优先复核基础 generation gate 中其他必需 runtime contracts 是否也需要同类回归覆盖 From 915d93d06de5c8d092a9f4cb5e94044250a1e843 Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Mon, 4 May 2026 19:12:49 +0800 Subject: [PATCH 4/7] =?UTF-8?q?test(cqrs):=20=E6=89=A9=E5=B1=95=20registry?= =?UTF-8?q?=20gate=20=E5=9B=9E=E5=BD=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增缺少 notification handler 合同时的 generator 静默跳过覆盖 - 新增缺少 stream handler 合同时的 generator 静默跳过覆盖 - 新增缺少 registry attribute 合同时的 generator 静默跳过覆盖 - 更新 CQRS 恢复文档与本轮验证记录 --- .../Cqrs/CqrsHandlerRegistryGeneratorTests.cs | 34 +++++++++++++++---- .../todos/cqrs-rewrite-migration-tracking.md | 16 ++++++--- .../traces/cqrs-rewrite-migration-trace.md | 25 ++++++++++++++ 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs index 5cdb81ea..e59f61a5 100644 --- a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs +++ b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs @@ -2333,16 +2333,36 @@ public class CqrsHandlerRegistryGeneratorTests } /// - /// 验证当 runtime 缺少 generated registry 需要实现的基础注册接口时, + /// 验证当 runtime 缺少 generated registry 需要依赖的基础合同时, /// 生成器会整体跳过发射,避免产出无法承载运行时注册合同的半成品源码。 /// - [Test] - public void Does_Not_Generate_Registry_When_Runtime_Lacks_Handler_Registry_Interface() + /// 待移除 runtime 合同块的起始标记。 + /// 待移除 runtime 合同块之后的下一个稳定标记。 + [TestCase( + "public interface ICqrsHandlerRegistry", + "[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]")] + [TestCase( + "public interface INotificationHandler", + "public interface IStreamRequestHandler")] + [TestCase( + "public interface IStreamRequestHandler", + "rename:MissingIStreamRequestHandler")] + [TestCase( + "[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]", + "[AttributeUsage(AttributeTargets.Assembly)]")] + public void Does_Not_Generate_Registry_When_Runtime_Lacks_Required_Generation_Contract( + string startMarker, + string endMarker) { - var source = RemoveBlock( - HiddenNestedHandlerSelfRegistrationSource, - "public interface ICqrsHandlerRegistry", - "[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]"); + var source = endMarker.StartsWith("rename:", StringComparison.Ordinal) + ? RenameTypeIdentifier( + HiddenNestedHandlerSelfRegistrationSource, + startMarker.Replace("public interface ", string.Empty, StringComparison.Ordinal), + endMarker["rename:".Length..]) + : RemoveBlock( + HiddenNestedHandlerSelfRegistrationSource, + startMarker, + endMarker); var execution = ExecuteGenerator(source); var inputCompilationErrors = execution.InputCompilationDiagnostics .Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) diff --git a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md index 5dd0cdfe..a30309b7 100644 --- a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md +++ b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md @@ -7,15 +7,16 @@ CQRS 迁移与收敛。 ## 当前恢复点 -- 恢复点编号:`CQRS-REWRITE-RP-079` +- 恢复点编号:`CQRS-REWRITE-RP-080` - 当前阶段:`Phase 8` - 当前 PR 锚点:`PR #307` - 当前结论: - `GFramework.Cqrs` 已完成对外部 `Mediator` 的生产级替代,当前主线已从“是否可替代”转向“仓库内部收口与能力深化顺序” - `dispatch/invoker` 生成前移已扩展到 request / stream 路径,`RP-077` 已补齐 request invoker provider gate 与 stream gate 对称的 descriptor / descriptor entry runtime 合同回归 - `RP-078` 已补齐 mixed fallback metadata 在 runtime 不允许多个 fallback attribute 实例时的单字符串 attribute 回退回归 - - 当前 `RP-079` 已补齐 runtime 缺少 generated handler registry interface 时的 generator 静默跳过回归 - - `ai-plan` active 入口现以 `PR #307` 和 `RP-079` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 + - `RP-079` 已补齐 runtime 缺少 generated handler registry interface 时的 generator 静默跳过回归 + - 当前 `RP-080` 已将基础 generation gate 回归扩展到 notification handler interface、stream handler interface 与 registry attribute 缺失分支 + - `ai-plan` active 入口现以 `PR #307` 和 `RP-080` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 ## 当前活跃事实 @@ -60,11 +61,18 @@ CQRS 迁移与收敛。 - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 - `git diff --check` - 结果:通过 +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Generate_Registry_When_Runtime_Lacks_Required_Generation_Contract"` + - 结果:通过,`4/4` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 ## 下一推荐步骤 1. 继续处理 `PR #307` 的剩余 review 收尾,优先保持 `ai-plan` active 入口与 trace 的单一锚点一致 -2. 若继续推进代码切片,优先复核基础 generation gate 中其他必需 runtime contracts 是否也需要同类回归覆盖 +2. 若继续推进代码切片,优先复核基础 generation gate 中 logging / DI 依赖是否已有合适的输入编译安全回归覆盖方式 3. 在进入下一批 runtime / generator 收敛前,保持最小 Release build 或 targeted test 作为权威验证 ## 活跃文档 diff --git a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md index 33f9909a..14a7e196 100644 --- a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md +++ b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md @@ -109,3 +109,28 @@ 1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 2. 下一批优先复核基础 generation gate 中其他必需 runtime contracts 是否也需要同类回归覆盖 + +### 阶段:基础 generated registry contract gate 扩展回归(CQRS-REWRITE-RP-080) + +- 将 `RP-079` 的单一 handler registry interface 缺失回归扩展为基础 generation gate 参数化测试 +- 已补齐缺失分支: + - `ICqrsHandlerRegistry` + - `INotificationHandler` + - `IStreamRequestHandler` + - `CqrsHandlerRegistryAttribute` +- stream handler interface 变体采用类型重命名构造 runtime metadata miss,避免删除命名空间尾部单行接口时引入输入编译错误 + +### 验证(RP-080) + +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Generate_Registry_When_Runtime_Lacks_Required_Generation_Contract"` + - 结果:通过,`4/4` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 + +### 当前下一步(RP-080) + +1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 +2. 下一批优先复核基础 generation gate 中 logging / DI 依赖是否已有合适的输入编译安全回归覆盖方式 From 61cc1be1e506c0311c0c01d6139a2fd2c6b1baf9 Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Mon, 4 May 2026 19:15:32 +0800 Subject: [PATCH 5/7] =?UTF-8?q?test(cqrs):=20=E8=A1=A5=E9=BD=90=E5=A4=96?= =?UTF-8?q?=E9=83=A8=20contract=20gate=20=E5=9B=9E=E5=BD=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增缺少 ILogger 合同时的 generator 静默跳过覆盖 - 新增缺少 IServiceCollection 合同时的 generator 静默跳过覆盖 - 更新 CQRS 恢复文档与本轮验证记录 --- .../Cqrs/CqrsHandlerRegistryGeneratorTests.cs | 6 +++++ .../todos/cqrs-rewrite-migration-tracking.md | 16 +++++++++---- .../traces/cqrs-rewrite-migration-trace.md | 23 +++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs index e59f61a5..5e1c67d5 100644 --- a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs +++ b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs @@ -2350,6 +2350,12 @@ public class CqrsHandlerRegistryGeneratorTests [TestCase( "[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]", "[AttributeUsage(AttributeTargets.Assembly)]")] + [TestCase( + "public interface ILogger", + "rename:MissingILogger")] + [TestCase( + "public interface IServiceCollection", + "rename:MissingServiceCollection")] public void Does_Not_Generate_Registry_When_Runtime_Lacks_Required_Generation_Contract( string startMarker, string endMarker) diff --git a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md index a30309b7..d5d2665c 100644 --- a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md +++ b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md @@ -7,7 +7,7 @@ CQRS 迁移与收敛。 ## 当前恢复点 -- 恢复点编号:`CQRS-REWRITE-RP-080` +- 恢复点编号:`CQRS-REWRITE-RP-081` - 当前阶段:`Phase 8` - 当前 PR 锚点:`PR #307` - 当前结论: @@ -15,8 +15,9 @@ CQRS 迁移与收敛。 - `dispatch/invoker` 生成前移已扩展到 request / stream 路径,`RP-077` 已补齐 request invoker provider gate 与 stream gate 对称的 descriptor / descriptor entry runtime 合同回归 - `RP-078` 已补齐 mixed fallback metadata 在 runtime 不允许多个 fallback attribute 实例时的单字符串 attribute 回退回归 - `RP-079` 已补齐 runtime 缺少 generated handler registry interface 时的 generator 静默跳过回归 - - 当前 `RP-080` 已将基础 generation gate 回归扩展到 notification handler interface、stream handler interface 与 registry attribute 缺失分支 - - `ai-plan` active 入口现以 `PR #307` 和 `RP-080` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 + - `RP-080` 已将基础 generation gate 回归扩展到 notification handler interface、stream handler interface 与 registry attribute 缺失分支 + - 当前 `RP-081` 已继续补齐基础 generation gate 的 logging 与 DI runtime contract 缺失分支 + - `ai-plan` active 入口现以 `PR #307` 和 `RP-081` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 ## 当前活跃事实 @@ -68,11 +69,18 @@ CQRS 迁移与收敛。 - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 - `git diff --check` - 结果:通过 +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Generate_Registry_When_Runtime_Lacks_Required_Generation_Contract"` + - 结果:通过,`6/6` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 ## 下一推荐步骤 1. 继续处理 `PR #307` 的剩余 review 收尾,优先保持 `ai-plan` active 入口与 trace 的单一锚点一致 -2. 若继续推进代码切片,优先复核基础 generation gate 中 logging / DI 依赖是否已有合适的输入编译安全回归覆盖方式 +2. 若继续推进代码切片,优先复核基础 generation gate 中 request handler contract 与 handler registry attribute 以外是否还有可安全构造的缺失分支 3. 在进入下一批 runtime / generator 收敛前,保持最小 Release build 或 targeted test 作为权威验证 ## 活跃文档 diff --git a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md index 14a7e196..276d815f 100644 --- a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md +++ b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md @@ -134,3 +134,26 @@ 1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 2. 下一批优先复核基础 generation gate 中 logging / DI 依赖是否已有合适的输入编译安全回归覆盖方式 + +### 阶段:基础 generated registry external contract gate 回归(CQRS-REWRITE-RP-081) + +- 延续 `RP-080` 的参数化基础 generation gate 测试,将外部 logging / DI 依赖也纳入同一组静默跳过回归 +- 已补齐缺失分支: + - `GFramework.Core.Abstractions.Logging.ILogger` + - `Microsoft.Extensions.DependencyInjection.IServiceCollection` +- 两个变体均通过类型重命名构造 runtime metadata miss,保持输入源码可编译,避免把依赖缺失测试误写成编译失败测试 + +### 验证(RP-081) + +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Generate_Registry_When_Runtime_Lacks_Required_Generation_Contract"` + - 结果:通过,`6/6` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 + +### 当前下一步(RP-081) + +1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 +2. 下一批优先复核基础 generation gate 中 request handler contract 与 handler registry attribute 以外是否还有可安全构造的缺失分支 From b1f406ad99383b02d4e4c4f14ceb1437d30ccc98 Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Mon, 4 May 2026 19:17:48 +0800 Subject: [PATCH 6/7] =?UTF-8?q?test(cqrs):=20=E8=A1=A5=E9=BD=90=20request?= =?UTF-8?q?=20handler=20gate=20=E5=9B=9E=E5=BD=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增缺少 IRequestHandler 合同时的 generator 静默跳过覆盖 - 更新 CQRS 恢复文档与本轮验证记录 --- .../Cqrs/CqrsHandlerRegistryGeneratorTests.cs | 3 ++ .../todos/cqrs-rewrite-migration-tracking.md | 16 ++++++++--- .../traces/cqrs-rewrite-migration-trace.md | 28 +++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs index 5e1c67d5..545577f2 100644 --- a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs +++ b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs @@ -2344,6 +2344,9 @@ public class CqrsHandlerRegistryGeneratorTests [TestCase( "public interface INotificationHandler", "public interface IStreamRequestHandler")] + [TestCase( + "public interface IRequestHandler", + "rename:MissingIRequestHandler")] [TestCase( "public interface IStreamRequestHandler", "rename:MissingIStreamRequestHandler")] diff --git a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md index d5d2665c..5853218b 100644 --- a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md +++ b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md @@ -7,7 +7,7 @@ CQRS 迁移与收敛。 ## 当前恢复点 -- 恢复点编号:`CQRS-REWRITE-RP-081` +- 恢复点编号:`CQRS-REWRITE-RP-082` - 当前阶段:`Phase 8` - 当前 PR 锚点:`PR #307` - 当前结论: @@ -16,8 +16,9 @@ CQRS 迁移与收敛。 - `RP-078` 已补齐 mixed fallback metadata 在 runtime 不允许多个 fallback attribute 实例时的单字符串 attribute 回退回归 - `RP-079` 已补齐 runtime 缺少 generated handler registry interface 时的 generator 静默跳过回归 - `RP-080` 已将基础 generation gate 回归扩展到 notification handler interface、stream handler interface 与 registry attribute 缺失分支 - - 当前 `RP-081` 已继续补齐基础 generation gate 的 logging 与 DI runtime contract 缺失分支 - - `ai-plan` active 入口现以 `PR #307` 和 `RP-081` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 + - `RP-081` 已继续补齐基础 generation gate 的 logging 与 DI runtime contract 缺失分支 + - 当前 `RP-082` 已补齐基础 generation gate 的 request handler runtime contract 缺失分支 + - `ai-plan` active 入口现以 `PR #307` 和 `RP-082` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 ## 当前活跃事实 @@ -76,11 +77,18 @@ CQRS 迁移与收敛。 - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 - `git diff --check` - 结果:通过 +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Generate_Registry_When_Runtime_Lacks_Required_Generation_Contract"` + - 结果:通过,`7/7` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 ## 下一推荐步骤 1. 继续处理 `PR #307` 的剩余 review 收尾,优先保持 `ai-plan` active 入口与 trace 的单一锚点一致 -2. 若继续推进代码切片,优先复核基础 generation gate 中 request handler contract 与 handler registry attribute 以外是否还有可安全构造的缺失分支 +2. 若继续推进代码切片,优先复核基础 generation gate 之外的 runtime contract 或 fallback selection 分支;基础 gate 的可安全构造缺失分支已覆盖 3. 在进入下一批 runtime / generator 收敛前,保持最小 Release build 或 targeted test 作为权威验证 ## 活跃文档 diff --git a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md index 276d815f..58669018 100644 --- a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md +++ b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md @@ -157,3 +157,31 @@ 1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 2. 下一批优先复核基础 generation gate 中 request handler contract 与 handler registry attribute 以外是否还有可安全构造的缺失分支 + +### 阶段:基础 generated registry request handler gate 回归(CQRS-REWRITE-RP-082) + +- 延续 `RP-081` 的基础 generation gate 参数化测试,补齐 `IRequestHandler` 缺失分支 +- 该变体同样通过类型重命名构造 runtime metadata miss,保持输入源码可编译 +- 至此基础 generation gate 中可安全构造的缺失分支已覆盖: + - request handler interface + - notification handler interface + - stream handler interface + - handler registry interface + - handler registry attribute + - logging interface + - DI service collection interface + +### 验证(RP-082) + +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Generate_Registry_When_Runtime_Lacks_Required_Generation_Contract"` + - 结果:通过,`7/7` passed +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `git diff --check` + - 结果:通过 + +### 当前下一步(RP-082) + +1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 +2. 下一批优先复核基础 generation gate 之外的 runtime contract 或 fallback selection 分支;基础 gate 的可安全构造缺失分支已覆盖 From 212d5b1cce581fa2ec79b6ea9927e363c8238c4a Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Mon, 4 May 2026 20:56:19 +0800 Subject: [PATCH 7/7] =?UTF-8?q?docs(cqrs):=20=E5=90=8C=E6=AD=A5=20PR=20?= =?UTF-8?q?=E6=81=A2=E5=A4=8D=E9=94=9A=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新 CQRS active tracking 的当前 PR 锚点为 PR #323 - 补充 PR review 收敛 trace 与最新验证结果 --- .../todos/cqrs-rewrite-migration-tracking.md | 21 ++++++----- .../traces/cqrs-rewrite-migration-trace.md | 35 ++++++++++++++++--- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md index 5853218b..efc871e8 100644 --- a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md +++ b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md @@ -9,7 +9,7 @@ CQRS 迁移与收敛。 - 恢复点编号:`CQRS-REWRITE-RP-082` - 当前阶段:`Phase 8` -- 当前 PR 锚点:`PR #307` +- 当前 PR 锚点:`PR #323` - 当前结论: - `GFramework.Cqrs` 已完成对外部 `Mediator` 的生产级替代,当前主线已从“是否可替代”转向“仓库内部收口与能力深化顺序” - `dispatch/invoker` 生成前移已扩展到 request / stream 路径,`RP-077` 已补齐 request invoker provider gate 与 stream gate 对称的 descriptor / descriptor entry runtime 合同回归 @@ -18,13 +18,13 @@ CQRS 迁移与收敛。 - `RP-080` 已将基础 generation gate 回归扩展到 notification handler interface、stream handler interface 与 registry attribute 缺失分支 - `RP-081` 已继续补齐基础 generation gate 的 logging 与 DI runtime contract 缺失分支 - 当前 `RP-082` 已补齐基础 generation gate 的 request handler runtime contract 缺失分支 - - `ai-plan` active 入口现以 `PR #307` 和 `RP-082` 为唯一权威恢复锚点;更早 PR 与阶段细节均以下方归档为准 + - `ai-plan` active 入口现以 `PR #323` 和 `RP-082` 为唯一权威恢复锚点;`PR #307`、其他更早 PR 与阶段细节均以下方归档或说明为准 ## 当前活跃事实 -- 当前分支对应 `PR #307`,状态为 `OPEN` +- 当前分支对应 `PR #323`,状态为 `OPEN` - latest-head review 仍以 `ai-plan` 恢复文档收敛为主要待闭环项;代码与测试侧的本地有效问题已收敛 -- 远端 `CTRF` 最新汇总为 `2247/2247` passed +- 远端 `CTRF` 最新汇总为 `2274/2274` passed - `MegaLinter` 当前只暴露 `dotnet-format` 的 `Restore operation failed` 环境噪音,尚未提供本地仍成立的文件级格式诊断 ## 当前风险 @@ -35,9 +35,14 @@ CQRS 迁移与收敛。 ## 最近权威验证 -- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json --json-output /tmp/current-pr-review.json` +- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json --json-output ` - 结果:通过 - - 备注:确认当前分支对应 `PR #307`,本轮剩余 open AI feedback 主要集中在 `ai-plan` 收敛 + - 备注:确认当前分支对应 `PR #323`,本轮剩余 open AI feedback 主要集中在 `ai-plan` PR 锚点收敛 +- `git diff --check` + - 结果:通过 +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 - `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release` - 结果:通过,`0 warning / 0 error` - `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Entry_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"` @@ -87,7 +92,7 @@ CQRS 迁移与收敛。 ## 下一推荐步骤 -1. 继续处理 `PR #307` 的剩余 review 收尾,优先保持 `ai-plan` active 入口与 trace 的单一锚点一致 +1. 继续处理 `PR #323` 的剩余 review 收尾,优先保持 `ai-plan` active 入口与 trace 的单一锚点一致 2. 若继续推进代码切片,优先复核基础 generation gate 之外的 runtime contract 或 fallback selection 分支;基础 gate 的可安全构造缺失分支已覆盖 3. 在进入下一批 runtime / generator 收敛前,保持最小 Release build 或 targeted test 作为权威验证 @@ -103,5 +108,5 @@ CQRS 迁移与收敛。 ## 说明 -- `PR #261`、`PR #302`、`PR #305` 及更早阶段的详细过程已不再作为 active 恢复入口;如需追溯,以对应归档文件为准 +- `PR #261`、`PR #302`、`PR #305`、`PR #307` 及更早阶段的详细过程已不再作为 active 恢复入口;如需追溯,以对应归档文件或历史 trace 段落为准 - active tracking 仅保留当前恢复点、当前风险、最近权威验证与下一推荐步骤,避免 `boot` 落到历史阶段细节 diff --git a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md index 58669018..0dec487b 100644 --- a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md +++ b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md @@ -2,11 +2,11 @@ ## 2026-04-30 -### 阶段:PR #307 active 入口收敛(CQRS-REWRITE-RP-076) +### 阶段:历史 PR #307 active 入口收敛(CQRS-REWRITE-RP-076) - 继续沿用 `$gframework-pr-review` 对 `PR #307` 做 latest-head triage,本轮只处理仍成立的 `ai-plan` 恢复入口问题 - 主线程确认当前远端权威信号: - - 当前分支对应 `PR #307`,状态为 `OPEN` + - 当时分支对应 `PR #307`,状态为 `OPEN` - 远端 `CTRF` 最新汇总为 `2247/2247` passed - `MegaLinter` 仅剩 `dotnet-format` 的 `Restore operation failed` 环境噪音 - 仍未闭环的 review 重点集中在 `cqrs-rewrite` active tracking / trace 仍保留过多历史锚点,而非新的运行时代码缺陷 @@ -17,7 +17,7 @@ ### 验证(RP-076) -- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json --json-output /tmp/current-pr-review.json` +- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json --json-output ` - 结果:通过 - 备注:确认 `PR #307` 的当前 review 重点已收敛到 `ai-plan` 文档收尾 - `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release` @@ -27,7 +27,7 @@ ### 当前下一步(RP-076) -1. 继续按 `PR #307` 的 latest-head review 收尾,优先保持 active tracking 与 active trace 的单一锚点一致 +1. 当时继续按 `PR #307` 的 latest-head review 收尾,优先保持 active tracking 与 active trace 的单一锚点一致 2. 若继续推进代码切片,先复核 request 侧是否仍存在与 stream invoker gate 对称的生成合同遗漏 3. 进入下一批前继续使用最小 Release build 或 targeted test 作为权威验证,避免把环境噪音误判为代码问题 @@ -185,3 +185,30 @@ 1. 继续复算 branch diff vs `origin/main`,若仍低于 `25` 个文件可继续下一批 2. 下一批优先复核基础 generation gate 之外的 runtime contract 或 fallback selection 分支;基础 gate 的可安全构造缺失分支已覆盖 + +### 阶段:PR #323 review 锚点收敛(CQRS-REWRITE-RP-082) + +- 使用 `$gframework-pr-review` 重新拉取当前分支 PR review payload,确认当前分支对应 `PR #323`,状态为 `OPEN` +- 本轮 latest-head open AI thread 仅指出 active tracking 中仍保留 `PR #307` 作为当前 PR 锚点;本地复核后确认该反馈仍成立 +- 已将 active tracking 的当前 PR 锚点、活跃事实、最近 PR review 备注和下一推荐步骤统一到 `PR #323` +- `PR #307` 仅保留为历史 PR 说明和较早 trace 段落,不再作为 active 恢复入口 + +### 验证(PR #323 review) + +- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json --json-output ` + - 结果:通过 + - 备注:确认 `PR #323` 只有 1 个 CodeRabbit open thread,指向 active tracking 的 PR 锚点漂移 +- 远端 `CTRF` 最新汇总为 `2274/2274` passed +- `MegaLinter` 当前仅报告 `dotnet-format` 的 `Restore operation failed` 环境噪音,未提供本地仍成立的文件级格式诊断 +- `git diff --check` + - 结果:通过 +- `python3 scripts/license-header.py --check` + - 结果:通过 + - 备注:当前 WSL worktree 需要显式绑定 `GIT_DIR` / `GIT_WORK_TREE` 后运行 +- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release` + - 结果:通过,`0 warning / 0 error` + +### 当前下一步(PR #323 review) + +1. 若 review 重新触发后仍有 latest-head open thread,继续以 `PR #323` 为当前唯一 PR 恢复锚点复核 +2. 后续若继续推进代码切片,优先复核基础 generation gate 之外的 runtime contract 或 fallback selection 分支