diff --git a/GFramework.Cqrs.Tests/Mediator/MediatorAdvancedFeaturesTests.cs b/GFramework.Cqrs.Tests/Mediator/MediatorAdvancedFeaturesTests.cs index 344a0203..d8e9de59 100644 --- a/GFramework.Cqrs.Tests/Mediator/MediatorAdvancedFeaturesTests.cs +++ b/GFramework.Cqrs.Tests/Mediator/MediatorAdvancedFeaturesTests.cs @@ -236,6 +236,7 @@ public class MediatorAdvancedFeaturesTests } } +// 这些高级特性测试需要把一组仅供当前文件使用的辅助类型共置,避免拆成多个噪声文件。 #pragma warning disable MA0048 #region Advanced Test Classes diff --git a/GFramework.Cqrs.Tests/Mediator/MediatorArchitectureIntegrationTests.cs b/GFramework.Cqrs.Tests/Mediator/MediatorArchitectureIntegrationTests.cs index b1ac1d24..c0d1f260 100644 --- a/GFramework.Cqrs.Tests/Mediator/MediatorArchitectureIntegrationTests.cs +++ b/GFramework.Cqrs.Tests/Mediator/MediatorArchitectureIntegrationTests.cs @@ -1,3 +1,4 @@ +using System.Collections.Concurrent; using GFramework.Core.Abstractions.Architectures; using GFramework.Core.Abstractions.Logging; using GFramework.Core.Architectures; @@ -331,13 +332,7 @@ public class MediatorArchitectureIntegrationTests public ValueTask Handle(TestNestedRequest request, CancellationToken cancellationToken) { TestNestedRequestHandler2.ExecutionCount++; - - if (request.Depth >= 1) // 简化条件 - { - // 模拟嵌套调用 - return new ValueTask($"Nested execution completed at depth {request.Depth}"); - } - + // 模拟嵌套调用 return new ValueTask($"Nested execution completed at depth {request.Depth}"); } } @@ -391,30 +386,28 @@ public class MediatorArchitectureIntegrationTests public sealed class TestUncachedRequestHandler : IRequestHandler { - public ValueTask Handle(TestUncachedRequest request, CancellationToken cancellationToken) + public async ValueTask Handle(TestUncachedRequest request, CancellationToken cancellationToken) { // 模拟一些处理时间 - Task.Delay(5, cancellationToken).Wait(cancellationToken); - return new ValueTask(request.Id); + await Task.Delay(5, cancellationToken).ConfigureAwait(false); + return request.Id; } } public sealed class TestCachedRequestHandler : IRequestHandler { - private static readonly Dictionary _cache = new(); + private static readonly ConcurrentDictionary _cache = new(); - public ValueTask Handle(TestCachedRequest request, CancellationToken cancellationToken) + public async ValueTask Handle(TestCachedRequest request, CancellationToken cancellationToken) { if (_cache.TryGetValue(request.Id, out var cachedValue)) { - return new ValueTask(cachedValue); + return cachedValue; } // 模拟处理时间 - Task.Delay(10, cancellationToken).Wait(cancellationToken); - var newValue = request.Id; - _cache[request.Id] = newValue; - return new ValueTask(newValue); + await Task.Delay(10, cancellationToken).ConfigureAwait(false); + return _cache.GetOrAdd(request.Id, static id => id); } } @@ -435,7 +428,7 @@ public class MediatorArchitectureIntegrationTests { public ValueTask Handle(TestStateModificationRequest request, CancellationToken cancellationToken) { - request.SharedState.Counter += request.Increment; + request.SharedState.IncrementBy(request.Increment); return new ValueTask("State modified"); } } @@ -567,7 +560,14 @@ public class MediatorArchitectureIntegrationTests // 并发测试相关类 public class SharedState { - public int Counter { get; set; } + private int _counter; + + public int Counter => _counter; + + public void IncrementBy(int increment) + { + Interlocked.Add(ref _counter, increment); + } } public sealed record TestConcurrentRequest : IRequest diff --git a/GFramework.Game.Tests/Config/YamlConfigModelContractTests.cs b/GFramework.Game.Tests/Config/YamlConfigModelContractTests.cs new file mode 100644 index 00000000..9839b853 --- /dev/null +++ b/GFramework.Game.Tests/Config/YamlConfigModelContractTests.cs @@ -0,0 +1,125 @@ +using System.Text.RegularExpressions; +using GFramework.Game.Config; + +namespace GFramework.Game.Tests.Config; + +/// +/// 验证内部 schema 运行时模型会在构造阶段拒绝无效状态, +/// 避免调用方把不一致的约束对象继续传入加载器和校验器。 +/// +[TestFixture] +public sealed class YamlConfigModelContractTests +{ + /// + /// 验证枚举允许值模型会拒绝空白比较键。 + /// + [Test] + public void AllowedValue_Should_Reject_Whitespace_Comparable_Value() + { + Assert.Throws(() => new YamlConfigAllowedValue(" ", "visible")); + } + + /// + /// 验证常量约束模型会拒绝空白比较键。 + /// + [Test] + public void ConstantValue_Should_Reject_Whitespace_Comparable_Value() + { + Assert.Throws(() => new YamlConfigConstantValue(" ", "\"visible\"")); + } + + /// + /// 验证 contains 约束模型会在构造阶段拦截负值和反向区间。 + /// + [Test] + public void ArrayContainsConstraints_Should_Reject_Invalid_Bounds() + { + var itemNode = CreateStringNode(); + + Assert.Multiple(() => + { + Assert.Throws(() => new YamlConfigArrayContainsConstraints(itemNode, -1, null)); + Assert.Throws(() => new YamlConfigArrayContainsConstraints(itemNode, null, -1)); + Assert.Throws(() => new YamlConfigArrayContainsConstraints(itemNode, 3, 2)); + }); + } + + /// + /// 验证数组约束模型会在构造阶段拦截负值和反向区间。 + /// + [Test] + public void ArrayConstraints_Should_Reject_Invalid_Bounds() + { + Assert.Multiple(() => + { + Assert.Throws(() => new YamlConfigArrayConstraints(-1, null, false, null)); + Assert.Throws(() => new YamlConfigArrayConstraints(null, -1, false, null)); + Assert.Throws(() => new YamlConfigArrayConstraints(4, 3, false, null)); + }); + } + + /// + /// 验证对象约束模型会在构造阶段拦截负值和反向区间。 + /// + [Test] + public void ObjectConstraints_Should_Reject_Invalid_Bounds() + { + Assert.Multiple(() => + { + Assert.Throws(() => + new YamlConfigObjectConstraints(-1, null, null, null, null, null)); + Assert.Throws(() => + new YamlConfigObjectConstraints(null, -1, null, null, null, null)); + Assert.Throws(() => + new YamlConfigObjectConstraints(5, 4, null, null, null, null)); + }); + } + + /// + /// 验证字符串约束模型要求正则原文与预编译正则成对出现。 + /// + [Test] + public void StringConstraints_Should_Require_Pattern_And_Regex_To_Be_Paired() + { + Assert.Multiple(() => + { + Assert.Throws(() => + new YamlConfigStringConstraints(null, null, "value", null, null)); + Assert.Throws(() => + new YamlConfigStringConstraints( + null, + null, + null, + new Regex("value", RegexOptions.None, TimeSpan.FromSeconds(1)), + null)); + }); + } + + /// + /// 验证 schema 模型会复制引用表集合,避免外部可变集合继续污染内部状态。 + /// + [Test] + public void Schema_Should_Copy_Referenced_Table_Names() + { + var referencedTableNames = new List { "item" }; + var schema = new YamlConfigSchema("monster.schema.json", CreateStringNode(), referencedTableNames); + + referencedTableNames.Add("weapon"); + + Assert.Multiple(() => + { + Assert.That(schema.ReferencedTableNames, Is.EqualTo(new[] { "item" })); + Assert.That(schema.ReferencedTableNames, Is.Not.SameAs(referencedTableNames)); + }); + } + + private static YamlConfigSchemaNode CreateStringNode() + { + return YamlConfigSchemaNode.CreateScalar( + YamlConfigSchemaPropertyType.String, + referenceTableName: null, + allowedValues: null, + constraints: null, + schemaPathHint: "tests.schema.json"); + } +} diff --git a/GFramework.Game/Config/YamlConfigAllowedValue.cs b/GFramework.Game/Config/YamlConfigAllowedValue.cs index 60077ef5..bbbfd99b 100644 --- a/GFramework.Game/Config/YamlConfigAllowedValue.cs +++ b/GFramework.Game/Config/YamlConfigAllowedValue.cs @@ -11,9 +11,11 @@ internal sealed class YamlConfigAllowedValue /// /// 用于与 YAML 节点比较的稳定键。 /// 用于诊断输出的原始 JSON 文本。 + /// 时抛出。 + /// 为空或仅包含空白字符时抛出。 public YamlConfigAllowedValue(string comparableValue, string displayValue) { - ArgumentNullException.ThrowIfNull(comparableValue); + ArgumentException.ThrowIfNullOrWhiteSpace(comparableValue); ArgumentException.ThrowIfNullOrWhiteSpace(displayValue); ComparableValue = comparableValue; diff --git a/GFramework.Game/Config/YamlConfigArrayConstraints.cs b/GFramework.Game/Config/YamlConfigArrayConstraints.cs index 64ddaf3c..b7a91128 100644 --- a/GFramework.Game/Config/YamlConfigArrayConstraints.cs +++ b/GFramework.Game/Config/YamlConfigArrayConstraints.cs @@ -13,12 +13,31 @@ internal sealed class YamlConfigArrayConstraints /// 最大元素数量约束。 /// 是否要求数组元素唯一。 /// 数组 contains 约束;未声明时为空。 + /// 为负数时抛出。 + /// 大于 时抛出。 public YamlConfigArrayConstraints( int? minItems, int? maxItems, bool uniqueItems, YamlConfigArrayContainsConstraints? containsConstraints) { + if (minItems is < 0) + { + throw new ArgumentOutOfRangeException(nameof(minItems), minItems, "minItems 不能为负数。"); + } + + if (maxItems is < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxItems), maxItems, "maxItems 不能为负数。"); + } + + if (minItems.HasValue && + maxItems.HasValue && + minItems.Value > maxItems.Value) + { + throw new ArgumentException("minItems 不能大于 maxItems。", nameof(minItems)); + } + MinItems = minItems; MaxItems = maxItems; UniqueItems = uniqueItems; diff --git a/GFramework.Game/Config/YamlConfigArrayContainsConstraints.cs b/GFramework.Game/Config/YamlConfigArrayContainsConstraints.cs index a61800f8..e954fcd8 100644 --- a/GFramework.Game/Config/YamlConfigArrayContainsConstraints.cs +++ b/GFramework.Game/Config/YamlConfigArrayContainsConstraints.cs @@ -12,12 +12,31 @@ internal sealed class YamlConfigArrayContainsConstraints /// contains 子 schema。 /// 最小匹配数量;为 时按 JSON Schema 语义默认 1。 /// 最大匹配数量。 + /// 时抛出。 + /// 为负数时抛出。 + /// 大于 时抛出。 public YamlConfigArrayContainsConstraints( YamlConfigSchemaNode containsNode, int? minContains, int? maxContains) { ArgumentNullException.ThrowIfNull(containsNode); + if (minContains is < 0) + { + throw new ArgumentOutOfRangeException(nameof(minContains), minContains, "minContains 不能为负数。"); + } + + if (maxContains is < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxContains), maxContains, "maxContains 不能为负数。"); + } + + if (minContains.HasValue && + maxContains.HasValue && + minContains.Value > maxContains.Value) + { + throw new ArgumentException("minContains 不能大于 maxContains。", nameof(minContains)); + } ContainsNode = containsNode; MinContains = minContains; diff --git a/GFramework.Game/Config/YamlConfigConditionalSchemas.cs b/GFramework.Game/Config/YamlConfigConditionalSchemas.cs index 7d4bbbf2..b71cdfc3 100644 --- a/GFramework.Game/Config/YamlConfigConditionalSchemas.cs +++ b/GFramework.Game/Config/YamlConfigConditionalSchemas.cs @@ -12,6 +12,7 @@ internal sealed class YamlConfigConditionalSchemas /// 条件判断 schema。 /// 条件命中时需要满足的 schema。 /// 条件未命中时需要满足的 schema。 + /// 时抛出。 public YamlConfigConditionalSchemas( YamlConfigSchemaNode ifSchema, YamlConfigSchemaNode? thenSchema, diff --git a/GFramework.Game/Config/YamlConfigConstantValue.cs b/GFramework.Game/Config/YamlConfigConstantValue.cs index 48caa4c5..b40a1e7a 100644 --- a/GFramework.Game/Config/YamlConfigConstantValue.cs +++ b/GFramework.Game/Config/YamlConfigConstantValue.cs @@ -11,9 +11,11 @@ internal sealed class YamlConfigConstantValue /// /// 用于与 YAML 节点比较的稳定键。 /// 用于诊断输出的原始常量文本。 + /// 时抛出。 + /// 为空或仅包含空白字符时抛出。 public YamlConfigConstantValue(string comparableValue, string displayValue) { - ArgumentNullException.ThrowIfNull(comparableValue); + ArgumentException.ThrowIfNullOrWhiteSpace(comparableValue); ArgumentException.ThrowIfNullOrWhiteSpace(displayValue); ComparableValue = comparableValue; diff --git a/GFramework.Game/Config/YamlConfigObjectConstraints.cs b/GFramework.Game/Config/YamlConfigObjectConstraints.cs index 01b460f9..ae148d6c 100644 --- a/GFramework.Game/Config/YamlConfigObjectConstraints.cs +++ b/GFramework.Game/Config/YamlConfigObjectConstraints.cs @@ -15,6 +15,8 @@ internal sealed class YamlConfigObjectConstraints /// 对象内条件 schema 约束。 /// 对象内组合 schema 约束。 /// 对象内条件分支约束。 + /// 为负数时抛出。 + /// 大于 时抛出。 public YamlConfigObjectConstraints( int? minProperties, int? maxProperties, @@ -23,6 +25,23 @@ internal sealed class YamlConfigObjectConstraints IReadOnlyList? allOfSchemas, YamlConfigConditionalSchemas? conditionalSchemas) { + if (minProperties is < 0) + { + throw new ArgumentOutOfRangeException(nameof(minProperties), minProperties, "minProperties 不能为负数。"); + } + + if (maxProperties is < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxProperties), maxProperties, "maxProperties 不能为负数。"); + } + + if (minProperties.HasValue && + maxProperties.HasValue && + minProperties.Value > maxProperties.Value) + { + throw new ArgumentException("minProperties 不能大于 maxProperties。", nameof(minProperties)); + } + MinProperties = minProperties; MaxProperties = maxProperties; DependentRequired = dependentRequired; diff --git a/GFramework.Game/Config/YamlConfigSchema.cs b/GFramework.Game/Config/YamlConfigSchema.cs index e3ae2f0c..a0ebc969 100644 --- a/GFramework.Game/Config/YamlConfigSchema.cs +++ b/GFramework.Game/Config/YamlConfigSchema.cs @@ -12,6 +12,7 @@ internal sealed class YamlConfigSchema /// Schema 文件路径。 /// 根节点模型。 /// Schema 声明的目标引用表名称集合。 + /// 时抛出。 public YamlConfigSchema( string schemaPath, YamlConfigSchemaNode rootNode, @@ -23,7 +24,7 @@ internal sealed class YamlConfigSchema SchemaPath = schemaPath; RootNode = rootNode; - ReferencedTableNames = referencedTableNames; + ReferencedTableNames = [.. referencedTableNames]; } /// diff --git a/GFramework.Game/Config/YamlConfigSchemaNode.cs b/GFramework.Game/Config/YamlConfigSchemaNode.cs index 35509bef..aeeb3ab2 100644 --- a/GFramework.Game/Config/YamlConfigSchemaNode.cs +++ b/GFramework.Game/Config/YamlConfigSchemaNode.cs @@ -280,15 +280,6 @@ internal sealed class YamlConfigSchemaNode NegatedSchemaNode = negatedSchemaNode; } - public static NodeValidation None { get; } = new( - referenceTableName: null, - allowedValues: null, - constraints: null, - arrayConstraints: null, - objectConstraints: null, - constantValue: null, - negatedSchemaNode: null); - public string? ReferenceTableName { get; } public IReadOnlyCollection? AllowedValues { get; } diff --git a/GFramework.Game/Config/YamlConfigStringConstraints.cs b/GFramework.Game/Config/YamlConfigStringConstraints.cs index efb75840..013e52e1 100644 --- a/GFramework.Game/Config/YamlConfigStringConstraints.cs +++ b/GFramework.Game/Config/YamlConfigStringConstraints.cs @@ -17,6 +17,7 @@ internal sealed class YamlConfigStringConstraints /// 正则模式约束原文。 /// 已编译的正则表达式。 /// 字符串 format 约束。 + /// 未成对出现时抛出。 public YamlConfigStringConstraints( int? minLength, int? maxLength, @@ -24,6 +25,11 @@ internal sealed class YamlConfigStringConstraints Regex? patternRegex, YamlConfigStringFormatConstraint? formatConstraint) { + if ((pattern is null) != (patternRegex is null)) + { + throw new ArgumentException("pattern 与 patternRegex 必须同时为空或同时提供。", nameof(pattern)); + } + MinLength = minLength; MaxLength = maxLength; Pattern = pattern; diff --git a/GFramework.Game/Config/YamlConfigStringFormatConstraint.cs b/GFramework.Game/Config/YamlConfigStringFormatConstraint.cs index 97c3a262..6127a784 100644 --- a/GFramework.Game/Config/YamlConfigStringFormatConstraint.cs +++ b/GFramework.Game/Config/YamlConfigStringFormatConstraint.cs @@ -11,6 +11,8 @@ internal sealed class YamlConfigStringFormatConstraint /// /// schema 中声明的 format 名称。 /// 归一化后的共享 format 枚举。 + /// 时抛出。 + /// 为空或仅包含空白字符时抛出。 public YamlConfigStringFormatConstraint( string schemaName, YamlConfigStringFormatKind kind) 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 315d0e0c..66d65d6e 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,43 +6,40 @@ ## 当前恢复点 -- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-094` -- 当前阶段:`Phase 94` +- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-095` +- 当前阶段:`Phase 95` - 当前焦点: - - `2026-04-29` 继续按 `$gframework-batch-boot 50` 从仓库根 `dotnet clean` + `dotnet build` 的权威 warning 基线收尾 `YamlConfigSchemaValidator` - - 本轮 clean build 只剩 `15` 条 warning,但实际只对应 `YamlConfigSchemaValidator.cs` 同一文件中的 `5` 个独立 `MA0051` 热点,因此不再并发派发 worker,避免同文件冲突 - - 已将 `ParseNode`、`ValidateObjectNode`、`ValidateObjectConstraints`、`ValidateScalarNode`、`ValidateNumericScalarConstraints` 按语义拆成 helper,并补齐对象条件分支 helper - - 当前仓库根 clean build 已收敛到 `0` warnings、`0` errors;本轮停止原因从“接近文件阈值”切换为“当前 warning hotspot 已耗尽” + - `2026-04-29` 继续处理 `PR #301` 的 latest-head review threads,只修复当前工作树上仍然成立的问题 + - 已修复 `MediatorArchitectureIntegrationTests` 中仍然成立的并发与阻塞问题:移除冗余分支、把 `Task.Delay().Wait()` 改为 `await`、把静态缓存换成 `ConcurrentDictionary`、并把共享计数更新改成原子操作 + - 已补 `GFramework.Game/Config` 运行时 schema 模型的构造期契约校验与 `` XML 文档,并新增 `YamlConfigModelContractTests` 锁定这些无效状态保护 + - 本轮明确暂不接受两个误报方向:`YamlConfigReferenceUsage.DisplayPath` 别名删除建议,以及两个本地枚举补 `[GenerateEnumExtensions]` 的泛化建议 ## 当前活跃事实 - 当前 `origin/main` 基线提交为 `0e32dab`(`2026-04-28T17:15:47+08:00`)。 - 当前直接验证结果: - - `dotnet clean` - - 最新结果:成功;标准仓库根 clean 本轮可直接运行,未再命中需要额外绕开的环境噪音 - - `dotnet build` - - 最新结果:成功;`0 Warning(s)`、`0 Error(s)`;本轮开始时同一口径 clean build 的 `15` 条 warning 已全部清零 - `dotnet build GFramework.Game/GFramework.Game.csproj -c Release -clp:Summary` - 最新结果:成功;`0 Warning(s)`、`0 Error(s)` - - `dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "FullyQualifiedName~YamlConfigLoaderTests|FullyQualifiedName~YamlConfigSchemaValidatorTests"` - - 最新结果:成功;`80` 通过、`0` 失败 + - `dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "FullyQualifiedName~YamlConfigSchemaValidatorTests|FullyQualifiedName~YamlConfigModelContractTests"` + - 最新结果:成功;`10` 通过、`0` 失败 + - `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~MediatorArchitectureIntegrationTests|FullyQualifiedName~MediatorAdvancedFeaturesTests"` + - 最新结果:成功;`25` 通过、`0` 失败 - `git diff --check` - 最新结果:成功;无新增 whitespace / conflict-marker 问题 - 当前批次摘要: - - 当前分支提交后预计相对 `origin/main...HEAD` 包含 `22` 个变更文件,低于 `50` 个文件阈值 - - 已完成 worker 切片: - - `ed269d4`:`MediatorArchitectureIntegrationTests.cs`,清理 `MA0048` / `MA0004` / `MA0016` - - `121df44`:`MediatorAdvancedFeaturesTests.cs`,清理 `MA0048` / `MA0004` / `MA0015` - - `9109eec`:`MediatorComprehensiveTests.cs`,清理 `MA0048` / `MA0004` / `MA0016` / `MA0002` / `MA0015` - - 主线程切片:`YamlConfigSchemaValidator.cs` 方法拆分,清理剩余 `MA0051`,并修正新增 helper 里的 `MA0006` - - Game 追加切片: - - `1395b84`:`YamlConfigSchemaValidator.ObjectKeywords.cs`,清理该文件 `MA0051` - - 已完成:将 `YamlConfigSchemaValidator.cs` 末尾 schema model 类型拆到独立同名文件,清理 `MA0048` + - 当前切片直接修改 `12` 个已有文件,并新增 `YamlConfigModelContractTests.cs` 作为模型契约回归覆盖 + - 本轮修复集中在 `GFramework.Cqrs.Tests` 与 `GFramework.Game` 两个最新 review thread 热区,没有再扩写回 warning-batch 的多文件并发清理范围 + - PR review triage 结论: + - 接受:并发共享状态、阻塞等待、无效约束状态、缺失 `` 文档 + - 延后:`DisplayPath` 诊断别名删除建议 + - 驳回:两个枚举补 `[GenerateEnumExtensions]` 的泛化建议 ## 当前风险 -- 当前仓库根 clean build warning 已清零,本主题暂时没有剩余源码 warning 风险。 - - 缓解措施:若后续继续 batch warning 清理,先重新执行同轮 `dotnet clean` + `dotnet build` 采样,再决定是否需要分派 subagent。 +- 当前 GitHub PR 仍会保留尚未推送折叠的 open threads,以及被明确延后 / 驳回的机器人建议。 + - 缓解措施:提交并推送后重新执行 `$gframework-pr-review`,只保留仍有真实依据的剩余线程。 +- 本轮未重跑仓库根 `dotnet clean` + `dotnet build`,因此 RP-094 的仓库级 warning 真值不能直接外推到这次 PR-review follow-up 之后。 + - 缓解措施:若下一轮重新回到 analyzer warning reduction 主线,先按仓库规则重新采样仓库根 clean build。 ## 活跃文档 @@ -63,13 +60,13 @@ ## 验证说明 - 权威验证结果统一维护在“当前活跃事实”。 -- `GFramework.Game` 当前 Release 构建已清零,并通过 config 定向测试;本轮标准仓库根 Debug clean build 也已清零。 -- 本轮标准仓库根 `dotnet clean` + `dotnet build` 已直接回到 `0 Warning(s)`、`0 Error(s)`,因此 warning reduction 真值已从模块级验证收口到仓库级 clean build。 +- `GFramework.Game` 当前 Release 构建已清零,并通过 config 定向测试。 +- `GFramework.Cqrs.Tests` 当前 PR-review follow-up 定向测试通过,说明并发/缓存测试辅助实现的行为修正没有破坏现有集成断言。 - `git diff --check` 结果为空,说明本轮新增改动没有引入新的尾随空格或冲突标记。 -- warning reduction 的仓库级真值以同轮 `dotnet build`、定向 `dotnet test` 与 `git diff --check` 为准,并与 trace 中的验证里程碑保持一致。 +- 本轮以受影响项目的 Release build / tests 为完成条件;若下轮恢复 warning reduction 仓库级真值,需要重新执行仓库根 `dotnet clean` + `dotnet build`。 ## 下一步建议 -1. 提交 `YamlConfigSchemaValidator` 收尾重构与本轮 `ai-plan` 同步。 -2. 如需继续 warning reduction,先从新的仓库根 clean build 重新采样是否还有新增 warning hotspot。 -3. 若未来 warning 再次分散到多个文件,再按 `$gframework-batch-boot 50` 规则切换回多 worker 并行模式。 +1. 提交当前 PR-review follow-up 与本轮 `ai-plan` 同步。 +2. 推送分支后重新执行 `$gframework-pr-review`,确认剩余 open threads 是否只剩延后 / 误报项。 +3. 若下一轮恢复 warning reduction 主线,先重新执行仓库根 `dotnet clean` + `dotnet build` 建立新的权威基线。 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 8df8306c..26dab494 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,38 @@ # Analyzer Warning Reduction 追踪 +## 2026-04-29 — RP-095 + +### 阶段:复核 `PR #301` latest-head review threads,并只修复当前工作树上仍然成立的问题 + +- 触发背景: + - 用户显式要求执行 `$gframework-pr-review`,需要把 GitHub PR review 信号与本地代码现状重新核对,而不是沿用旧的 warning-batch 假设 +- 本轮 triage 结论: + - 接受并修复: + - `MediatorArchitectureIntegrationTests` 中 `Task.Delay().Wait()` 阻塞、静态 `Dictionary` 竞态、`SharedState.Counter +=` 非原子更新、以及 `TestNestedRequestHandler` 冗余分支 + - `GFramework.Game/Config` 中仍然成立的模型契约缺口:空白比较键、数组 / 对象边界非法状态、`Pattern` / `PatternRegex` 不一致、`ReferencedTableNames` 未做 defensive copy、以及缺失的 `` XML 文档 + - `MediatorAdvancedFeaturesTests` 中 `MA0048` 抑制缺少原因注释 + - `YamlConfigSchemaNode.NodeValidation.None` 未被引用,按 review 建议删除死代码 + - 明确不接受或延后: + - `YamlConfigReferenceUsage.DisplayPath`:当前在 loader 诊断与测试断言中承担独立语义标签,不作为“纯冗余 alias”删除 + - `YamlConfigSchemaPropertyType` / `YamlConfigStringFormatKind` 补 `[GenerateEnumExtensions]`:仓库产品代码没有现成约定或使用面,判断为泛化误报 +- 主线程实施: + - 将 CQRS 集成测试辅助处理器改为真正异步,并用 `ConcurrentDictionary` / `Interlocked` 收口并发共享状态 + - 为 `YamlConfigAllowedValue`、`YamlConfigConstantValue`、`YamlConfigArrayContainsConstraints`、`YamlConfigArrayConstraints`、`YamlConfigObjectConstraints`、`YamlConfigStringConstraints`、`YamlConfigSchema`、`YamlConfigConditionalSchemas`、`YamlConfigStringFormatConstraint` 补运行时契约或 `` 注释 + - 新增 `YamlConfigModelContractTests`,锁定上述模型拒绝无效状态的行为 +- 验证里程碑: + - `dotnet build GFramework.Game/GFramework.Game.csproj -c Release` + - 结果:成功;`0 Warning(s)`、`0 Error(s)` + - `dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "FullyQualifiedName~YamlConfigSchemaValidatorTests|FullyQualifiedName~YamlConfigModelContractTests"` + - 第一次结果:成功;`10` 通过、`0` 失败,但新增测试触发 `MA0009` + - 第二次结果:成功;`10` 通过、`0` 失败;为测试中的 `Regex` 补 timeout 后 warning 清零 + - `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~MediatorArchitectureIntegrationTests|FullyQualifiedName~MediatorAdvancedFeaturesTests"` + - 结果:成功;`25` 通过、`0` 失败 + - `git diff --check` + - 结果:成功;无新增 whitespace / conflict-marker 问题 +- 下一步: + - 提交当前 PR-review follow-up 与 `ai-plan` 同步 + - 推送后重新执行 `$gframework-pr-review`,确认 remaining open threads 是否已缩减到延后 / 误报项 + ## 2026-04-29 — RP-094 ### 阶段:收尾 `YamlConfigSchemaValidator` 剩余 `MA0051` 并将仓库根 clean build 归零