mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
test(game-tests): 收敛热重载长方法 warning
- 重构 YamlConfigLoaderTests 的热重载夹具与回调接线,消化 4 个 MA0051 长方法警告 - 更新 analyzer-warning-reduction active todo 与 trace,记录 652 条根构建 warning 的新基线 - 保持 GFramework.Game.Tests 的 Release build 为 0 Warning 和 0 Error
This commit is contained in:
parent
6a704f3aa7
commit
be26640b58
@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using GFramework.Core.Abstractions.Events;
|
||||
using GFramework.Game.Abstractions.Config;
|
||||
using GFramework.Game.Config;
|
||||
|
||||
@ -2789,83 +2790,15 @@ public class YamlConfigLoaderTests
|
||||
[Test]
|
||||
public async Task EnableHotReload_Should_Keep_Previous_State_When_Contains_Reference_Dependency_Breaks()
|
||||
{
|
||||
CreateConfigFile(
|
||||
"item/potion.yaml",
|
||||
"""
|
||||
id: potion
|
||||
name: Potion
|
||||
""");
|
||||
CreateConfigFile(
|
||||
"monster/slime.yaml",
|
||||
"""
|
||||
id: 1
|
||||
name: Slime
|
||||
dropItemIds:
|
||||
- potion
|
||||
""");
|
||||
CreateSchemaFile(
|
||||
"schemas/item.schema.json",
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"name": { "type": "string" }
|
||||
}
|
||||
}
|
||||
""");
|
||||
CreateSchemaFile(
|
||||
"schemas/monster.schema.json",
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name", "dropItemIds"],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
"name": { "type": "string" },
|
||||
"dropItemIds": {
|
||||
"type": "array",
|
||||
"minContains": 1,
|
||||
"contains": {
|
||||
"type": "string",
|
||||
"x-gframework-ref-table": "item"
|
||||
},
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
var loader = new YamlConfigLoader(_rootPath)
|
||||
.RegisterTable<string, ItemConfigStub>("item", "item", "schemas/item.schema.json",
|
||||
static config => config.Id)
|
||||
.RegisterTable<int, MonsterDropArrayConfigStub>("monster", "monster", "schemas/monster.schema.json",
|
||||
static config => config.Id);
|
||||
var registry = new ConfigRegistry();
|
||||
await loader.LoadAsync(registry);
|
||||
|
||||
var reloadFailureTaskSource =
|
||||
new TaskCompletionSource<(string TableName, Exception Exception)>(TaskCreationOptions
|
||||
.RunContinuationsAsynchronously);
|
||||
var hotReload = loader.EnableHotReload(
|
||||
registry,
|
||||
onTableReloadFailed: (tableName, exception) =>
|
||||
reloadFailureTaskSource.TrySetResult((tableName, exception)),
|
||||
debounceDelay: TimeSpan.FromMilliseconds(150));
|
||||
var (loader, registry) = await CreateLoadedContainsReferenceHotReloadScenarioAsync().ConfigureAwait(false);
|
||||
var (reloadFailureTaskSource, hotReload) = EnableHotReloadWithFailureCapture(loader, registry);
|
||||
|
||||
try
|
||||
{
|
||||
CreateConfigFile(
|
||||
"item/potion.yaml",
|
||||
"""
|
||||
id: elixir
|
||||
name: Elixir
|
||||
""");
|
||||
CreateConfigFile("item/potion.yaml", UpdatedItemConfigContent);
|
||||
|
||||
var failure = await WaitForTaskWithinAsync(reloadFailureTaskSource.Task, TimeSpan.FromSeconds(5));
|
||||
var failure = await WaitForTaskWithinAsync(reloadFailureTaskSource.Task, TimeSpan.FromSeconds(5))
|
||||
.ConfigureAwait(false);
|
||||
var diagnosticException = failure.Exception as ConfigLoadException;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
@ -2958,65 +2891,17 @@ public class YamlConfigLoaderTests
|
||||
[Test]
|
||||
public async Task EnableHotReload_Should_Support_Options_Object()
|
||||
{
|
||||
CreateConfigFile(
|
||||
"monster/slime.yaml",
|
||||
"""
|
||||
id: 1
|
||||
name: Slime
|
||||
hp: 10
|
||||
""");
|
||||
CreateSchemaFile(
|
||||
"schemas/monster.schema.json",
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
"name": { "type": "string" },
|
||||
"hp": { "type": "integer" }
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
var loader = new YamlConfigLoader(_rootPath)
|
||||
.RegisterTable(
|
||||
new YamlConfigTableRegistrationOptions<int, MonsterConfigStub>(
|
||||
"monster",
|
||||
"monster",
|
||||
static config => config.Id)
|
||||
{
|
||||
SchemaRelativePath = "schemas/monster.schema.json"
|
||||
});
|
||||
var registry = new ConfigRegistry();
|
||||
await loader.LoadAsync(registry);
|
||||
|
||||
var reloadTaskSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var hotReload = loader.EnableHotReload(
|
||||
registry,
|
||||
new YamlConfigHotReloadOptions
|
||||
{
|
||||
OnTableReloaded = tableName => reloadTaskSource.TrySetResult(tableName),
|
||||
DebounceDelay = TimeSpan.FromMilliseconds(150)
|
||||
});
|
||||
var (loader, registry) = await CreateLoadedMonsterHotReloadScenarioAsync(useOptionsObject: true)
|
||||
.ConfigureAwait(false);
|
||||
var (reloadTaskSource, hotReload) = EnableHotReloadWithReloadCapture(loader, registry, useOptionsObject: true);
|
||||
|
||||
try
|
||||
{
|
||||
CreateConfigFile(
|
||||
"monster/slime.yaml",
|
||||
"""
|
||||
id: 1
|
||||
name: Slime
|
||||
hp: 25
|
||||
""");
|
||||
CreateConfigFile("monster/slime.yaml", UpdatedMonsterConfigContent);
|
||||
|
||||
var tableName = await WaitForTaskWithinAsync(reloadTaskSource.Task, TimeSpan.FromSeconds(5));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(tableName, Is.EqualTo("monster"));
|
||||
Assert.That(registry.GetTable<int, MonsterConfigStub>("monster").Get(1).Hp, Is.EqualTo(25));
|
||||
});
|
||||
var tableName = await WaitForTaskWithinAsync(reloadTaskSource.Task, TimeSpan.FromSeconds(5))
|
||||
.ConfigureAwait(false);
|
||||
AssertMonsterHotReloadUpdated(tableName, registry);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -3050,60 +2935,15 @@ public class YamlConfigLoaderTests
|
||||
[Test]
|
||||
public async Task EnableHotReload_Should_Keep_Previous_Table_When_Schema_Change_Makes_Reload_Fail()
|
||||
{
|
||||
CreateConfigFile(
|
||||
"monster/slime.yaml",
|
||||
"""
|
||||
id: 1
|
||||
name: Slime
|
||||
hp: 10
|
||||
""");
|
||||
CreateSchemaFile(
|
||||
"schemas/monster.schema.json",
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
"name": { "type": "string" },
|
||||
"hp": { "type": "integer" }
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
var loader = new YamlConfigLoader(_rootPath)
|
||||
.RegisterTable<int, MonsterConfigStub>("monster", "monster", "schemas/monster.schema.json",
|
||||
static config => config.Id);
|
||||
var registry = new ConfigRegistry();
|
||||
await loader.LoadAsync(registry);
|
||||
|
||||
var reloadFailureTaskSource =
|
||||
new TaskCompletionSource<(string TableName, Exception Exception)>(TaskCreationOptions
|
||||
.RunContinuationsAsynchronously);
|
||||
var hotReload = loader.EnableHotReload(
|
||||
registry,
|
||||
onTableReloadFailed: (tableName, exception) =>
|
||||
reloadFailureTaskSource.TrySetResult((tableName, exception)),
|
||||
debounceDelay: TimeSpan.FromMilliseconds(150));
|
||||
var (loader, registry) = await CreateLoadedMonsterHotReloadScenarioAsync().ConfigureAwait(false);
|
||||
var (reloadFailureTaskSource, hotReload) = EnableHotReloadWithFailureCapture(loader, registry);
|
||||
|
||||
try
|
||||
{
|
||||
CreateSchemaFile(
|
||||
"schemas/monster.schema.json",
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name", "rarity"],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
"name": { "type": "string" },
|
||||
"hp": { "type": "integer" },
|
||||
"rarity": { "type": "string" }
|
||||
}
|
||||
}
|
||||
""");
|
||||
CreateSchemaFile("schemas/monster.schema.json", MonsterSchemaWithRarityContent);
|
||||
|
||||
var failure = await WaitForTaskWithinAsync(reloadFailureTaskSource.Task, TimeSpan.FromSeconds(5));
|
||||
var failure = await WaitForTaskWithinAsync(reloadFailureTaskSource.Task, TimeSpan.FromSeconds(5))
|
||||
.ConfigureAwait(false);
|
||||
var diagnosticException = failure.Exception as ConfigLoadException;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
@ -3130,75 +2970,15 @@ public class YamlConfigLoaderTests
|
||||
[Test]
|
||||
public async Task EnableHotReload_Should_Keep_Previous_State_When_Dependency_Table_Breaks_Cross_Table_Reference()
|
||||
{
|
||||
CreateConfigFile(
|
||||
"item/potion.yaml",
|
||||
"""
|
||||
id: potion
|
||||
name: Potion
|
||||
""");
|
||||
CreateConfigFile(
|
||||
"monster/slime.yaml",
|
||||
"""
|
||||
id: 1
|
||||
name: Slime
|
||||
dropItemId: potion
|
||||
""");
|
||||
CreateSchemaFile(
|
||||
"schemas/item.schema.json",
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"name": { "type": "string" }
|
||||
}
|
||||
}
|
||||
""");
|
||||
CreateSchemaFile(
|
||||
"schemas/monster.schema.json",
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name", "dropItemId"],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
"name": { "type": "string" },
|
||||
"dropItemId": {
|
||||
"type": "string",
|
||||
"x-gframework-ref-table": "item"
|
||||
}
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
var loader = new YamlConfigLoader(_rootPath)
|
||||
.RegisterTable<string, ItemConfigStub>("item", "item", "schemas/item.schema.json",
|
||||
static config => config.Id)
|
||||
.RegisterTable<int, MonsterDropConfigStub>("monster", "monster", "schemas/monster.schema.json",
|
||||
static config => config.Id);
|
||||
var registry = new ConfigRegistry();
|
||||
await loader.LoadAsync(registry);
|
||||
|
||||
var reloadFailureTaskSource =
|
||||
new TaskCompletionSource<(string TableName, Exception Exception)>(TaskCreationOptions
|
||||
.RunContinuationsAsynchronously);
|
||||
var hotReload = loader.EnableHotReload(
|
||||
registry,
|
||||
onTableReloadFailed: (tableName, exception) =>
|
||||
reloadFailureTaskSource.TrySetResult((tableName, exception)),
|
||||
debounceDelay: TimeSpan.FromMilliseconds(150));
|
||||
var (loader, registry) = await CreateLoadedCrossTableReferenceHotReloadScenarioAsync().ConfigureAwait(false);
|
||||
var (reloadFailureTaskSource, hotReload) = EnableHotReloadWithFailureCapture(loader, registry);
|
||||
|
||||
try
|
||||
{
|
||||
CreateConfigFile(
|
||||
"item/potion.yaml",
|
||||
"""
|
||||
id: elixir
|
||||
name: Elixir
|
||||
""");
|
||||
CreateConfigFile("item/potion.yaml", UpdatedItemConfigContent);
|
||||
|
||||
var failure = await WaitForTaskWithinAsync(reloadFailureTaskSource.Task, TimeSpan.FromSeconds(5));
|
||||
var failure = await WaitForTaskWithinAsync(reloadFailureTaskSource.Task, TimeSpan.FromSeconds(5))
|
||||
.ConfigureAwait(false);
|
||||
var diagnosticException = failure.Exception as ConfigLoadException;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
@ -3223,6 +3003,243 @@ public class YamlConfigLoaderTests
|
||||
}
|
||||
}
|
||||
|
||||
private const string ItemSchemaContent =
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"name": { "type": "string" }
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
private const string InitialMonsterConfigContent =
|
||||
"""
|
||||
id: 1
|
||||
name: Slime
|
||||
hp: 10
|
||||
""";
|
||||
|
||||
private const string UpdatedMonsterConfigContent =
|
||||
"""
|
||||
id: 1
|
||||
name: Slime
|
||||
hp: 25
|
||||
""";
|
||||
|
||||
private const string MonsterSchemaContent =
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
"name": { "type": "string" },
|
||||
"hp": { "type": "integer" }
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
private const string MonsterSchemaWithRarityContent =
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name", "rarity"],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
"name": { "type": "string" },
|
||||
"hp": { "type": "integer" },
|
||||
"rarity": { "type": "string" }
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
private const string UpdatedItemConfigContent =
|
||||
"""
|
||||
id: elixir
|
||||
name: Elixir
|
||||
""";
|
||||
|
||||
private const string MonsterDropArrayConfigContent =
|
||||
"""
|
||||
id: 1
|
||||
name: Slime
|
||||
dropItemIds:
|
||||
- potion
|
||||
""";
|
||||
|
||||
private const string MonsterDropArraySchemaContent =
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name", "dropItemIds"],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
"name": { "type": "string" },
|
||||
"dropItemIds": {
|
||||
"type": "array",
|
||||
"minContains": 1,
|
||||
"contains": {
|
||||
"type": "string",
|
||||
"x-gframework-ref-table": "item"
|
||||
},
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
private const string MonsterDropConfigContent =
|
||||
"""
|
||||
id: 1
|
||||
name: Slime
|
||||
dropItemId: potion
|
||||
""";
|
||||
|
||||
private const string MonsterDropSchemaContent =
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name", "dropItemId"],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
"name": { "type": "string" },
|
||||
"dropItemId": {
|
||||
"type": "string",
|
||||
"x-gframework-ref-table": "item"
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// 创建并加载标准 monster 热重载夹具,供重载成功与 schema 失败场景复用。
|
||||
/// </summary>
|
||||
/// <param name="useOptionsObject">是否通过选项对象注册表。</param>
|
||||
/// <returns>已完成首次加载的加载器与注册表。</returns>
|
||||
private async Task<(YamlConfigLoader Loader, ConfigRegistry Registry)> CreateLoadedMonsterHotReloadScenarioAsync(
|
||||
bool useOptionsObject = false)
|
||||
{
|
||||
CreateConfigFile("monster/slime.yaml", InitialMonsterConfigContent);
|
||||
CreateSchemaFile("schemas/monster.schema.json", MonsterSchemaContent);
|
||||
|
||||
var loader = useOptionsObject
|
||||
? new YamlConfigLoader(_rootPath).RegisterTable(
|
||||
new YamlConfigTableRegistrationOptions<int, MonsterConfigStub>(
|
||||
"monster",
|
||||
"monster",
|
||||
static config => config.Id)
|
||||
{
|
||||
SchemaRelativePath = "schemas/monster.schema.json"
|
||||
})
|
||||
: new YamlConfigLoader(_rootPath)
|
||||
.RegisterTable<int, MonsterConfigStub>("monster", "monster", "schemas/monster.schema.json",
|
||||
static config => config.Id);
|
||||
var registry = new ConfigRegistry();
|
||||
await loader.LoadAsync(registry).ConfigureAwait(false);
|
||||
return (loader, registry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建并加载 contains 子 schema 引用场景,供热重载依赖回滚测试复用。
|
||||
/// </summary>
|
||||
/// <returns>已完成首次加载的加载器与注册表。</returns>
|
||||
private async Task<(YamlConfigLoader Loader, ConfigRegistry Registry)>
|
||||
CreateLoadedContainsReferenceHotReloadScenarioAsync()
|
||||
{
|
||||
var loader = CreateItemBackedMonsterLoader<MonsterDropArrayConfigStub>(
|
||||
MonsterDropArrayConfigContent,
|
||||
MonsterDropArraySchemaContent,
|
||||
static config => config.Id,
|
||||
("item/potion.yaml", "potion", "Potion"));
|
||||
var registry = new ConfigRegistry();
|
||||
await loader.LoadAsync(registry).ConfigureAwait(false);
|
||||
return (loader, registry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建并加载跨表单值引用场景,供热重载依赖回滚测试复用。
|
||||
/// </summary>
|
||||
/// <returns>已完成首次加载的加载器与注册表。</returns>
|
||||
private async Task<(YamlConfigLoader Loader, ConfigRegistry Registry)>
|
||||
CreateLoadedCrossTableReferenceHotReloadScenarioAsync()
|
||||
{
|
||||
var loader = CreateItemBackedMonsterLoader<MonsterDropConfigStub>(
|
||||
MonsterDropConfigContent,
|
||||
MonsterDropSchemaContent,
|
||||
static config => config.Id,
|
||||
("item/potion.yaml", "potion", "Potion"));
|
||||
var registry = new ConfigRegistry();
|
||||
await loader.LoadAsync(registry).ConfigureAwait(false);
|
||||
return (loader, registry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以统一的失败回调配置启用热重载,避免每个测试重复接线相同的通知逻辑。
|
||||
/// </summary>
|
||||
/// <param name="loader">已完成首次加载的加载器。</param>
|
||||
/// <param name="registry">要复用的配置注册表。</param>
|
||||
/// <returns>失败通知任务源与取消注册句柄。</returns>
|
||||
private static (TaskCompletionSource<(string TableName, Exception Exception)> TaskSource, IUnRegister Registration)
|
||||
EnableHotReloadWithFailureCapture(YamlConfigLoader loader, ConfigRegistry registry)
|
||||
{
|
||||
var reloadFailureTaskSource =
|
||||
new TaskCompletionSource<(string TableName, Exception Exception)>(TaskCreationOptions
|
||||
.RunContinuationsAsynchronously);
|
||||
var hotReload = loader.EnableHotReload(
|
||||
registry,
|
||||
onTableReloadFailed: (tableName, exception) =>
|
||||
reloadFailureTaskSource.TrySetResult((tableName, exception)),
|
||||
debounceDelay: TimeSpan.FromMilliseconds(150));
|
||||
return (reloadFailureTaskSource, hotReload);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以统一的成功回调配置启用热重载,避免相同的防抖与回调装配在测试中重复出现。
|
||||
/// </summary>
|
||||
/// <param name="loader">已完成首次加载的加载器。</param>
|
||||
/// <param name="registry">要复用的配置注册表。</param>
|
||||
/// <param name="useOptionsObject">是否通过选项对象启用热重载。</param>
|
||||
/// <returns>成功通知任务源与取消注册句柄。</returns>
|
||||
private static (TaskCompletionSource<string> TaskSource, IUnRegister Registration) EnableHotReloadWithReloadCapture(
|
||||
YamlConfigLoader loader,
|
||||
ConfigRegistry registry,
|
||||
bool useOptionsObject = false)
|
||||
{
|
||||
var reloadTaskSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var hotReload = useOptionsObject
|
||||
? loader.EnableHotReload(
|
||||
registry,
|
||||
new YamlConfigHotReloadOptions
|
||||
{
|
||||
OnTableReloaded = tableName => reloadTaskSource.TrySetResult(tableName),
|
||||
DebounceDelay = TimeSpan.FromMilliseconds(150)
|
||||
})
|
||||
: loader.EnableHotReload(
|
||||
registry,
|
||||
onTableReloaded: tableName => reloadTaskSource.TrySetResult(tableName),
|
||||
debounceDelay: TimeSpan.FromMilliseconds(150));
|
||||
return (reloadTaskSource, hotReload);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断言标准 monster 热重载成功后,通知表名与刷新后的生命值都符合预期。
|
||||
/// </summary>
|
||||
/// <param name="tableName">热重载回调返回的表名。</param>
|
||||
/// <param name="registry">承载刷新结果的注册表。</param>
|
||||
private static void AssertMonsterHotReloadUpdated(string tableName, ConfigRegistry registry)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(tableName, Is.EqualTo("monster"));
|
||||
Assert.That(registry.GetTable<int, MonsterConfigStub>("monster").Get(1).Hp, Is.EqualTo(25));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为对象数组 <c>contains</c> 子集匹配场景创建加载器,避免测试方法体被大段固定 schema 稀释。
|
||||
/// </summary>
|
||||
|
||||
@ -6,37 +6,39 @@
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-065`
|
||||
- 当前阶段:`Phase 65`
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-066`
|
||||
- 当前阶段:`Phase 66`
|
||||
- 当前焦点:
|
||||
- `2026-04-25` 已确认此前一批 `dotnet clean` / `dotnet build` / `dotnet test` 异常主要来自 agent 沙箱环境,而不是仓库或 WSL 默认 shell 本身
|
||||
- 已用提权后的直接命令重新建立仓库根基线:`dotnet clean` 成功,`dotnet build` 结果为 `656 Warning(s)`、`0 Error(s)`
|
||||
- 当前 `HEAD` 与 `origin/main` 对齐;基于 `$gframework-batch-boot 50` 的 committed branch diff 现为 `0 files / 0 lines`
|
||||
- 当前活跃写集是 4 个测试噪音清理文件,属于新的低风险 warning-reduction 批次;提交前需由主线程在沙箱外重新验证
|
||||
- 主线程已完成该批次的沙箱外复核,当前可安全并入本轮提交
|
||||
- 已决定把“沙箱内 .NET 验证失败时必须申请沙箱外重跑并以该结果为准”写入 `AGENTS.md`,避免后续继续扩散伪环境阻塞
|
||||
- `2026-04-25` 已先提交 `6a704f3` `fix(analyzer): 固化沙箱外验证并清理测试噪音`,把 AGENTS / active ai-plan 真值修正与 4 文件测试噪音批次一起收口
|
||||
- 当前单文件批次聚焦 `GFramework.Game.Tests/Config/YamlConfigLoaderTests.cs`,已收敛 4 个根构建直接确认的 `MA0051`
|
||||
- 提权后的直接仓库根基线已从 `656 Warning(s)` 降至 `652 Warning(s)`,说明本轮单文件批次有效
|
||||
- `GFramework.Game.Tests` 的直接受影响 Release build 当前为 `0 Warning(s)`、`0 Error(s)`
|
||||
- 本批次落地后,branch diff 相对 `origin/main` 将从 `7 files` 推进到 `8 files`,仍显著低于 `$gframework-batch-boot 50` 阈值
|
||||
|
||||
## 当前活跃事实
|
||||
|
||||
- 当前 `origin/main` 基线提交为 `4ad880c`(`2026-04-25T14:35:38+08:00`)。
|
||||
- `fix/analyzer-warning-reduction-batch` 当前 `HEAD` 等于 `origin/main`;因此 shorthand 阈值 `$gframework-batch-boot 50` 的当前 committed 规模为:
|
||||
- `git diff --name-only origin/main...HEAD | wc -l`:`0`
|
||||
- `git diff --numstat origin/main...HEAD`:`0 added / 0 deleted`
|
||||
- 提权后的直接仓库根验证已经确认:
|
||||
- `6a704f3` 落地后,当前 committed branch diff 相对 `origin/main` 为:
|
||||
- `git diff --name-only origin/main...HEAD | wc -l`:`7`
|
||||
- `git diff --numstat origin/main...HEAD`:累计 `104` added、`123` deleted
|
||||
- 提权后的直接仓库根验证当前确认为:
|
||||
- `dotnet clean`
|
||||
- 结果:成功;此前沙箱内 “Build FAILED but 0 errors” 的 clean 结果不是仓库真值
|
||||
- `dotnet build`
|
||||
- 结果:成功;`656 Warning(s)`、`0 Error(s)`,当前 warning reduction 应以此为总基线
|
||||
- 当前待集成的低风险批次文件:
|
||||
- 最新结果:成功;`652 Warning(s)`、`0 Error(s)`
|
||||
- 已提交的低风险批次文件:
|
||||
- `AGENTS.md`
|
||||
- `GFramework.Ecs.Arch.Tests/Ecs/EcsAdvancedTests.cs`
|
||||
- `GFramework.Game.Tests/Config/GameConfigBootstrapTests.cs`
|
||||
- `GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs`
|
||||
- `GFramework.Game.Tests/Config/YamlConfigTextValidatorTests.cs`
|
||||
- `GFramework.Ecs.Arch.Tests/Ecs/EcsAdvancedTests.cs`
|
||||
- 上述批次的 worker 侧验证结果:
|
||||
- `ai-plan/public/analyzer-warning-reduction/todos/analyzer-warning-reduction-tracking.md`
|
||||
- `ai-plan/public/analyzer-warning-reduction/traces/analyzer-warning-reduction-trace.md`
|
||||
- 当前待提交批次文件:
|
||||
- `GFramework.Game.Tests/Config/YamlConfigLoaderTests.cs`
|
||||
- 当前批次验证结果:
|
||||
- `dotnet build GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release`
|
||||
- 最新主线程结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet build GFramework.Ecs.Arch.Tests/GFramework.Ecs.Arch.Tests.csproj -c Release`
|
||||
- 最新主线程结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
|
||||
## 当前风险
|
||||
|
||||
@ -64,18 +66,16 @@
|
||||
- `dotnet clean`
|
||||
- 当前结果:成功;在提权后的直接 shell 中可正常完成仓库根 clean
|
||||
- `dotnet build`
|
||||
- 当前结果:成功;`656 Warning(s)`、`0 Error(s)`
|
||||
- 当前结果:成功;`652 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet build GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release`
|
||||
- 当前结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet build GFramework.Ecs.Arch.Tests/GFramework.Ecs.Arch.Tests.csproj -c Release`
|
||||
- 当前结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- `git diff --name-only origin/main...HEAD | wc -l`
|
||||
- 当前结果:`0`
|
||||
- 当前结果:`7`
|
||||
- `git diff --numstat origin/main...HEAD`
|
||||
- 当前结果:`0 added / 0 deleted`
|
||||
- 当前结果:累计 `104` added、`123` deleted
|
||||
|
||||
## 下一步建议
|
||||
|
||||
1. 集成并复核当前 4 文件测试噪音批次后,用沙箱外 `dotnet build GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release` 与 `dotnet build GFramework.Ecs.Arch.Tests/GFramework.Ecs.Arch.Tests.csproj -c Release` 重新确认结果。
|
||||
2. 下一轮 warning reduction 继续优先处理 `GFramework.Game.Tests/Config/YamlConfigLoaderTests.cs` 的长方法切片;它仍是已确认的单文件低风险热点,适合继续用 worker 独立推进。
|
||||
1. 提交当前 `YamlConfigLoaderTests.cs` 单文件批次后,继续按 `$gframework-batch-boot 50` 规则重算 branch diff,并挑选下一个 1-3 文件的低风险热点。
|
||||
2. 下一轮优先从 `GFramework.Cqrs.Tests` 或 `GFramework.Game` 中继续选择单文件 `MA0051` / 测试噪音切片,避免过早推高 review 范围。
|
||||
3. 后续凡是沙箱内 `.NET` 验证再次出现无诊断失败、pipe/socket 权限问题或与普通 shell 不一致的结果,直接申请沙箱外重跑同一命令,不再扩散 workaround 型命令噪音。
|
||||
|
||||
@ -1,5 +1,32 @@
|
||||
# Analyzer Warning Reduction 追踪
|
||||
|
||||
## 2026-04-25 — RP-066
|
||||
|
||||
### 阶段:主线程回收停滞的单文件批次,并继续压低根构建 warning 基线
|
||||
|
||||
- 触发背景:
|
||||
- `RP-065` 收尾后,`fix/analyzer-warning-reduction-batch` 已通过 `6a704f3` 把 AGENTS / active ai-plan 真值修正和 4 文件测试噪音批次提交到分支
|
||||
- 原先负责 `YamlConfigLoaderTests.cs` 的 worker 长时间无结果,主线程收回该单文件批次以避免继续阻塞
|
||||
- 主线程实施:
|
||||
- 关闭停滞 worker,直接重构 `GFramework.Game.Tests/Config/YamlConfigLoaderTests.cs`
|
||||
- 通过提取固定夹具内容、热重载接线 helper 与共享断言,收敛以下 4 个长方法 warning:
|
||||
- `EnableHotReload_Should_Keep_Previous_State_When_Contains_Reference_Dependency_Breaks`
|
||||
- `EnableHotReload_Should_Support_Options_Object`
|
||||
- `EnableHotReload_Should_Keep_Previous_Table_When_Schema_Change_Makes_Reload_Fail`
|
||||
- `EnableHotReload_Should_Keep_Previous_State_When_Dependency_Table_Breaks_Cross_Table_Reference`
|
||||
- 在第一次仓库根重建中命中了两个 `CS0411` 泛型推断错误,主线程随即补上显式类型参数并重新建立 clean/build 基线
|
||||
- 验证里程碑:
|
||||
- `dotnet clean`
|
||||
- 结果:成功
|
||||
- `dotnet build`
|
||||
- 结果:成功;`652 Warning(s)`、`0 Error(s)`,相较 `RP-065` 的 `656` 再下降 `4`
|
||||
- `dotnet build GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release`
|
||||
- 结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- 当前结论:
|
||||
- `YamlConfigLoaderTests.cs` 这 4 个根构建直接确认的 `MA0051` 已被消化
|
||||
- 当前分支在 `6a704f3` 之后的下一提交只会新增 1 个唯一文件,因此 branch diff 仍明显低于 `$gframework-batch-boot 50` 阈值
|
||||
- 下一轮可继续选择新的单文件或小写集热点,而不必暂停当前 batch loop
|
||||
|
||||
## 2026-04-25 — RP-065
|
||||
|
||||
### 阶段:确认 .NET 验证噪音来自沙箱,并把无沙箱直跑写成仓库规则
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user