fix(core-tests): 收敛PR298的nitpick问题

- 修复测试辅助类型的只读暴露、空安全和线程安全问题

- 更新异步查询结果命名与init属性XML文档,保持语义一致

- 同步ai-plan恢复点与验证真值,记录PR298 nitpick跟进
This commit is contained in:
gewuyou 2026-04-27 20:18:58 +08:00
parent f0a36de07c
commit fbf8f9f0a2
23 changed files with 95 additions and 48 deletions

View File

@ -11,7 +11,7 @@ public sealed class TestCommandWithResultV2 : ICommand<int>
private IArchitectureContext _context = null!; private IArchitectureContext _context = null!;
/// <summary> /// <summary>
/// 获取或设置命令执行结果。 /// 获取命令执行结果;该值只能在对象初始化阶段设置
/// </summary> /// </summary>
public int Result { get; init; } public int Result { get; init; }

View File

@ -11,7 +11,7 @@ public sealed class TestQueryV2 : IQuery<int>
private IArchitectureContext _context = null!; private IArchitectureContext _context = null!;
/// <summary> /// <summary>
/// 获取或设置查询返回值。 /// 获取查询返回值;该值只能在对象初始化阶段设置
/// </summary> /// </summary>
public int Result { get; init; } public int Result { get; init; }

View File

@ -1,3 +1,4 @@
using System.Threading;
using GFramework.Cqrs.Abstractions.Cqrs; using GFramework.Cqrs.Abstractions.Cqrs;
namespace GFramework.Core.Tests.Architectures; namespace GFramework.Core.Tests.Architectures;
@ -10,13 +11,20 @@ namespace GFramework.Core.Tests.Architectures;
public sealed class TrackingPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> public sealed class TrackingPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse> where TRequest : IRequest<TResponse>
{ {
/// <summary> private static int _invocationCount;
/// 获取当前测试进程中该请求类型对应的行为触发次数。
/// </summary>
public static int InvocationCount { get; set; }
/// <summary> /// <summary>
/// 记录一次行为执行,然后继续执行下一个处理器。 /// 获取当前测试进程中该请求类型对应的行为触发次数。
/// 该计数器是按泛型闭包共享的静态状态,测试需要在每次运行前显式重置。
/// </summary>
public static int InvocationCount
{
get => Volatile.Read(ref _invocationCount);
set => Volatile.Write(ref _invocationCount, value);
}
/// <summary>
/// 以线程安全方式记录一次行为执行,然后继续执行下一个处理器。
/// </summary> /// </summary>
/// <param name="message">当前请求消息。</param> /// <param name="message">当前请求消息。</param>
/// <param name="next">下一个处理委托。</param> /// <param name="next">下一个处理委托。</param>
@ -27,7 +35,7 @@ public sealed class TrackingPipelineBehavior<TRequest, TResponse> : IPipelineBeh
MessageHandlerDelegate<TRequest, TResponse> next, MessageHandlerDelegate<TRequest, TResponse> next,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
InvocationCount++; Interlocked.Increment(ref _invocationCount);
return await next(message, cancellationToken).ConfigureAwait(false); return await next(message, cancellationToken).ConfigureAwait(false);
} }
} }

View File

@ -43,7 +43,8 @@ internal class ComplexQuery : IQuery<ComplexResult>
/// <returns>此前通过 <see cref="SetContext" /> 绑定的上下文实例。</returns> /// <returns>此前通过 <see cref="SetContext" /> 绑定的上下文实例。</returns>
public IArchitectureContext GetContext() public IArchitectureContext GetContext()
{ {
return _context!; return _context ?? throw new InvalidOperationException(
$"{nameof(SetContext)} must be called before {nameof(GetContext)}.");
} }
/// <summary> /// <summary>

View File

@ -5,7 +5,7 @@ namespace GFramework.Core.Tests.Coroutine;
/// <summary> /// <summary>
/// 为协程测试提供固定时间步长的时间源。 /// 为协程测试提供固定时间步长的时间源。
/// </summary> /// </summary>
public class TestTimeSource : ITimeSource public sealed class TestTimeSource : ITimeSource
{ {
/// <summary> /// <summary>
/// 获取当前累计时间。 /// 获取当前累计时间。

View File

@ -49,7 +49,7 @@ public class EnvironmentTests
[Test] [Test]
public void Get_Should_Return_Value_When_Key_Exists() public void Get_Should_Return_Value_When_Key_Exists()
{ {
_environment.Register("testKey", "testValue"); _environment.RegisterForTest("testKey", "testValue");
var result = _environment.Get<string>("testKey"); var result = _environment.Get<string>("testKey");
@ -73,7 +73,7 @@ public class EnvironmentTests
[Test] [Test]
public void Get_Should_ReturnNull_When_Type_Does_Not_Match() public void Get_Should_ReturnNull_When_Type_Does_Not_Match()
{ {
_environment.Register("testKey", "testValue"); _environment.RegisterForTest("testKey", "testValue");
var result = _environment.Get<List<int>>("testKey"); var result = _environment.Get<List<int>>("testKey");
@ -86,7 +86,7 @@ public class EnvironmentTests
[Test] [Test]
public void TryGet_Should_ReturnTrue_And_Value_When_Key_Exists() public void TryGet_Should_ReturnTrue_And_Value_When_Key_Exists()
{ {
_environment.Register("testKey", "testValue"); _environment.RegisterForTest("testKey", "testValue");
var result = _environment.TryGet<string>("testKey", out var value); var result = _environment.TryGet<string>("testKey", out var value);
@ -112,7 +112,7 @@ public class EnvironmentTests
[Test] [Test]
public void TryGet_Should_ReturnFalse_When_Type_Does_Not_Match() public void TryGet_Should_ReturnFalse_When_Type_Does_Not_Match()
{ {
_environment.Register("testKey", "testValue"); _environment.RegisterForTest("testKey", "testValue");
var result = _environment.TryGet<List<int>>("testKey", out var value); var result = _environment.TryGet<List<int>>("testKey", out var value);
@ -126,7 +126,7 @@ public class EnvironmentTests
[Test] [Test]
public void GetRequired_Should_Return_Value_When_Key_Exists() public void GetRequired_Should_Return_Value_When_Key_Exists()
{ {
_environment.Register("testKey", "testValue"); _environment.RegisterForTest("testKey", "testValue");
var result = _environment.GetRequired<string>("testKey"); var result = _environment.GetRequired<string>("testKey");
@ -149,7 +149,7 @@ public class EnvironmentTests
[Test] [Test]
public void Register_Should_Add_Value_To_Dictionary() public void Register_Should_Add_Value_To_Dictionary()
{ {
_environment.Register("newKey", "newValue"); _environment.RegisterForTest("newKey", "newValue");
var result = _environment.Get<string>("newKey"); var result = _environment.Get<string>("newKey");
@ -162,8 +162,8 @@ public class EnvironmentTests
[Test] [Test]
public void Register_Should_Overwrite_Existing_Value() public void Register_Should_Overwrite_Existing_Value()
{ {
_environment.Register("testKey", "value1"); _environment.RegisterForTest("testKey", "value1");
_environment.Register("testKey", "value2"); _environment.RegisterForTest("testKey", "value2");
var result = _environment.Get<string>("testKey"); var result = _environment.Get<string>("testKey");

View File

@ -5,7 +5,7 @@ namespace GFramework.Core.Tests.Environment;
/// <summary> /// <summary>
/// 为环境相关测试提供可写注册入口的测试环境实现。 /// 为环境相关测试提供可写注册入口的测试环境实现。
/// </summary> /// </summary>
public class TestEnvironment : EnvironmentBase public sealed class TestEnvironment : EnvironmentBase
{ {
/// <summary> /// <summary>
/// 获取测试环境名称。 /// 获取测试环境名称。
@ -13,11 +13,11 @@ public class TestEnvironment : EnvironmentBase
public override string Name { get; } = "TestEnvironment"; public override string Name { get; } = "TestEnvironment";
/// <summary> /// <summary>
/// 将测试数据注册到基础环境存储中,便于测试通过公开入口准备上下文。 /// 将测试数据注册到基础环境存储中,便于测试通过显式测试辅助入口准备上下文。
/// </summary> /// </summary>
/// <param name="key">要注册的环境键。</param> /// <param name="key">要注册的环境键。</param>
/// <param name="value">要注册的环境值。</param> /// <param name="value">要注册的环境值。</param>
public new void Register(string key, object value) public void RegisterForTest(string key, object value)
{ {
base.Register(key, value); base.Register(key, value);
} }

View File

@ -212,7 +212,7 @@ public class AbstractAsyncQueryTests
Assert.That(result, Is.Not.Null); Assert.That(result, Is.Not.Null);
Assert.That(result.Value, Is.EqualTo(20)); Assert.That(result.Value, Is.EqualTo(20));
Assert.That(result.DoubleValue, Is.EqualTo(30)); Assert.That(result.TripleValue, Is.EqualTo(30));
} }
/// <summary> /// <summary>

View File

@ -87,7 +87,7 @@ public class AsyncQueryExecutorTests
Assert.That(result, Is.Not.Null); Assert.That(result, Is.Not.Null);
Assert.That(result.Value, Is.EqualTo(200)); Assert.That(result.Value, Is.EqualTo(200));
Assert.That(result.DoubleValue, Is.EqualTo(300)); Assert.That(result.TripleValue, Is.EqualTo(300));
} }
/// <summary> /// <summary>

View File

@ -25,7 +25,7 @@ public sealed class TestAsyncComplexQuery : AbstractAsyncQuery<TestAsyncQueryInp
var result = new TestAsyncQueryResult var result = new TestAsyncQueryResult
{ {
Value = input.Value * 2, Value = input.Value * 2,
DoubleValue = input.Value * 3 TripleValue = input.Value * 3
}; };
return Task.FromResult(result); return Task.FromResult(result);

View File

@ -31,7 +31,7 @@ public sealed class TestAsyncComplexQueryV4 : AbstractAsyncQuery<TestAsyncQueryI
var result = new TestAsyncQueryResultV2 var result = new TestAsyncQueryResultV2
{ {
Value = input.Value * 2, Value = input.Value * 2,
DoubleValue = input.Value * 3 TripleValue = input.Value * 3
}; };
return Task.FromResult(result); return Task.FromResult(result);
} }

View File

@ -8,7 +8,7 @@ namespace GFramework.Core.Tests.Query;
public sealed class TestAsyncQueryInput : IQueryInput public sealed class TestAsyncQueryInput : IQueryInput
{ {
/// <summary> /// <summary>
/// 获取或设置查询值。 /// 获取查询值;该值只能在对象初始化阶段设置
/// </summary> /// </summary>
public int Value { get; init; } public int Value { get; init; }
} }

View File

@ -6,12 +6,12 @@ namespace GFramework.Core.Tests.Query;
public sealed class TestAsyncQueryResult public sealed class TestAsyncQueryResult
{ {
/// <summary> /// <summary>
/// 获取或设置主结果值。 /// 获取主结果值;该值只能在对象初始化阶段设置
/// </summary> /// </summary>
public int Value { get; init; } public int Value { get; init; }
/// <summary> /// <summary>
/// 获取或设置派生的双重结果值 /// 获取派生的三倍结果值;该值只能在对象初始化阶段设置
/// </summary> /// </summary>
public int DoubleValue { get; init; } public int TripleValue { get; init; }
} }

View File

@ -6,12 +6,12 @@ namespace GFramework.Core.Tests.Query;
public sealed class TestAsyncQueryResultV2 public sealed class TestAsyncQueryResultV2
{ {
/// <summary> /// <summary>
/// 获取或设置值 /// 获取值;该值只能在对象初始化阶段设置。
/// </summary> /// </summary>
public int Value { get; init; } public int Value { get; init; }
/// <summary> /// <summary>
/// 获取或设置双倍值 /// 获取三倍值;该值只能在对象初始化阶段设置。
/// </summary> /// </summary>
public int DoubleValue { get; init; } public int TripleValue { get; init; }
} }

View File

@ -245,7 +245,7 @@ public class StateMachineTests
[Test] [Test]
public async Task ChangeToAsync_WhenCurrentStateDeniesTransition_WithAsyncState_Should_Call_CanTransitionToAsync() public async Task ChangeToAsync_WhenCurrentStateDeniesTransition_WithAsyncState_Should_Call_CanTransitionToAsync()
{ {
var state1 = new TestAsyncState { AllowTransition = false }; var state1 = new TestAsyncState { AllowTransitions = false };
var state2 = new TestStateV3(); var state2 = new TestStateV3();
_stateMachine.Register(state1); _stateMachine.Register(state1);
_stateMachine.Register(state2); _stateMachine.Register(state2);

View File

@ -10,7 +10,7 @@ public sealed class TestAsyncState : IState, IAsyncState
/// <summary> /// <summary>
/// 获取或设置是否允许向目标状态转移。 /// 获取或设置是否允许向目标状态转移。
/// </summary> /// </summary>
public bool AllowTransition { get; set; } = true; public bool AllowTransitions { get; set; } = true;
/// <summary> /// <summary>
/// 获取异步进入状态是否已被调用。 /// 获取异步进入状态是否已被调用。
@ -80,7 +80,7 @@ public sealed class TestAsyncState : IState, IAsyncState
{ {
await Task.Delay(1).ConfigureAwait(false); await Task.Delay(1).ConfigureAwait(false);
CanTransitionToCallCount++; CanTransitionToCallCount++;
return AllowTransition; return AllowTransitions;
} }
/// <summary> /// <summary>

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using GFramework.Core.Abstractions.State; using GFramework.Core.Abstractions.State;
using GFramework.Core.State; using GFramework.Core.State;
@ -14,8 +15,8 @@ public class TestStateMachineSystemV5 : StateMachineSystem
/// 获取状态机当前维护的状态实例映射,供测试断言注册结果使用。 /// 获取状态机当前维护的状态实例映射,供测试断言注册结果使用。
/// </summary> /// </summary>
/// <returns>状态类型到状态实例的只读视图。</returns> /// <returns>状态类型到状态实例的只读视图。</returns>
public IDictionary<Type, IState> GetStates() public IReadOnlyDictionary<Type, IState> GetStates()
{ {
return States; return States as IReadOnlyDictionary<Type, IState> ?? new ReadOnlyDictionary<Type, IState>(States);
} }
} }

View File

@ -19,6 +19,7 @@ public class TestStateV5_2 : IState
/// <returns>始终返回 <see langword="true" /> 以简化状态机切换测试。</returns> /// <returns>始终返回 <see langword="true" /> 以简化状态机切换测试。</returns>
public bool CanTransitionTo(IState next) public bool CanTransitionTo(IState next)
{ {
_ = next;
return true; return true;
} }
@ -28,6 +29,7 @@ public class TestStateV5_2 : IState
/// <param name="previous">前一个状态。</param> /// <param name="previous">前一个状态。</param>
public void OnEnter(IState? previous) public void OnEnter(IState? previous)
{ {
_ = previous;
} }
/// <summary> /// <summary>
@ -36,5 +38,6 @@ public class TestStateV5_2 : IState
/// <param name="next">下一个状态。</param> /// <param name="next">下一个状态。</param>
public void OnExit(IState? next) public void OnExit(IState? next)
{ {
_ = next;
} }
} }

View File

@ -198,7 +198,7 @@ public class AbstractContextUtilityTests
Assert.That(utility.Destroyed, Is.True); Assert.That(utility.Destroyed, Is.True);
// 重置状态 // 重置状态
utility.Destroyed = false; utility.ResetDestroyedStateForTest();
// 第二次初始化和销毁 // 第二次初始化和销毁
utility.Initialize(); utility.Initialize();

View File

@ -14,12 +14,13 @@ public sealed class TestContextUtilityV1 : AbstractContextUtility
public bool Initialized { get; private set; } public bool Initialized { get; private set; }
/// <summary> /// <summary>
/// 获取或设置一个值,该值指示当前工具是否已执行销毁逻辑。 /// 获取一个值,该值指示当前工具是否已执行销毁逻辑。
/// </summary> /// </summary>
public bool Destroyed { get; set; } public bool Destroyed { get; private set; }
/// <summary> /// <summary>
/// 获取一个值,该值指示测试初始化钩子是否已被调用。 /// 获取一个值,该值指示测试专用的 <see cref="OnInit" /> 钩子是否已被调用。
/// 该标记与 <see cref="Initialized" /> 共享同一执行时机,但单独暴露以便断言钩子本身已运行。
/// </summary> /// </summary>
public bool InitCalled { get; private set; } public bool InitCalled { get; private set; }
@ -48,4 +49,12 @@ public sealed class TestContextUtilityV1 : AbstractContextUtility
{ {
Destroyed = true; Destroyed = true;
} }
/// <summary>
/// 重置销毁标记,供同一实例的重复生命周期测试在下一轮初始化前清理观测状态。
/// </summary>
public void ResetDestroyedStateForTest()
{
Destroyed = false;
}
} }

View File

@ -13,9 +13,9 @@ public sealed class TestContextUtilityV2 : AbstractContextUtility
public bool Initialized { get; private set; } public bool Initialized { get; private set; }
/// <summary> /// <summary>
/// 获取或设置一个值,该值指示当前工具是否已执行销毁逻辑。 /// 获取一个值,该值指示当前工具是否已执行销毁逻辑。
/// </summary> /// </summary>
public bool Destroyed { get; set; } public bool Destroyed { get; private set; }
/// <summary> /// <summary>
/// 获取一个值,该值指示自定义初始化步骤是否已完成。 /// 获取一个值,该值指示自定义初始化步骤是否已完成。

View File

@ -6,10 +6,11 @@
## 当前恢复点 ## 当前恢复点
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-085` - 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-086`
- 当前阶段:`Phase 85` - 当前阶段:`Phase 86`
- 当前焦点: - 当前焦点:
- `2026-04-27` 已按 `$gframework-batch-boot 100` 连续执行多波 `MA0048` 小切片,当前以 `GFramework.Core.Tests` 的测试辅助类型拆分为主 - `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` 等低风险单文件切片 - 本轮已完成 `ArchitectureContextTests``AsyncQueryExecutorTests``CommandExecutorTests``StateTests``StateMachineTests``StateMachineSystemTests``ArchitectureModulesBehaviorTests``ArchitectureAdditionalCqrsHandlersTests``QueryCoroutineExtensionsTests``ObjectPoolTests``AbstractContextUtilityTests` 等低风险单文件切片
- 当前仓库根权威基线已从 `353 Warning(s)` / `279` 个唯一位点下降到 `288 Warning(s)` / `214` 个唯一位点 - 当前仓库根权威基线已从 `353 Warning(s)` / `279` 个唯一位点下降到 `288 Warning(s)` / `214` 个唯一位点
- 当前分支下一波更适合转向 `GameContextTests.cs``ArchitectureServicesTests.cs``RegistryInitializationHookBaseTests.cs` 这类仍在 `GFramework.Core.Tests` 内、但已混入 `CS8766` / `MA0016` 的小型混合切片 - 当前分支下一波更适合转向 `GameContextTests.cs``ArchitectureServicesTests.cs``RegistryInitializationHookBaseTests.cs` 这类仍在 `GFramework.Core.Tests` 内、但已混入 `CS8766` / `MA0016` 的小型混合切片
@ -19,15 +20,15 @@
- 当前 `origin/main` 基线提交为 `7cfdd2c``2026-04-27T16:59:57+08:00`)。 - 当前 `origin/main` 基线提交为 `7cfdd2c``2026-04-27T16:59:57+08:00`)。
- 当前直接验证结果: - 当前直接验证结果:
- `dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release` - `dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release`
- 最新结果:成功;`0 Warning(s)``0 Error(s)` - 最新结果:成功;`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` - `dotnet clean`
- 最新结果:成功;已刷新仓库根 non-incremental 基线 - 最新结果:成功;已刷新仓库根 non-incremental 基线
- `dotnet build` - `dotnet build`
- 最新结果:成功;`288 Warning(s)``0 Error(s)`,唯一位点 `214` - 最新结果:成功;`288 Warning(s)``0 Error(s)`,唯一位点 `214`
- `dotnet build GFramework.Game/GFramework.Game.csproj -c Release` - `dotnet build GFramework.Game/GFramework.Game.csproj -c Release`
- 最新结果:成功;`0 Warning(s)``0 Error(s)` - 最新结果:成功;`0 Warning(s)``0 Error(s)`
- `dotnet build GFramework.Core.Tests/GFramework.Core.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"` - `dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "FullyQualifiedName~YamlConfigLoaderTests.ReadYamlAsync_Should_Preserve_OperationCanceledException_When_Cancellation_Is_Requested"`
- 最新结果:成功;`1` 通过、`0` 失败 - 最新结果:成功;`1` 通过、`0` 失败
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~MicrosoftDiContainerTests.GetAllByPriority_Should_Sort_By_Priority_Ascending"` - `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~MicrosoftDiContainerTests.GetAllByPriority_Should_Sort_By_Priority_Ascending"`

View File

@ -1,5 +1,29 @@
# Analyzer Warning Reduction 追踪 # Analyzer Warning Reduction 追踪
## 2026-04-27 — RP-086
### 阶段:收敛 PR #298 的 CodeRabbit nitpick follow-up
- 触发背景:
- 用户再次执行 `$gframework-pr-review` 后,要求按 `PR #298` 的 nitpick comments 收敛仍然适用的问题
- 复核 PR 真值后确认当前分支无 failed checks、无 open review threads但仍有一批测试辅助类型的可维护性 nitpick 值得本地落地
- 主线程实施:
- 校验 `TestStateMachineSystemV5``ComplexQuery``TrackingPipelineBehavior``TestEnvironment``TestContextUtilityV1/V2` 等改动后,分别修复可变内部状态暴露、`_context!` 空抑制、静态计数器非原子递增、`new Register(...)` 测试辅助入口和生命周期标记公开 setter 问题
- 统一更新 `TestQueryV2``TestCommandWithResultV2``TestAsyncQueryInput``TestAsyncQueryResult*` 的 XML 文档,使 `init` 属性语义与文档一致
- 将三倍结果属性从 `DoubleValue` 更名为 `TripleValue`,同步更新 `TestAsyncComplexQuery*` 与相关断言,避免名称与 `* 3` 的行为不一致
- 精简 active tracking移除重复的 `GFramework.Core.Tests` Release build 记录,并把该项目的当前真值修正为 `28 Warning(s)`
- 验证里程碑:
- `dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release`
- 结果:成功;`28 Warning(s)``0 Error(s)`
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-build`
- 结果:成功;`1610` 通过、`0` 失败
- 当前结论:
- `PR #298` 中仍然适用的低风险 nitpick 已完成收敛,且没有为当前 touched files 引入新的构建 warning 或测试回归
- `GFramework.Core.Tests` 的剩余 warning 仍集中在 `GameContextTests.cs``ArchitectureServicesTests.cs``RegistryInitializationHookBaseTests.cs` 等既有热点,不属于本轮 nitpick follow-up 新引入问题
- 下一步:
1. 提交本轮 `PR #298` nitpick follow-up 与 `ai-plan` 同步。
2. 回到 `GameContextTests.cs` / `ArchitectureServicesTests.cs``CS8766` warning reduction 主线。
## 2026-04-27 — RP-085 ## 2026-04-27 — RP-085
### 阶段:按 `$gframework-batch-boot 100` 并行消化 `GFramework.Core.Tests` 低风险 `MA0048` ### 阶段:按 `$gframework-batch-boot 100` 并行消化 `GFramework.Core.Tests` 低风险 `MA0048`