mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
fix(core): 修复 PR 评审指出的编译与样式问题
- 修复 AsyncExtensionsTests 中错误返回 ConfiguredTaskAwaitable 导致的测试编译失败 - 收敛多处测试中的冗余 async/await 与 ValueTask 断言包装,减少 PR review 指出的告警 - 更新 StoreSelection 的 net9+ 锁实现与 analyzer-warning-reduction 跟踪文档,记录 PR #288 与当前 MSB4018 环境阻塞
This commit is contained in:
parent
be336b2088
commit
4740d30fb7
@ -95,7 +95,7 @@ public class ArchitectureLifecycleBehaviorTests
|
||||
/// 验证用户初始化失败时,等待 Ready 的任务会失败并进入 FailedInitialization 阶段。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task InitializeAsync_When_OnInitialize_Throws_Should_Mark_FailedInitialization()
|
||||
public void InitializeAsync_When_OnInitialize_Throws_Should_Mark_FailedInitialization()
|
||||
{
|
||||
var architecture = new PhaseTrackingArchitecture(() => throw new InvalidOperationException("boom"));
|
||||
|
||||
|
||||
@ -123,7 +123,7 @@ public sealed class AsyncKeyLockManagerTests
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotThrowAsync(() => Task.WhenAll(tasks));
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -260,8 +260,8 @@ public sealed class AsyncKeyLockManagerTests
|
||||
await cts.CancelAsync().ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Assert.CatchAsync<OperationCanceledException>(async () =>
|
||||
await manager.AcquireLockAsync("test-key", cts.Token).ConfigureAwait(false));
|
||||
Assert.CatchAsync<OperationCanceledException>(() =>
|
||||
manager.AcquireLockAsync("test-key", cts.Token).AsTask());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -302,7 +302,7 @@ public sealed class AsyncKeyLockManagerTests
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotThrowAsync(() => Task.WhenAll(tasks));
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@ -123,7 +123,7 @@ public class AsyncExtensionsTests
|
||||
// Act & Assert
|
||||
Assert.ThrowsAsync<TimeoutException>(() =>
|
||||
AsyncExtensions.WithTimeoutAsync(
|
||||
ct => Task.Delay(TimeSpan.FromSeconds(2), ct).ConfigureAwait(false),
|
||||
ct => Task.Delay(TimeSpan.FromSeconds(2), ct),
|
||||
TimeSpan.FromMilliseconds(100)));
|
||||
}
|
||||
|
||||
|
||||
@ -136,7 +136,7 @@ public class StateMachineSystemTests
|
||||
/// 测试DestroyAsync方法不抛出异常
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task DestroyAsync_Should_Not_Throw_Exception()
|
||||
public void DestroyAsync_Should_Not_Throw_Exception()
|
||||
{
|
||||
Assert.That(() => _stateMachine!.DestroyAsync(), Throws.Nothing);
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ public class AsyncArchitectureTests : ArchitectureTestsBase<AsyncTestArchitectur
|
||||
/// </summary>
|
||||
/// <returns>异步任务</returns>
|
||||
[Test]
|
||||
public async Task Architecture_Should_Stop_Initialization_When_Model_Init_Fails()
|
||||
public void Architecture_Should_Stop_Initialization_When_Model_Init_Fails()
|
||||
{
|
||||
Architecture!.AddPostRegistrationHook(a => { a.RegisterModel(new FailingModel()); });
|
||||
|
||||
@ -134,7 +134,7 @@ public class AsyncArchitectureTests : ArchitectureTestsBase<AsyncTestArchitectur
|
||||
/// </summary>
|
||||
/// <returns>异步任务</returns>
|
||||
[Test]
|
||||
public async Task InitializeAsync_Should_Handle_Exception_Correctly()
|
||||
public void InitializeAsync_Should_Handle_Exception_Correctly()
|
||||
{
|
||||
Architecture!.AddPostRegistrationHook(a =>
|
||||
a.RegisterModel(new FailingModel())
|
||||
|
||||
@ -26,19 +26,29 @@ public static class NumericExtensions
|
||||
public static bool Between<T>(this T value, T min, T max, bool inclusive = true) where T : IComparable<T>
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (min is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(min));
|
||||
}
|
||||
|
||||
if (max is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(max));
|
||||
}
|
||||
|
||||
if (min.CompareTo(max) > 0)
|
||||
{
|
||||
throw new ArgumentException($"最小值 ({min}) 不能大于最大值 ({max})", nameof(min));
|
||||
}
|
||||
|
||||
if (inclusive)
|
||||
{
|
||||
return value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0;
|
||||
}
|
||||
|
||||
return value.CompareTo(min) > 0 && value.CompareTo(max) < 0;
|
||||
}
|
||||
@ -76,7 +86,9 @@ public static class NumericExtensions
|
||||
public static float InverseLerp(this float value, float from, float to)
|
||||
{
|
||||
if (Math.Abs(to - from) < float.Epsilon)
|
||||
{
|
||||
throw new DivideByZeroException("起始值和目标值不能相等");
|
||||
}
|
||||
|
||||
return (value - from) / (to - from);
|
||||
}
|
||||
|
||||
@ -39,17 +39,25 @@ public static class StringExtensions
|
||||
public static string Truncate(this string str, int maxLength, string suffix = "...")
|
||||
{
|
||||
if (str is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(str));
|
||||
}
|
||||
|
||||
if (suffix is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(suffix));
|
||||
}
|
||||
|
||||
if (maxLength < suffix.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxLength),
|
||||
$"最大长度必须至少为后缀长度 ({suffix.Length})");
|
||||
}
|
||||
|
||||
if (str.Length <= maxLength)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
return string.Concat(str.AsSpan(0, maxLength - suffix.Length), suffix);
|
||||
}
|
||||
@ -70,10 +78,14 @@ public static class StringExtensions
|
||||
public static string Join(this IEnumerable<string> values, string separator)
|
||||
{
|
||||
if (values is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(values));
|
||||
}
|
||||
|
||||
if (separator is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(separator));
|
||||
}
|
||||
|
||||
return string.Join(separator, values);
|
||||
}
|
||||
|
||||
@ -40,7 +40,9 @@ public sealed class StoreBuilder<TState> : IStoreBuilder<TState>
|
||||
public IStoreBuilder<TState> UseMiddleware(IStoreMiddleware<TState> middleware)
|
||||
{
|
||||
if (middleware is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(middleware));
|
||||
}
|
||||
|
||||
_configurators.Add(store => store.UseMiddleware(middleware));
|
||||
return this;
|
||||
@ -111,7 +113,9 @@ public sealed class StoreBuilder<TState> : IStoreBuilder<TState>
|
||||
public IStoreBuilder<TState> AddReducer<TAction>(Func<TState, TAction, TState> reducer)
|
||||
{
|
||||
if (reducer is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(reducer));
|
||||
}
|
||||
|
||||
_configurators.Add(store => store.RegisterReducer(reducer));
|
||||
return this;
|
||||
@ -126,7 +130,9 @@ public sealed class StoreBuilder<TState> : IStoreBuilder<TState>
|
||||
public IStoreBuilder<TState> AddReducer<TAction>(IReducer<TState, TAction> reducer)
|
||||
{
|
||||
if (reducer is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(reducer));
|
||||
}
|
||||
|
||||
_configurators.Add(store => store.RegisterReducer(reducer));
|
||||
return this;
|
||||
|
||||
@ -27,7 +27,17 @@ public sealed class StoreSelection<TState, TSelected> : IReadonlyBindablePropert
|
||||
/// <summary>
|
||||
/// 保护监听器集合和底层 Store 订阅句柄的同步锁。
|
||||
/// </summary>
|
||||
#if NET9_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// net9.0 及以上目标使用专用 Lock,以满足分析器对专用同步原语的建议。
|
||||
/// </summary>
|
||||
private readonly System.Threading.Lock _lock = new();
|
||||
#else
|
||||
/// <summary>
|
||||
/// net8.0 目标仍回退到 object 锁,以保持多目标编译兼容性。
|
||||
/// </summary>
|
||||
private readonly object _lock = new();
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 负责从完整状态中投影出局部状态的选择器。
|
||||
|
||||
@ -6,14 +6,15 @@
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-062`
|
||||
- 当前阶段:`Phase 62`
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-063`
|
||||
- 当前阶段:`Phase 63`
|
||||
- 当前焦点:
|
||||
- `2026-04-25` 本轮 `$gframework-batch-boot 75` 已达到主停止条件,当前代码 stop commit 为 `9ce1fa6`
|
||||
- `2026-04-25` 当前 turn 先执行 `$gframework-pr-review`,核对 PR #288 的 latest-head AI review 与本地真实状态
|
||||
- 已修复 `GFramework.Core.Tests/Extensions/AsyncExtensionsTests.cs` 的 `ConfiguredTaskAwaitable -> Task` 编译错误,并顺手收敛一批同类测试/样式残留
|
||||
- 基线 `origin/main` 仍为 `9964962`(`2026-04-24T23:05:53+08:00`)
|
||||
- 当前累计 branch diff 相对 `origin/main` 为 `75` 个文件、`2098` 行,已触达本轮 `75 files` 阈值
|
||||
- `RP-061` 之后已接受 2 个批次提交:`03c73a8`、`9ce1fa6`
|
||||
- 当前默认恢复入口不再继续扩写集;若要继续 analyzer reduction,优先先处理 `GFramework.Core.Tests` 的 net10 build 环境阻塞
|
||||
- 当前默认恢复入口不再继续扩写集;若要继续 analyzer reduction,优先先处理 WSL 下 NuGet fallback package folder 指向失效 Windows 路径的构建环境阻塞
|
||||
|
||||
## 当前活跃事实
|
||||
|
||||
@ -27,6 +28,22 @@
|
||||
- `AsyncExtensionsTests.cs`
|
||||
- `LogContextTests.cs`
|
||||
- `PauseStackManagerTests.cs`
|
||||
- 本 turn 结合 PR #288 latest-head review 额外收敛了以下仍然成立的问题:
|
||||
- `AsyncExtensionsTests.cs`:修复 `WithTimeoutAsync` 无返回值测试中错误返回 `ConfiguredTaskAwaitable` 导致的 `CS0029` / `CS1662`
|
||||
- `AsyncKeyLockManagerTests.cs`:去掉两处不会产生额外价值的 `Assert.DoesNotThrowAsync(() => Task.WhenAll(...))` 包装,并把取消断言改为直接消费 `ValueTask.AsTask()`
|
||||
- `AsyncArchitectureTests.cs`
|
||||
- `ArchitectureLifecycleBehaviorTests.cs`
|
||||
- `StateMachineSystemTests.cs`
|
||||
- `RegistryInitializationHookBaseTests.cs`
|
||||
- `NumericExtensions.cs`
|
||||
- `StringExtensions.cs`
|
||||
- `StoreBuilder.cs`
|
||||
- `StoreSelection.cs`
|
||||
- 当前 PR review 观察:
|
||||
- PR:`#288`
|
||||
- latest reviewed commit:`be336b2088b7c283a140add76d5cff30618ad16d`
|
||||
- `coderabbitai[bot]` 仍有 `7` 个 open threads,`greptile-apps[bot]` 仍有 `2` 个 open threads
|
||||
- 本 turn 已优先修复 latest-head 中明确指向 `AsyncExtensionsTests.cs:126` 的 critical 编译错误
|
||||
- 本轮 `Core` runtime 低风险机械型清理已落地到:
|
||||
- `AsyncExtensions.cs`
|
||||
- `CollectionExtensions.cs`
|
||||
@ -47,8 +64,9 @@
|
||||
|
||||
## 当前风险
|
||||
|
||||
- 当前环境下 `GFramework.Core.Tests` 的默认 net10 build 会在 SDK resolver 阶段命中 `MSB4276`。
|
||||
- 缓解措施:继续该 topic 前,优先修复或绕过 `Microsoft.NET.SDK.WorkloadAutoImportPropsLocator` 缺件;不要把该环境失败误判成当前 22 文件批次的代码回归。
|
||||
- 当前环境下 `GFramework.Core` / `GFramework.Core.Tests` 的 Release build 会命中 `MSB4018`。
|
||||
- 直接原因:`ResolvePackageAssets` 仍从历史 restore 生成的 `obj/*.csproj.nuget.g.props` 读取失效的 Windows fallback package folder `D:\Tool\Development Tools\Microsoft Visual Studio\Shared\NuGetPackages`。
|
||||
- 缓解措施:下次恢复时先重建 WSL 原生 restore 元数据,或显式清理并重做 `obj` 下的 NuGet restore 工件,再重新建立可信 build 基线。
|
||||
- `dotnet clean GFramework.sln -c Release` 与 `dotnet clean GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release` 仍无法稳定提供新的 clean 基线。
|
||||
- 缓解措施:后续若继续整仓 warning reduction,需要单独定位 clean 失败原因,或明确继续沿用 direct build 观测值作为临时真值。
|
||||
- 当前 worktree 仍存在未跟踪的 `.codex` 目录。
|
||||
@ -71,9 +89,17 @@
|
||||
## 验证说明
|
||||
|
||||
- `dotnet build GFramework.Core/GFramework.Core.csproj -c Release --no-restore -p:TargetFramework=net8.0 -p:RestoreFallbackFolders="" -v minimal`
|
||||
- 结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- 历史结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-incremental --no-restore -p:RestoreFallbackFolders= -v:diag`
|
||||
- 结果:失败;`MSB4276`,默认 SDK resolver 无法解析 `Microsoft.NET.SDK.WorkloadAutoImportPropsLocator`,属于当前 WSL / dotnet 10 环境阻塞
|
||||
- 历史结果:失败;`MSB4276`,默认 SDK resolver 无法解析 `Microsoft.NET.SDK.WorkloadAutoImportPropsLocator`,属于当前 WSL / dotnet 10 环境阻塞
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home MSBuildEnableWorkloadResolver=false dotnet build GFramework.Core/GFramework.Core.csproj -c Release --no-restore -p:TargetFramework=net8.0 -p:RestoreFallbackFolders="" -v minimal`
|
||||
- 结果:失败;`MSB4018`,`ResolvePackageAssets` 命中失效 Windows fallback package folder `D:\Tool\Development Tools\Microsoft Visual Studio\Shared\NuGetPackages`
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home MSBuildEnableWorkloadResolver=false dotnet build GFramework.Core/GFramework.Core.csproj -c Release --no-restore -p:TargetFramework=net9.0 -p:RestoreFallbackFolders="" -v minimal`
|
||||
- 结果:失败;`MSB4018`,原因同上
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home MSBuildEnableWorkloadResolver=false dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-restore -p:TargetFramework=net10.0 -p:RestoreFallbackFolders="" -v minimal`
|
||||
- 结果:失败;`MSB4018`,原因同上
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --json-output /tmp/current-pr-review.json`
|
||||
- 结果:成功;定位到 PR `#288`,提取 latest-head unresolved AI review threads、MegaLinter 与 Docstring Coverage 信号
|
||||
- `dotnet restore GFramework.Core.Tests/GFramework.Core.Tests.csproj -p:TestTargetFrameworks=net8.0 -p:RestoreFallbackFolders="" -v minimal`
|
||||
- 结果:失败;`NU1201`,`GFramework.Tests.Common` 仅支持 `net10.0`,因此不能用 `net8.0` 旁路验证 `Core.Tests`
|
||||
- `git diff --name-only origin/main...HEAD | wc -l`
|
||||
@ -83,6 +109,6 @@
|
||||
|
||||
## 下一步建议
|
||||
|
||||
1. 当前 `$gframework-batch-boot 75` 已达到阈值;默认在 `9ce1fa6` 停止,不再继续扩写集。
|
||||
2. 若后续要继续 `Core` / `Core.Tests` warning reduction,先解决 `GFramework.Core.Tests` 的 `MSB4276` 环境阻塞,再重新建立可信 warning 基线。
|
||||
1. 当前 turn 已先修复 latest-head PR review 中最紧急的编译错误;后续若继续 PR #288 收尾,优先重新抓取 unresolved threads,确认剩余 8 个 open threads 哪些仍成立。
|
||||
2. 若后续要继续 `Core` / `Core.Tests` warning reduction,先修复 WSL 下 stale NuGet restore metadata 导致的 `MSB4018`,再重新建立可信 build 基线。
|
||||
3. 若要开启下一轮批处理,优先选择新的 stop-condition(例如新的 file 阈值、warning 目标或限定到单模块)后再继续。
|
||||
|
||||
@ -1,5 +1,35 @@
|
||||
# Analyzer Warning Reduction 追踪
|
||||
|
||||
## 2026-04-25 — RP-063
|
||||
|
||||
### 阶段:先收口 PR #288 latest-head 编译错误,再暂停在环境阻塞点并准备提交
|
||||
|
||||
- 触发背景:
|
||||
- 用户显式要求先执行 `$gframework-pr-review`,并指出 `AsyncExtensionsTests.cs(126,23)` 当前存在 `CS0029` / `CS1662` 构建错误
|
||||
- 当前 worktree 仍是 `fix/analyzer-warning-reduction-batch`,因此本 turn 继续沿用 `analyzer-warning-reduction` 的 active recovery 文档
|
||||
- 主线程实施:
|
||||
- 运行 PR review 抓取脚本,确认当前分支对应 PR `#288`
|
||||
- 核对 latest-head unresolved review threads 后,优先修复 `AsyncExtensionsTests.cs` 中 `ct => Task.Delay(...).ConfigureAwait(false)` 错误返回 `ConfiguredTaskAwaitable` 的问题
|
||||
- 顺手收敛多处已被 latest review 点名且本地仍成立的低风险残留:
|
||||
- 测试中的 `async` 无 `await`
|
||||
- `ValueTask` 断言包装
|
||||
- `RegistryInitializationHookBaseTests.cs` 的可空返回签名
|
||||
- `NumericExtensions.cs`、`StringExtensions.cs`、`StoreBuilder.cs` 的 Allman 花括号残留
|
||||
- `StoreSelection.cs` 在 `net9.0+` 下切到 `System.Threading.Lock`,同时保留 `net8.0` 兼容分支
|
||||
- 验证里程碑:
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --json-output /tmp/current-pr-review.json`
|
||||
- 结果:成功;确认 PR `#288` 的 latest-head unresolved AI review threads 共 `9` 个,其中 `AsyncExtensionsTests.cs:126` 为 critical 编译错误
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home MSBuildEnableWorkloadResolver=false dotnet build GFramework.Core/GFramework.Core.csproj -c Release --no-restore -p:TargetFramework=net8.0 -p:RestoreFallbackFolders="" -v minimal`
|
||||
- 结果:失败;`MSB4018`,`ResolvePackageAssets` 仍读取失效 Windows fallback package folder `D:\Tool\Development Tools\Microsoft Visual Studio\Shared\NuGetPackages`
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home MSBuildEnableWorkloadResolver=false dotnet build GFramework.Core/GFramework.Core.csproj -c Release --no-restore -p:TargetFramework=net9.0 -p:RestoreFallbackFolders="" -v minimal`
|
||||
- 结果:失败;原因同上
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home MSBuildEnableWorkloadResolver=false dotnet build GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --no-restore -p:TargetFramework=net10.0 -p:RestoreFallbackFolders="" -v minimal`
|
||||
- 结果:失败;原因同上
|
||||
- 当前结论:
|
||||
- 用户点名的 `AsyncExtensionsTests.cs` 编译错误已在源码层修复
|
||||
- 本 turn 未能拿到新的可通过 Release build,阻塞点已从先前记录的 `MSB4276` 收敛为当前 `obj/*.csproj.nuget.g.props` 中 stale Windows fallback package folder 导致的 `MSB4018`
|
||||
- 用户随后要求“先不管这个了,先提交吧”,因此本 turn 在记录环境阻塞后先执行提交收口
|
||||
|
||||
## 2026-04-25 — RP-062
|
||||
|
||||
### 阶段:触达 `$gframework-batch-boot 75` 停止阈值并收口到 `75 files / 2098 lines`
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user