From ba4ace8d40ca4d7326fb1f0937a440adeb372fe7 Mon Sep 17 00:00:00 2001
From: gewuyou <95328647+GeWuYou@users.noreply.github.com>
Date: Tue, 28 Apr 2026 08:32:00 +0800
Subject: [PATCH] =?UTF-8?q?test(analyzer):=20=E6=94=B6=E6=95=9B=20Core.Tes?=
=?UTF-8?q?ts=20=E4=B8=8E=20Cqrs.Tests=20=E8=AD=A6=E5=91=8A=E6=89=B9?=
=?UTF-8?q?=E6=AC=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 拆分 GameContextTests、ArchitectureServicesTests、RegistryInitializationHookBaseTests 与 Cqrs 测试辅助类型,消除批次内 MA0048 热点
- 修复 Core.Tests 零散可空性、集合抽象和测试辅助 warning,使受影响 Release 构建清零
- 更新 analyzer-warning-reduction 跟踪与 trace,记录 236 条仓库根 warning 基线和 45/50 停止点
---
.../AnotherTestArchitectureContext.cs | 8 +
.../ArchitectureServicesTests.cs | 212 ---------
.../Architectures/ContextProviderTests.cs | 7 -
.../Architectures/TestArchitectureBase.cs | 5 +-
.../TestArchitectureContextV3.cs | 412 ++++++++++++++++++
.../CommandCoroutineExtensionsTests.cs | 4 +-
.../Coroutine/WaitForMultipleEventsTests.cs | 4 +-
GFramework.Core.Tests/Events/EmptyEvent.cs | 6 +
.../Events/EventListenerScopeTests.cs | 4 +-
GFramework.Core.Tests/Events/TestEvent.cs | 8 +-
GFramework.Core.Tests/Logging/LoggerTests.cs | 41 --
.../Logging/LoggingConfigurationTests.cs | 5 +-
GFramework.Core.Tests/Logging/TestLogger.cs | 45 ++
.../Resource/ResourceManagerTests.cs | 50 ---
.../Resource/TestResource.cs | 17 +
.../Resource/TestResourceLoader.cs | 52 +++
.../analyzer-warning-reduction-tracking.md | 62 ++-
.../analyzer-warning-reduction-trace.md | 50 +++
18 files changed, 634 insertions(+), 358 deletions(-)
create mode 100644 GFramework.Core.Tests/Architectures/AnotherTestArchitectureContext.cs
create mode 100644 GFramework.Core.Tests/Architectures/TestArchitectureContextV3.cs
create mode 100644 GFramework.Core.Tests/Events/EmptyEvent.cs
create mode 100644 GFramework.Core.Tests/Logging/TestLogger.cs
create mode 100644 GFramework.Core.Tests/Resource/TestResource.cs
create mode 100644 GFramework.Core.Tests/Resource/TestResourceLoader.cs
diff --git a/GFramework.Core.Tests/Architectures/AnotherTestArchitectureContext.cs b/GFramework.Core.Tests/Architectures/AnotherTestArchitectureContext.cs
new file mode 100644
index 00000000..850a3723
--- /dev/null
+++ b/GFramework.Core.Tests/Architectures/AnotherTestArchitectureContext.cs
@@ -0,0 +1,8 @@
+namespace GFramework.Core.Tests.Architectures;
+
+///
+/// 表示用于验证上下文类型不匹配分支的测试架构上下文。
+///
+public class AnotherTestArchitectureContext : TestArchitectureContext
+{
+}
diff --git a/GFramework.Core.Tests/Architectures/ArchitectureServicesTests.cs b/GFramework.Core.Tests/Architectures/ArchitectureServicesTests.cs
index f1474403..2c060b5b 100644
--- a/GFramework.Core.Tests/Architectures/ArchitectureServicesTests.cs
+++ b/GFramework.Core.Tests/Architectures/ArchitectureServicesTests.cs
@@ -262,215 +262,3 @@ public class ArchitectureServicesTests
Assert.That(_services!.ModuleManager, Is.Not.Null);
}
}
-
-#region Test Classes
-
-public class TestArchitectureContextV3 : IArchitectureContext
-{
- private readonly MicrosoftDiContainer _container = new();
- private readonly DefaultEnvironment _environment = new();
- public int Id { get; init; }
-
- public TService? GetService() where TService : class
- {
- return _container.Get();
- }
-
- public IReadOnlyList GetServices() where TService : class
- {
- return _container.GetAll();
- }
-
- public TModel? GetModel() where TModel : class, IModel
- {
- return _container.Get();
- }
-
- public IReadOnlyList GetModels() where TModel : class, IModel
- {
- return _container.GetAll();
- }
-
- public TSystem? GetSystem() where TSystem : class, ISystem
- {
- return _container.Get();
- }
-
- public IReadOnlyList GetSystems() where TSystem : class, ISystem
- {
- return _container.GetAll();
- }
-
- public TUtility? GetUtility() where TUtility : class, IUtility
- {
- return _container.Get();
- }
-
- public IReadOnlyList GetUtilities() where TUtility : class, IUtility
- {
- return _container.GetAll();
- }
-
- public IReadOnlyList GetServicesByPriority() where TService : class
- {
- return _container.GetAllByPriority();
- }
-
- public IReadOnlyList GetSystemsByPriority() where TSystem : class, ISystem
- {
- return _container.GetAllByPriority();
- }
-
- public IReadOnlyList GetModelsByPriority() where TModel : class, IModel
- {
- return _container.GetAllByPriority();
- }
-
- public IReadOnlyList GetUtilitiesByPriority() where TUtility : class, IUtility
- {
- return _container.GetAllByPriority();
- }
-
- public void SendEvent() where TEvent : new()
- {
- }
-
- public void SendEvent(TEvent e) where TEvent : class
- {
- }
-
- public IUnRegister RegisterEvent(Action handler)
- {
- return new DefaultUnRegister(() => { });
- }
-
- public void UnRegisterEvent(Action onEvent)
- {
- }
-
- public ValueTask SendRequestAsync(IRequest request,
- CancellationToken cancellationToken = default)
- {
- throw new NotSupportedException();
- }
-
- public TResponse SendRequest(IRequest request)
- {
- throw new NotSupportedException();
- }
-
- ///
- /// 测试桩:异步发送 CQRS 命令并返回响应。
- ///
- /// 命令响应类型。
- /// 要发送的命令。
- /// 取消令牌。
- /// 命令响应任务。
- /// 该测试桩不支持此成员。
- public ValueTask SendCommandAsync(
- GFramework.Cqrs.Abstractions.Cqrs.Command.ICommand command,
- CancellationToken cancellationToken = default)
- {
- throw new NotSupportedException();
- }
-
- ///
- /// 测试桩:同步发送 CQRS 命令并返回响应。
- ///
- /// 命令响应类型。
- /// 要发送的命令。
- /// 命令响应。
- /// 该测试桩不支持此成员。
- public TResponse SendCommand(GFramework.Cqrs.Abstractions.Cqrs.Command.ICommand command)
- {
- throw new NotSupportedException();
- }
-
- ///
- /// 测试桩:异步发送 CQRS 查询并返回结果。
- ///
- /// 查询结果类型。
- /// 要发送的查询。
- /// 取消令牌。
- /// 查询结果任务。
- /// 该测试桩不支持此成员。
- public ValueTask SendQueryAsync(
- GFramework.Cqrs.Abstractions.Cqrs.Query.IQuery query,
- CancellationToken cancellationToken = default)
- {
- throw new NotSupportedException();
- }
-
- ///
- /// 测试桩:同步发送 CQRS 查询并返回结果。
- ///
- /// 查询结果类型。
- /// 要发送的查询。
- /// 查询结果。
- /// 该测试桩不支持此成员。
- public TResponse SendQuery(GFramework.Cqrs.Abstractions.Cqrs.Query.IQuery query)
- {
- throw new NotSupportedException();
- }
-
- public ValueTask PublishAsync(TNotification notification,
- CancellationToken cancellationToken = default) where TNotification : INotification
- {
- throw new NotSupportedException();
- }
-
- public IAsyncEnumerable CreateStream(
- IStreamRequest request,
- CancellationToken cancellationToken = default)
- {
- throw new NotSupportedException();
- }
-
- public ValueTask SendAsync(TCommand command, CancellationToken cancellationToken = default)
- where TCommand : IRequest
- {
- throw new NotSupportedException();
- }
-
- public ValueTask SendAsync(IRequest command,
- CancellationToken cancellationToken = default)
- {
- throw new NotSupportedException();
- }
-
- public void SendCommand(ICommand command)
- {
- }
-
- public TResult SendCommand(Abstractions.Command.ICommand command)
- {
- return default!;
- }
-
- public Task SendCommandAsync(IAsyncCommand command)
- {
- return Task.CompletedTask;
- }
-
- public Task SendCommandAsync(IAsyncCommand command)
- {
- return (Task)Task.CompletedTask;
- }
-
- public TResult SendQuery(Abstractions.Query.IQuery query)
- {
- return default!;
- }
-
- public Task SendQueryAsync(IAsyncQuery query)
- {
- return (Task)Task.CompletedTask;
- }
-
- public IEnvironment GetEnvironment()
- {
- return _environment;
- }
-}
-
-#endregion
diff --git a/GFramework.Core.Tests/Architectures/ContextProviderTests.cs b/GFramework.Core.Tests/Architectures/ContextProviderTests.cs
index 5fc205ce..ee196cdf 100644
--- a/GFramework.Core.Tests/Architectures/ContextProviderTests.cs
+++ b/GFramework.Core.Tests/Architectures/ContextProviderTests.cs
@@ -147,10 +147,3 @@ public class ContextProviderTests
Assert.That(foundContext, Is.SameAs(context));
}
}
-
-///
-/// 另一个测试用的架构上下文类,用于测试类型不匹配的情况
-///
-public class AnotherTestArchitectureContext : TestArchitectureContext
-{
-}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/Architectures/TestArchitectureBase.cs b/GFramework.Core.Tests/Architectures/TestArchitectureBase.cs
index 57cf9a71..fdd144f7 100644
--- a/GFramework.Core.Tests/Architectures/TestArchitectureBase.cs
+++ b/GFramework.Core.Tests/Architectures/TestArchitectureBase.cs
@@ -9,6 +9,7 @@ namespace GFramework.Core.Tests.Architectures;
public abstract class TestArchitectureBase : Architecture
{
private Action? _postRegistrationHook;
+ private readonly List _phaseHistory = [];
///
/// 获取就绪事件是否已触发的状态
@@ -23,7 +24,7 @@ public abstract class TestArchitectureBase : Architecture
///
/// 获取架构阶段历史记录列表
///
- public List PhaseHistory { get; } = [];
+ public IReadOnlyList PhaseHistory => _phaseHistory;
///
/// 添加注册后钩子函数
@@ -43,6 +44,6 @@ public abstract class TestArchitectureBase : Architecture
_postRegistrationHook?.Invoke(this);
// 订阅阶段变更事件以记录历史
- PhaseChanged += (_, eventArgs) => PhaseHistory.Add(eventArgs.Phase);
+ PhaseChanged += (_, eventArgs) => _phaseHistory.Add(eventArgs.Phase);
}
}
diff --git a/GFramework.Core.Tests/Architectures/TestArchitectureContextV3.cs b/GFramework.Core.Tests/Architectures/TestArchitectureContextV3.cs
new file mode 100644
index 00000000..6fda6f2d
--- /dev/null
+++ b/GFramework.Core.Tests/Architectures/TestArchitectureContextV3.cs
@@ -0,0 +1,412 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using GFramework.Core.Abstractions.Architectures;
+using GFramework.Core.Abstractions.Command;
+using GFramework.Core.Abstractions.Environment;
+using GFramework.Core.Abstractions.Events;
+using GFramework.Core.Abstractions.Model;
+using GFramework.Core.Abstractions.Query;
+using GFramework.Core.Abstractions.Systems;
+using GFramework.Core.Abstractions.Utility;
+using GFramework.Core.Environment;
+using GFramework.Core.Events;
+using GFramework.Core.Ioc;
+using GFramework.Cqrs;
+using GFramework.Cqrs.Abstractions.Cqrs;
+using ICommand = GFramework.Core.Abstractions.Command.ICommand;
+
+namespace GFramework.Core.Tests.Architectures;
+
+///
+/// 为 提供最小实现的架构上下文测试桩。
+///
+///
+/// 该类型仅用于验证 的上下文传递行为,因此仅保留当前测试切片需要的容器、
+/// 环境与接口实现。所有不在本测试范围内的 CQRS 调用均明确抛出 ,
+/// 以避免误把测试桩当作真实运行时上下文使用。
+///
+public class TestArchitectureContextV3 : IArchitectureContext
+{
+ private readonly MicrosoftDiContainer _container = new();
+ private readonly DefaultEnvironment _environment = new();
+
+ ///
+ /// 获取或初始化用于区分测试上下文实例的标识。
+ ///
+ public int Id { get; init; }
+
+ ///
+ /// 获取指定类型的服务实例。
+ ///
+ /// 服务类型。
+ /// 已注册的服务实例。
+ /// 未注册或存在多个同类型实例时抛出。
+ public TService GetService() where TService : class
+ {
+ return _container.GetRequired();
+ }
+
+ ///
+ /// 获取指定类型的所有服务实例。
+ ///
+ /// 服务类型。
+ /// 所有已注册的服务实例。
+ public IReadOnlyList GetServices() where TService : class
+ {
+ return _container.GetAll();
+ }
+
+ ///
+ /// 获取指定类型的模型实例。
+ ///
+ /// 模型类型。
+ /// 已注册的模型实例。
+ /// 未注册或存在多个同类型实例时抛出。
+ public TModel GetModel() where TModel : class, IModel
+ {
+ return _container.GetRequired();
+ }
+
+ ///
+ /// 获取指定类型的所有模型实例。
+ ///
+ /// 模型类型。
+ /// 所有已注册的模型实例。
+ public IReadOnlyList GetModels() where TModel : class, IModel
+ {
+ return _container.GetAll();
+ }
+
+ ///
+ /// 获取指定类型的系统实例。
+ ///
+ /// 系统类型。
+ /// 已注册的系统实例。
+ /// 未注册或存在多个同类型实例时抛出。
+ public TSystem GetSystem() where TSystem : class, ISystem
+ {
+ return _container.GetRequired();
+ }
+
+ ///
+ /// 获取指定类型的所有系统实例。
+ ///
+ /// 系统类型。
+ /// 所有已注册的系统实例。
+ public IReadOnlyList GetSystems() where TSystem : class, ISystem
+ {
+ return _container.GetAll();
+ }
+
+ ///
+ /// 获取指定类型的工具实例。
+ ///
+ /// 工具类型。
+ /// 已注册的工具实例。
+ /// 未注册或存在多个同类型实例时抛出。
+ public TUtility GetUtility() where TUtility : class, IUtility
+ {
+ return _container.GetRequired();
+ }
+
+ ///
+ /// 获取指定类型的所有工具实例。
+ ///
+ /// 工具类型。
+ /// 所有已注册的工具实例。
+ public IReadOnlyList GetUtilities() where TUtility : class, IUtility
+ {
+ return _container.GetAll();
+ }
+
+ ///
+ /// 获取指定类型的所有服务实例,并按优先级排序。
+ ///
+ /// 服务类型。
+ /// 按优先级排序后的服务实例。
+ public IReadOnlyList GetServicesByPriority() where TService : class
+ {
+ return _container.GetAllByPriority();
+ }
+
+ ///
+ /// 获取指定类型的所有系统实例,并按优先级排序。
+ ///
+ /// 系统类型。
+ /// 按优先级排序后的系统实例。
+ public IReadOnlyList GetSystemsByPriority() where TSystem : class, ISystem
+ {
+ return _container.GetAllByPriority();
+ }
+
+ ///
+ /// 获取指定类型的所有模型实例,并按优先级排序。
+ ///
+ /// 模型类型。
+ /// 按优先级排序后的模型实例。
+ public IReadOnlyList GetModelsByPriority() where TModel : class, IModel
+ {
+ return _container.GetAllByPriority();
+ }
+
+ ///
+ /// 获取指定类型的所有工具实例,并按优先级排序。
+ ///
+ /// 工具类型。
+ /// 按优先级排序后的工具实例。
+ public IReadOnlyList GetUtilitiesByPriority() where TUtility : class, IUtility
+ {
+ return _container.GetAllByPriority();
+ }
+
+ ///
+ /// 发送无参数事件。
+ ///
+ /// 事件类型。
+ public void SendEvent() where TEvent : new()
+ {
+ }
+
+ ///
+ /// 发送带参数事件。
+ ///
+ /// 事件类型。
+ /// 事件实例。
+ public void SendEvent(TEvent e) where TEvent : class
+ {
+ }
+
+ ///
+ /// 注册事件处理器。
+ ///
+ /// 事件类型。
+ /// 事件处理回调。
+ /// 用于注销回调的句柄。
+ public IUnRegister RegisterEvent(Action handler)
+ {
+ return new DefaultUnRegister(() => { });
+ }
+
+ ///
+ /// 取消事件处理器注册。
+ ///
+ /// 事件类型。
+ /// 要取消的事件回调。
+ public void UnRegisterEvent(Action onEvent)
+ {
+ }
+
+ ///
+ /// 异步发送新版 CQRS 请求。
+ ///
+ /// 响应类型。
+ /// 要发送的请求。
+ /// 取消令牌。
+ /// 请求响应任务。
+ /// 该测试桩不支持此成员。
+ public ValueTask SendRequestAsync(
+ IRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 同步发送新版 CQRS 请求。
+ ///
+ /// 响应类型。
+ /// 要发送的请求。
+ /// 请求响应。
+ /// 该测试桩不支持此成员。
+ public TResponse SendRequest(IRequest request)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 异步发送新版 CQRS 命令并返回响应。
+ ///
+ /// 命令响应类型。
+ /// 要发送的命令。
+ /// 取消令牌。
+ /// 命令响应任务。
+ /// 该测试桩不支持此成员。
+ public ValueTask SendCommandAsync(
+ GFramework.Cqrs.Abstractions.Cqrs.Command.ICommand command,
+ CancellationToken cancellationToken = default)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 同步发送新版 CQRS 命令并返回响应。
+ ///
+ /// 命令响应类型。
+ /// 要发送的命令。
+ /// 命令响应。
+ /// 该测试桩不支持此成员。
+ public TResponse SendCommand(GFramework.Cqrs.Abstractions.Cqrs.Command.ICommand command)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 异步发送新版 CQRS 查询并返回结果。
+ ///
+ /// 查询结果类型。
+ /// 要发送的查询。
+ /// 取消令牌。
+ /// 查询结果任务。
+ /// 该测试桩不支持此成员。
+ public ValueTask SendQueryAsync(
+ GFramework.Cqrs.Abstractions.Cqrs.Query.IQuery query,
+ CancellationToken cancellationToken = default)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 同步发送新版 CQRS 查询并返回结果。
+ ///
+ /// 查询结果类型。
+ /// 要发送的查询。
+ /// 查询结果。
+ /// 该测试桩不支持此成员。
+ public TResponse SendQuery(GFramework.Cqrs.Abstractions.Cqrs.Query.IQuery query)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 发布通知消息。
+ ///
+ /// 通知类型。
+ /// 通知实例。
+ /// 取消令牌。
+ /// 通知发布任务。
+ /// 该测试桩不支持此成员。
+ public ValueTask PublishAsync(
+ TNotification notification,
+ CancellationToken cancellationToken = default)
+ where TNotification : INotification
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 创建流式请求结果。
+ ///
+ /// 流元素类型。
+ /// 流式请求。
+ /// 取消令牌。
+ /// 流式响应序列。
+ /// 该测试桩不支持此成员。
+ public IAsyncEnumerable CreateStream(
+ IStreamRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 异步发送无返回值请求命令。
+ ///
+ /// 命令类型。
+ /// 要发送的命令。
+ /// 取消令牌。
+ /// 命令发送任务。
+ /// 该测试桩不支持此成员。
+ public ValueTask SendAsync(TCommand command, CancellationToken cancellationToken = default)
+ where TCommand : IRequest
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 异步发送带返回值请求。
+ ///
+ /// 响应类型。
+ /// 要发送的请求。
+ /// 取消令牌。
+ /// 请求响应任务。
+ /// 该测试桩不支持此成员。
+ public ValueTask SendAsync(
+ IRequest command,
+ CancellationToken cancellationToken = default)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// 发送旧版无返回值命令。
+ ///
+ /// 要发送的命令。
+ public void SendCommand(ICommand command)
+ {
+ }
+
+ ///
+ /// 发送旧版带返回值命令。
+ ///
+ /// 命令响应类型。
+ /// 要发送的命令。
+ /// 默认响应值。
+ public TResult SendCommand(GFramework.Core.Abstractions.Command.ICommand command)
+ {
+ return default!;
+ }
+
+ ///
+ /// 异步发送旧版无返回值命令。
+ ///
+ /// 要发送的命令。
+ /// 已完成任务。
+ public Task SendCommandAsync(IAsyncCommand command)
+ {
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 异步发送旧版带返回值命令。
+ ///
+ /// 命令响应类型。
+ /// 要发送的命令。
+ /// 占位任务。
+ public Task SendCommandAsync(IAsyncCommand command)
+ {
+ return (Task)Task.CompletedTask;
+ }
+
+ ///
+ /// 发送旧版查询请求。
+ ///
+ /// 查询结果类型。
+ /// 要发送的查询。
+ /// 默认查询结果。
+ public TResult SendQuery(GFramework.Core.Abstractions.Query.IQuery query)
+ {
+ return default!;
+ }
+
+ ///
+ /// 异步发送旧版查询请求。
+ ///
+ /// 查询结果类型。
+ /// 要发送的查询。
+ /// 占位任务。
+ public Task SendQueryAsync(IAsyncQuery query)
+ {
+ return (Task)Task.CompletedTask;
+ }
+
+ ///
+ /// 获取当前测试上下文绑定的环境实例。
+ ///
+ /// 默认测试环境实例。
+ public IEnvironment GetEnvironment()
+ {
+ return _environment;
+ }
+}
diff --git a/GFramework.Core.Tests/Coroutine/CommandCoroutineExtensionsTests.cs b/GFramework.Core.Tests/Coroutine/CommandCoroutineExtensionsTests.cs
index 494688bd..84378a6b 100644
--- a/GFramework.Core.Tests/Coroutine/CommandCoroutineExtensionsTests.cs
+++ b/GFramework.Core.Tests/Coroutine/CommandCoroutineExtensionsTests.cs
@@ -405,7 +405,7 @@ public class CommandCoroutineExtensionsTests
CommandCoroutineExtensions.SendCommandAndWaitEventCoroutine(
contextAware,
command,
- null,
+ _ => { },
-1.0f));
}
@@ -421,7 +421,7 @@ public class CommandCoroutineExtensionsTests
// 设置上下文服务以返回null事件总线
contextAware._mockContext
.Setup(ctx => ctx.GetService())
- .Returns((IEventBus?)null);
+ .Returns((IEventBus)null!);
// 创建协程
var coroutine = CommandCoroutineExtensions.SendCommandAndWaitEventCoroutine(
diff --git a/GFramework.Core.Tests/Coroutine/WaitForMultipleEventsTests.cs b/GFramework.Core.Tests/Coroutine/WaitForMultipleEventsTests.cs
index 1d0588d0..88baf123 100644
--- a/GFramework.Core.Tests/Coroutine/WaitForMultipleEventsTests.cs
+++ b/GFramework.Core.Tests/Coroutine/WaitForMultipleEventsTests.cs
@@ -20,7 +20,7 @@ namespace GFramework.Core.Tests.Coroutine
(eventBus as IDisposable)?.Dispose();
}
- private IEventBus eventBus;
+ private IEventBus eventBus = null!;
[Test]
public void Constructor_RegistersBothEventTypes()
@@ -138,4 +138,4 @@ namespace GFramework.Core.Tests.Coroutine
public string Data { get; set; } = string.Empty;
}
}
-}
\ No newline at end of file
+}
diff --git a/GFramework.Core.Tests/Events/EmptyEvent.cs b/GFramework.Core.Tests/Events/EmptyEvent.cs
new file mode 100644
index 00000000..60d479e2
--- /dev/null
+++ b/GFramework.Core.Tests/Events/EmptyEvent.cs
@@ -0,0 +1,6 @@
+namespace GFramework.Core.Tests.Events;
+
+///
+/// 表示不携带任何负载的空测试事件。
+///
+public sealed class EmptyEvent;
diff --git a/GFramework.Core.Tests/Events/EventListenerScopeTests.cs b/GFramework.Core.Tests/Events/EventListenerScopeTests.cs
index a88edba6..2c6b9569 100644
--- a/GFramework.Core.Tests/Events/EventListenerScopeTests.cs
+++ b/GFramework.Core.Tests/Events/EventListenerScopeTests.cs
@@ -1,3 +1,4 @@
+using System.Runtime.InteropServices;
using GFramework.Core.Abstractions.Events;
using GFramework.Core.Events;
using Moq;
@@ -303,6 +304,7 @@ public class EventListenerScopeTests
///
/// 测试用的结构体事件
///
+ [StructLayout(LayoutKind.Auto)]
private struct StructEvent
{
public int Id { get; set; }
@@ -318,4 +320,4 @@ public class EventListenerScopeTests
using var scope = new EventListenerScope(eventBusMock.Object);
// 作用域内部不验证
}
-}
\ No newline at end of file
+}
diff --git a/GFramework.Core.Tests/Events/TestEvent.cs b/GFramework.Core.Tests/Events/TestEvent.cs
index c7e47ed6..d3806918 100644
--- a/GFramework.Core.Tests/Events/TestEvent.cs
+++ b/GFramework.Core.Tests/Events/TestEvent.cs
@@ -1,8 +1,12 @@
namespace GFramework.Core.Tests.Events;
+///
+/// 表示包含整型载荷的测试事件。
+///
public sealed class TestEvent
{
+ ///
+ /// 获取初始化阶段写入的接收值。
+ ///
public int ReceivedValue { get; init; }
}
-
-public sealed class EmptyEvent;
\ No newline at end of file
diff --git a/GFramework.Core.Tests/Logging/LoggerTests.cs b/GFramework.Core.Tests/Logging/LoggerTests.cs
index 3bba60a4..f26e68b6 100644
--- a/GFramework.Core.Tests/Logging/LoggerTests.cs
+++ b/GFramework.Core.Tests/Logging/LoggerTests.cs
@@ -419,44 +419,3 @@ public class LoggerTests
Assert.That(fatalLogger.Logs[0].Level, Is.EqualTo(LogLevel.Fatal));
}
}
-
-///
-/// 测试用的日志记录器实现类,继承自AbstractLogger
-///
-public sealed class TestLogger : AbstractLogger
-{
- private readonly List _logs = new();
-
- ///
- /// 初始化TestLogger的新实例
- ///
- /// 日志记录器的名称,默认为null
- /// 最小日志级别,默认为LogLevel.Info
- public TestLogger(string? name = null, LogLevel minLevel = LogLevel.Info) : base(name, minLevel)
- {
- }
-
- ///
- /// 获取按写入顺序保存的日志条目只读视图
- ///
- public IReadOnlyList Logs => _logs;
-
- ///
- /// 将日志信息写入内部存储
- ///
- /// 日志级别
- /// 日志消息
- /// 相关异常(可选)
- protected override void Write(LogLevel level, string message, Exception? exception)
- {
- _logs.Add(new LogEntry(level, message, exception));
- }
-
- ///
- /// 表示单个日志条目的记录类型
- ///
- /// 日志级别
- /// 日志消息
- /// 相关异常(可选)
- public sealed record LogEntry(LogLevel Level, string Message, Exception? Exception);
-}
diff --git a/GFramework.Core.Tests/Logging/LoggingConfigurationTests.cs b/GFramework.Core.Tests/Logging/LoggingConfigurationTests.cs
index 9586533f..533d368c 100644
--- a/GFramework.Core.Tests/Logging/LoggingConfigurationTests.cs
+++ b/GFramework.Core.Tests/Logging/LoggingConfigurationTests.cs
@@ -307,8 +307,9 @@ public class LoggingConfigurationTests
}}";
var config = LoggingConfigurationLoader.LoadFromJsonString(json);
- Assert.That(config.Appenders[0].Filter, Is.Not.Null);
- Assert.That(config.Appenders[0].Filter.Type, Is.EqualTo("Namespace"));
+ var filter = config.Appenders[0].Filter;
+ Assert.That(filter, Is.Not.Null);
+ Assert.That(filter!.Type, Is.EqualTo("Namespace"));
}
finally
{
diff --git a/GFramework.Core.Tests/Logging/TestLogger.cs b/GFramework.Core.Tests/Logging/TestLogger.cs
new file mode 100644
index 00000000..594b6de7
--- /dev/null
+++ b/GFramework.Core.Tests/Logging/TestLogger.cs
@@ -0,0 +1,45 @@
+using GFramework.Core.Abstractions.Logging;
+using GFramework.Core.Logging;
+
+namespace GFramework.Core.Tests.Logging;
+
+///
+/// 表示供日志相关测试复用的内存日志记录器。
+///
+public sealed class TestLogger : AbstractLogger
+{
+ private readonly List _logs = new();
+
+ ///
+ /// 初始化 的新实例。
+ ///
+ /// 日志记录器的名称;未指定时沿用基类默认行为。
+ /// 允许写入的最小日志级别。
+ public TestLogger(string? name = null, LogLevel minLevel = LogLevel.Info) : base(name, minLevel)
+ {
+ }
+
+ ///
+ /// 获取按写入顺序保存的日志条目只读视图。
+ ///
+ public IReadOnlyList Logs => _logs;
+
+ ///
+ /// 将日志信息追加到内存列表,供断言读取。
+ ///
+ /// 日志级别。
+ /// 日志消息。
+ /// 相关异常;没有异常时为 。
+ protected override void Write(LogLevel level, string message, Exception? exception)
+ {
+ _logs.Add(new LogEntry(level, message, exception));
+ }
+
+ ///
+ /// 表示单个日志条目的不可变快照。
+ ///
+ /// 日志级别。
+ /// 日志消息。
+ /// 相关异常;没有异常时为 。
+ public sealed record LogEntry(LogLevel Level, string Message, Exception? Exception);
+}
diff --git a/GFramework.Core.Tests/Resource/ResourceManagerTests.cs b/GFramework.Core.Tests/Resource/ResourceManagerTests.cs
index dba15f62..d91f447b 100644
--- a/GFramework.Core.Tests/Resource/ResourceManagerTests.cs
+++ b/GFramework.Core.Tests/Resource/ResourceManagerTests.cs
@@ -1,58 +1,8 @@
-using System.IO;
-using GFramework.Core.Abstractions.Resource;
using GFramework.Core.Resource;
using NUnit.Framework;
namespace GFramework.Core.Tests.Resource;
-///
-/// 测试用的简单资源类
-///
-public class TestResource
-{
- public string Content { get; set; } = string.Empty;
- public bool IsDisposed { get; set; }
-}
-
-///
-/// 测试用的资源加载器
-///
-public class TestResourceLoader : IResourceLoader
-{
- private readonly Dictionary _resourceData = new();
-
- public TestResource Load(string path)
- {
- if (_resourceData.TryGetValue(path, out var content))
- {
- return new TestResource { Content = content };
- }
-
- throw new FileNotFoundException($"Resource not found: {path}");
- }
-
- public async Task LoadAsync(string path)
- {
- await Task.Delay(10).ConfigureAwait(false); // 模拟异步加载
- return Load(path);
- }
-
- public void Unload(TestResource resource)
- {
- resource.IsDisposed = true;
- }
-
- public bool CanLoad(string path)
- {
- return _resourceData.ContainsKey(path);
- }
-
- public void AddTestData(string path, string content)
- {
- _resourceData[path] = content;
- }
-}
-
///
/// ResourceManager 功能测试类
///
diff --git a/GFramework.Core.Tests/Resource/TestResource.cs b/GFramework.Core.Tests/Resource/TestResource.cs
new file mode 100644
index 00000000..a9f78cae
--- /dev/null
+++ b/GFramework.Core.Tests/Resource/TestResource.cs
@@ -0,0 +1,17 @@
+namespace GFramework.Core.Tests.Resource;
+
+///
+/// 表示 ResourceManager 测试使用的简单资源对象。
+///
+public class TestResource
+{
+ ///
+ /// 获取或设置资源内容。
+ ///
+ public string Content { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置一个值,指示资源是否已经被测试加载器标记为已卸载。
+ ///
+ public bool IsDisposed { get; set; }
+}
diff --git a/GFramework.Core.Tests/Resource/TestResourceLoader.cs b/GFramework.Core.Tests/Resource/TestResourceLoader.cs
new file mode 100644
index 00000000..5dcf6a14
--- /dev/null
+++ b/GFramework.Core.Tests/Resource/TestResourceLoader.cs
@@ -0,0 +1,52 @@
+using System.IO;
+using GFramework.Core.Abstractions.Resource;
+
+namespace GFramework.Core.Tests.Resource;
+
+///
+/// 为 ResourceManager 测试提供可控数据源的资源加载器。
+///
+public class TestResourceLoader : IResourceLoader
+{
+ private readonly Dictionary _resourceData = new(StringComparer.Ordinal);
+
+ ///
+ public TestResource Load(string path)
+ {
+ if (_resourceData.TryGetValue(path, out var content))
+ {
+ return new TestResource { Content = content };
+ }
+
+ throw new FileNotFoundException($"Resource not found: {path}");
+ }
+
+ ///
+ public async Task LoadAsync(string path)
+ {
+ await Task.Delay(10).ConfigureAwait(false); // 模拟异步加载
+ return Load(path);
+ }
+
+ ///
+ public void Unload(TestResource resource)
+ {
+ resource.IsDisposed = true;
+ }
+
+ ///
+ public bool CanLoad(string path)
+ {
+ return _resourceData.ContainsKey(path);
+ }
+
+ ///
+ /// 向测试加载器注册一条可返回的资源数据。
+ ///
+ /// 资源路径。
+ /// 资源内容。
+ public void AddTestData(string path, string content)
+ {
+ _resourceData[path] = content;
+ }
+}
diff --git a/ai-plan/public/analyzer-warning-reduction/todos/analyzer-warning-reduction-tracking.md b/ai-plan/public/analyzer-warning-reduction/todos/analyzer-warning-reduction-tracking.md
index 13d194c0..4c823765 100644
--- a/ai-plan/public/analyzer-warning-reduction/todos/analyzer-warning-reduction-tracking.md
+++ b/ai-plan/public/analyzer-warning-reduction/todos/analyzer-warning-reduction-tracking.md
@@ -6,53 +6,41 @@
## 当前恢复点
-- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-086`
-- 当前阶段:`Phase 86`
+- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-087`
+- 当前阶段:`Phase 87`
- 当前焦点:
- - `2026-04-27` 已按 `$gframework-batch-boot 100` 连续执行多波 `MA0048` 小切片,当前以 `GFramework.Core.Tests` 的测试辅助类型拆分为主
- - `2026-04-27` 已按 `$gframework-pr-review` 收敛 `PR #298` 的有效 nitpick,修复测试辅助类型的只读暴露、线程安全、空安全与文档一致性问题
- - 本轮已完成 `ArchitectureContextTests`、`AsyncQueryExecutorTests`、`CommandExecutorTests`、`StateTests`、`StateMachineTests`、`StateMachineSystemTests`、`ArchitectureModulesBehaviorTests`、`ArchitectureAdditionalCqrsHandlersTests`、`QueryCoroutineExtensionsTests`、`ObjectPoolTests`、`AbstractContextUtilityTests` 等低风险单文件切片
- - 当前仓库根权威基线已从 `353 Warning(s)` / `279` 个唯一位点下降到 `288 Warning(s)` / `214` 个唯一位点
- - 当前分支下一波更适合转向 `GameContextTests.cs`、`ArchitectureServicesTests.cs`、`RegistryInitializationHookBaseTests.cs` 这类仍在 `GFramework.Core.Tests` 内、但已混入 `CS8766` / `MA0016` 的小型混合切片
+ - `2026-04-28` 已按 `$gframework-batch-boot 50` 先执行仓库根 `dotnet clean` + `dotnet build`,建立本轮权威基线 `288 Warning(s)` / `214` 个唯一位点
+ - 本轮已并行收敛 `GameContextTests.cs`、`ArchitectureServicesTests.cs`、`RegistryInitializationHookBaseTests.cs`、`CqrsDispatcherCacheTests.cs` 与 `CqrsHandlerRegistrarTests.cs`
+ - 主线程已补齐 `ResourceManagerTests.cs`、`TestEvent.cs`、`LoggerTests.cs`、`ContextProviderTests.cs`、`TestArchitectureBase.cs`、`CommandCoroutineExtensionsTests.cs` 等 `Core.Tests` 零散 warning
+ - 当前 `GFramework.Core.Tests` 与 `GFramework.Cqrs.Tests` 的受影响项目 Release 构建都已恢复到 `0 Warning(s)` / `0 Error(s)`
+ - 当前仓库根权威基线已从本轮开始时的 `288 Warning(s)` / `214` 个唯一位点下降到 `236 Warning(s)` / `162` 个唯一位点;剩余 warning 只集中在 `Mediator/*` 与 `YamlConfigSchemaValidator*`
## 当前活跃事实
-- 当前 `origin/main` 基线提交为 `7cfdd2c`(`2026-04-27T16:59:57+08:00`)。
+- 当前 `origin/main` 基线提交为 `6cc87a9`(`2026-04-27T20:28:50+08:00`)。
- 当前直接验证结果:
- - `dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release`
- - 最新结果:成功;`28 Warning(s)`、`0 Error(s)`;当前 warning 来自 `GameContextTests.cs`、`ArchitectureServicesTests.cs`、`RegistryInitializationHookBaseTests.cs` 等既有热点
- - `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build`
- - 最新结果:成功;`1610` 通过、`0` 失败
- `dotnet clean`
- - 最新结果:成功;已刷新仓库根 non-incremental 基线
+ - 最新结果:成功;已刷新本轮 final non-incremental 仓库根基线
- `dotnet build`
- - 最新结果:成功;`288 Warning(s)`、`0 Error(s)`,唯一位点 `214`
- - `dotnet build GFramework.Game/GFramework.Game.csproj -c Release`
+ - 最新结果:成功;`236 Warning(s)`、`0 Error(s)`,唯一位点 `162`
+ - `dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release`
+ - 最新结果:成功;`0 Warning(s)`、`0 Error(s)`
+ - `dotnet build GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release`
- 最新结果:成功;`0 Warning(s)`、`0 Error(s)`
- - `dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "FullyQualifiedName~YamlConfigLoaderTests.ReadYamlAsync_Should_Preserve_OperationCanceledException_When_Cancellation_Is_Requested"`
- - 最新结果:成功;`1` 通过、`0` 失败
- - `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~MicrosoftDiContainerTests.GetAllByPriority_Should_Sort_By_Priority_Ascending"`
- - 最新结果:成功;`1` 通过、`0` 失败
- - `dotnet format GFramework.sln --verify-no-changes --include GFramework.Game/Config/YamlConfigLoader.cs GFramework.Game.Tests/Config/YamlConfigLoaderTests.cs GFramework.Core.Tests/Ioc/IMixedService.cs GFramework.Core.Tests/Ioc/IPrioritizedService.cs GFramework.Core.Tests/Ioc/PrioritizedService.cs GFramework.Core.Tests/Query/TestAsyncQueryWithExceptionV4.cs`
- - 最新结果:成功;本次 PR follow-up 改动文件无需额外格式化
- 当前批次摘要:
- - 本轮通过多批并行 worker 共完成 `20+` 个 `GFramework.Core.Tests` 文件的测试辅助类型拆分,集中消化纯 `MA0048` warning 热点
- - 本轮停止时共享工作树共有 `61` 个变更条目,仍低于 `$gframework-batch-boot 100` 的文件停止线
- - 本轮仓库根权威 warning 已从开始时的 `353` 下降到 `288`,且 `GFramework.Core.Tests` 受影响项目的 Release 构建已恢复到 `0 Warning(s)` / `0 Error(s)`
+ - 本轮接受并集成 `GameContextTests.cs`、`ArchitectureServicesTests.cs`、`RegistryInitializationHookBaseTests.cs`、`CqrsDispatcherCacheTests.cs`、`CqrsHandlerRegistrarTests.cs` 五个并行 worker 切片
+ - 主线程补齐 `Core.Tests` 内剩余零散 warning,使 `GFramework.Core.Tests` 项目级 Release 构建回到 `0 Warning(s)` / `0 Error(s)`
+ - 当前 `origin/main...HEAD` 已提交 branch diff 仍为 `21` 个文件;计入当前待提交工作树后的并集 footprint 为 `45 / 50` 个文件,已接近本轮停止线
- 当前建议保留到下一波次的候选:
- - `GFramework.Core.Tests/Architectures/GameContextTests.cs` 的 `4` 个 `CS8766` 与 `2` 个 `MA0048`
- - `GFramework.Core.Tests/Architectures/ArchitectureServicesTests.cs` 的 `4` 个 `CS8766` 与 `1` 个 `MA0048`
- - `GFramework.Core.Tests/Architectures/RegistryInitializationHookBaseTests.cs` 的 `1` 个 `MA0016` 与 `5` 个 `MA0048`
+ - `GFramework.Cqrs.Tests/Mediator/MediatorArchitectureIntegrationTests.cs`、`MediatorComprehensiveTests.cs`、`MediatorAdvancedFeaturesTests.cs` 的高密度 `MA0048` / `MA0004`
- `GFramework.Game/Config/YamlConfigSchemaValidator.cs` 与 `YamlConfigSchemaValidator.ObjectKeywords.cs` 的高耦合 warning 热点
## 当前风险
-- `GFramework.Cqrs.Tests/Mediator/*` 仍有 `47` / `44` / `34` 个唯一 warning 位点,属于高 changed-file 风险的 `MA0048` 大波次。
- - 缓解措施:优先继续处理 `6-7` 个 warning 的小文件切片,避免一次性推高文件数。
-- `GameContextTests.cs`、`ArchitectureServicesTests.cs` 这类混合 `CS8766` / `MA0048` 文件不再适合继续用“纯拆分”模式批量下发。
- - 缓解措施:下一波由主线程先局部修正可空签名,再决定是否继续并行拆分。
-- `YamlConfigSchemaValidator*` 仍然聚集多类高耦合 warning。
- - 缓解措施:继续把它们留在独立波次,不与测试项目的低风险拆分混提。
+- `GFramework.Cqrs.Tests/Mediator/*` 仍有 `94` / `88` / `68` 条输出 warning,属于高 changed-file 风险的 `MA0048` 大波次。
+ - 缓解措施:当前 footprint 已到 `45 / 50`,下一轮应在新提交基础上单独规划 `Mediator*` 波次,而不是继续叠在本轮工作树上。
+- `YamlConfigSchemaValidator*` 仍然聚集 `222` 条输出 warning,且同时混有 `MA0048`、`MA0009`、`MA0051`、`MA0006`。
+ - 缓解措施:保持为独立高耦合波次,不与测试项目拆分混提。
## 活跃文档
@@ -72,11 +60,11 @@
## 验证说明
- 权威验证结果统一维护在“当前活跃事实”。
-- `GFramework.Core.Tests` 项目级 Release 构建已在本轮清零,但仓库根 non-incremental 构建仍保留大量既有 warning。
+- `GFramework.Core.Tests` 与 `GFramework.Cqrs.Tests` 的当前受影响项目 Release 构建都已在本轮清零,但仓库根 non-incremental 构建仍保留 `Mediator/*` 与 `YamlConfigSchemaValidator*` 既有 warning。
- warning reduction 的仓库级真值只以同轮 `dotnet clean` 后的 `dotnet build` 为准。
## 下一步建议
-1. 提交本轮多批 `MA0048` warning reduction 与 `ai-plan` 同步。
-2. 下一波由主线程先处理 `GameContextTests.cs` / `ArchitectureServicesTests.cs` 的 `CS8766`,再决定是否继续拆分剩余 `MA0048`。
-3. 继续将 `YamlConfigSchemaValidator*` 与 `GFramework.Cqrs.Tests/Mediator/*` 作为独立高风险波次处理。
+1. 提交本轮 `Core.Tests` / `Cqrs.Tests` warning reduction 与 `ai-plan` 同步。
+2. 下一轮在新提交基础上单独规划 `Mediator/*` 波次,避免在 `45 / 50` footprint 状态继续扩批。
+3. 将 `YamlConfigSchemaValidator*` 保持为独立高耦合波次,必要时先由主线程局部切分再决定是否并行。
diff --git a/ai-plan/public/analyzer-warning-reduction/traces/analyzer-warning-reduction-trace.md b/ai-plan/public/analyzer-warning-reduction/traces/analyzer-warning-reduction-trace.md
index b57f4b67..edbc3a06 100644
--- a/ai-plan/public/analyzer-warning-reduction/traces/analyzer-warning-reduction-trace.md
+++ b/ai-plan/public/analyzer-warning-reduction/traces/analyzer-warning-reduction-trace.md
@@ -1,5 +1,55 @@
# Analyzer Warning Reduction 追踪
+## 2026-04-28 — RP-087
+
+### 阶段:按 `$gframework-batch-boot 50` 并行收敛 `Core.Tests` / `Cqrs.Tests` 低风险切片
+
+- 触发背景:
+ - 用户再次要求先拿仓库根构建 warning,再把可切分的 warning 批次分派给多个 subagent,以降低主线程上下文压力
+ - 当前分支与 `origin/main@6cc87a9` 无提交差异,适合从单文件和小型混合 warning 切片重新起步
+- 主线程实施:
+ - 先执行仓库规则要求的 non-incremental 基线:`dotnet restore GFramework.sln -p:RestoreFallbackFolders=` 以修复当前 WSL 环境里的旧 fallback 资产,再执行仓库根 `dotnet clean` + `dotnet build`
+ - 基线结果:`288 Warning(s)`、唯一位点 `214`
+ - 并行下发四个 disjoint worker:
+ - `GameContextTests.cs`
+ - `ArchitectureServicesTests.cs`
+ - `RegistryInitializationHookBaseTests.cs`
+ - `CqrsDispatcherCacheTests.cs`
+ - 主线程补齐不与 worker 重叠的零散切片:
+ - `ResourceManagerTests.cs`
+ - `TestEvent.cs`
+ - `EventListenerScopeTests.cs`
+ - `TestArchitectureBase.cs`
+ - `ContextProviderTests.cs`
+ - `LoggerTests.cs`
+ - `LoggingConfigurationTests.cs`
+ - `WaitForMultipleEventsTests.cs`
+ - `CommandCoroutineExtensionsTests.cs`
+ - 集成 `GameContextTests`、`CqrsDispatcherCacheTests` 与 `CqrsHandlerRegistrarTests` worker 产出的 commit `a7be413` / `9098490` / `98afcbf`,并接受已直接落到共享工作树的 `ArchitectureServicesTests` / `RegistryInitializationHookBaseTests` 切片
+ - 重新执行仓库根 `dotnet clean` + `dotnet build`
+ - final 结果:`236 Warning(s)`、唯一位点 `162`
+- 验证里程碑:
+ - `dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release`
+ - 结果:成功;`0 Warning(s)`、`0 Error(s)`
+ - `dotnet build GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release`
+ - 结果:成功;`0 Warning(s)`、`0 Error(s)`
+ - `dotnet clean`
+ - 结果:成功
+ - `dotnet build`
+ - 结果:成功;`236 Warning(s)`、`0 Error(s)`,唯一位点 `162`
+ - `git diff --name-only refs/remotes/origin/main...HEAD | wc -l`
+ - 结果:`21`
+ - 已提交 diff 与当前工作树变更并集文件数
+ - 结果:`45 / 50`
+- 当前结论:
+ - 本轮已经把剩余 `Core.Tests` warning 全部清空,并把 `CqrsDispatcherCacheTests.cs` 与 `CqrsHandlerRegistrarTests.cs` 这两处 `Cqrs.Tests` 单文件 `MA0048` 热点从仓库根中移除
+ - 仓库根权威 warning 从 `288` 下降到 `236`,唯一位点从 `214` 下降到 `162`
+ - 在 `45 / 50` footprint 下,继续扩批将明显压缩 review 余量;剩余切片也只剩 `Mediator*` 与 `YamlConfigSchemaValidator*` 这两组高风险热点,因此本轮应在这里收口
+- 下一步:
+ 1. 提交本轮已验证的 warning reduction 与 `ai-plan` 同步。
+ 2. 下一轮在新提交基础上单独规划 `Mediator*` 波次。
+ 3. 将 `YamlConfigSchemaValidator*` 保持为独立高耦合波次,再决定是否需要新的并行切法。
+
## 2026-04-27 — RP-086
### 阶段:收敛 PR #298 的 CodeRabbit nitpick follow-up