From 5f2442dbcdfa0f87acf85c02c98a3a2778f972e5 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:07:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(ai-first-config):=20=E6=94=B6=E5=8F=A3?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=88=86=E6=94=AF=E8=AF=84=E5=AE=A1=E8=B7=9F?= =?UTF-8?q?=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 Runtime 条件分支 schema 坏形状的诊断路径,改为指向具体 if/then/else 分支 - 新增 else 缺失 if 的运行时回归测试,保持与 Generator 覆盖对称 - 更新 ai-plan 跟踪与 trace,记录 PR #262 follow-up 验证并消除重复标题 --- .../Config/YamlConfigLoaderIfThenElseTests.cs | 41 +++++++++++++++++++ ...amlConfigSchemaValidator.ObjectKeywords.cs | 4 +- .../todos/ai-first-config-system-tracking.md | 18 +++++--- .../traces/ai-first-config-system-trace.md | 14 ++++--- 4 files changed, 65 insertions(+), 12 deletions(-) diff --git a/GFramework.Game.Tests/Config/YamlConfigLoaderIfThenElseTests.cs b/GFramework.Game.Tests/Config/YamlConfigLoaderIfThenElseTests.cs index f41efd5c..c73c3a56 100644 --- a/GFramework.Game.Tests/Config/YamlConfigLoaderIfThenElseTests.cs +++ b/GFramework.Game.Tests/Config/YamlConfigLoaderIfThenElseTests.cs @@ -313,6 +313,47 @@ public sealed class YamlConfigLoaderIfThenElseTests }); } + /// + /// 验证缺少 if 却声明 else 时,会在 schema 解析阶段被拒绝。 + /// + [Test] + public void LoadAsync_Should_Throw_When_Else_Is_Declared_Without_If() + { + CreateConfigFile( + "monster/slime.yaml", + BuildMonsterConfigYaml( + """ + bonus: 1 + """)); + CreateSchemaFile( + "schemas/monster.schema.json", + BuildMonsterSchema( + DefaultRewardPropertiesJson, + """ + "else": { + "type": "object", + "required": ["bonus"], + "properties": { + "bonus": { "type": "integer" } + } + } + """)); + + var loader = CreateMonsterRewardLoader(); + var registry = CreateRegistry(); + + var exception = Assert.ThrowsAsync(async () => await loader.LoadAsync(registry)); + + Assert.Multiple(() => + { + Assert.That(exception, Is.Not.Null); + Assert.That(exception!.Diagnostic.FailureKind, Is.EqualTo(ConfigLoadFailureKind.SchemaUnsupported)); + Assert.That(exception.Diagnostic.DisplayPath, Is.EqualTo("reward")); + Assert.That(exception.Message, Does.Contain("must declare 'if' when using 'then' or 'else'")); + Assert.That(registry.Count, Is.EqualTo(0)); + }); + } + /// /// 验证条件分支不能要求父对象未声明的字段。 /// diff --git a/GFramework.Game/Config/YamlConfigSchemaValidator.ObjectKeywords.cs b/GFramework.Game/Config/YamlConfigSchemaValidator.ObjectKeywords.cs index e8e5623d..4358d850 100644 --- a/GFramework.Game/Config/YamlConfigSchemaValidator.ObjectKeywords.cs +++ b/GFramework.Game/Config/YamlConfigSchemaValidator.ObjectKeywords.cs @@ -441,9 +441,9 @@ internal static partial class YamlConfigSchemaValidator throw ConfigLoadExceptionFactory.Create( ConfigLoadFailureKind.SchemaUnsupported, tableName, - $"{DescribeObjectSchemaTarget(propertyPath)} in schema file '{schemaPath}' must declare '{keywordName}' as an object-valued schema.", + $"{DescribeObjectSchemaTarget(conditionalSchemaPath)} in schema file '{schemaPath}' must declare '{keywordName}' as an object-valued schema.", schemaPath: schemaPath, - displayPath: GetDiagnosticPath(propertyPath)); + displayPath: GetDiagnosticPath(conditionalSchemaPath)); } ValidateInlineObjectSchemaTargetsAgainstParentObject( diff --git a/ai-plan/public/ai-first-config-system/todos/ai-first-config-system-tracking.md b/ai-plan/public/ai-first-config-system/todos/ai-first-config-system-tracking.md index e9115842..0c39d776 100644 --- a/ai-plan/public/ai-first-config-system/todos/ai-first-config-system-tracking.md +++ b/ai-plan/public/ai-first-config-system/todos/ai-first-config-system-tracking.md @@ -23,6 +23,8 @@ - 缓解措施:继续为新增共享关键字补齐三端测试覆盖,优先保证 C# Runtime 与 Generator 回归通过,并记录 JS 测试与构建验证 - PR review 信号漂移风险:CodeRabbit 可能把建议折叠在 latest review body,而不是 issue comments - 缓解措施:`gframework-pr-review` 现已同时解析 latest review body,并输出 declared / parsed 数量以便快速识别解析缺口 +- PR follow-up 残留风险:PR `#262` 最新 review thread 仍有少量 open comments,且 nitpick body 解析仍存在 declared / parsed 缺口 + - 缓解措施:先以 latest unresolved thread 为准逐条本地核验;已确认并补齐运行时诊断路径与 `else without if` 回归测试,剩余解析缺口单独留在 skill 后续处理 - 非阻塞项回退风险:将 VS Code 功能标为非阻塞但导致主线回退的风险 - 缓解措施:C# 主线补齐新关键字时仍需在 `configValidation.js` 与 `extension.js` 中同步落地,只是不让复杂表单控件阻塞发布 @@ -49,6 +51,12 @@ - `gframework-pr-review` 现已解析 latest CodeRabbit review body 中 folded `Nitpick comments` - text 输出会显示 `CodeRabbit nitpick comments: X declared, Y parsed`,避免再次静默遗漏 - 已按 5 条 nitpick 更新 VS Code tool hints、shared validation helper,以及对称分支测试覆盖 +- PR `#262` 最新 follow-up: + - 最新抓取结果显示仍有 2 条 actionable comments 与 1 条已解析 nitpick 需要本地核验 + - `SchemaConfigGenerator` 的分支级诊断定位已在当前分支,无需重复修改 + - `YamlConfigSchemaValidator` 已补齐 `conditionalSchemaPath` 诊断路径,避免 `reward[then]` / `reward[else]` 坏形状误报到父路径 + - `YamlConfigLoaderIfThenElseTests` 已新增运行时 `else` 缺失 `if` 回归,避免 Runtime / Generator 覆盖漂移 + - active trace 已将重复的 `### 验证` 标题改为专用 PR follow-up 标题,消除 `MD024` - 分支同步状态: - `feat/ai-first-config` 已 rebase 到 `origin/feat/ai-first-config` - 当前已解决“ahead / behind 同时存在”的分支差异,不再 behind 远端 @@ -74,14 +82,14 @@ - `2026-04-17` 之前的详细实现记录与定向验证命令已归档到历史 tracking / trace - active 跟踪文件只保留当前恢复点、当前状态和下一步,不再重复堆积已完成阶段的完整历史 - `2026-04-20` 当前恢复点验证: - - `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py`:通过(`CodeRabbit nitpick comments: 5 declared, 5 parsed`) + - `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py`:通过(`CodeRabbit actionable comments: 2`,`CodeRabbit nitpick comments: 2 declared, 1 parsed`) - `bun run test`(`tools/gframework-config-tool`):通过 - `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~SchemaConfigGeneratorTests"`:通过 - - `dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "FullyQualifiedName~YamlConfigLoaderIfThenElseTests"`:通过 + - `dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "FullyQualifiedName~YamlConfigLoaderIfThenElseTests"`:通过(8 tests;新增 `else without if` 运行时回归) - `dotnet build GFramework.sln -c Release`:通过(存在仓库既有 analyzer warning,无新增错误) ## 下一步 -1. 先用 `GFramework.Game/Config/YamlConfigSchemaValidator.cs`、`GFramework.Game.SourceGenerators/Config/SchemaConfigGenerator.cs`、`tools/gframework-config-tool/src/configValidation.js` 盘点下一批候选关键字 -2. 优先判断 `oneOf` / `anyOf` 是否存在可接受的 object-focused 子集;如果仍会引入生成类型形状漂移,就直接跳过 -3. 在下一批关键字之前,保持“Runtime / Generator / Tooling 三端一致且不做属性合并”这条筛选线 +1. 提交并推送当前 PR `#262` follow-up 修复后,重新抓取一次 PR review,确认 open thread 是否已清空或只剩 parser gap +2. 若 PR review 已收口,再回到 `GFramework.Game/Config/YamlConfigSchemaValidator.cs`、`GFramework.Game.SourceGenerators/Config/SchemaConfigGenerator.cs`、`tools/gframework-config-tool/src/configValidation.js` 盘点下一批候选关键字 +3. 优先判断 `oneOf` / `anyOf` 是否存在可接受的 object-focused 子集;若仍会引入生成类型形状漂移,就直接跳过 diff --git a/ai-plan/public/ai-first-config-system/traces/ai-first-config-system-trace.md b/ai-plan/public/ai-first-config-system/traces/ai-first-config-system-trace.md index 213a8a2e..4693c3c0 100644 --- a/ai-plan/public/ai-first-config-system/traces/ai-first-config-system-trace.md +++ b/ai-plan/public/ai-first-config-system/traces/ai-first-config-system-trace.md @@ -78,20 +78,24 @@ - rebase 过程中 Git 跳过了远端已具备的 commit `76488dc` - 当前分支已不再 behind 远端,仅保留本地领先提交 -### 验证 +### PR `#262` review follow-up 验证 - 2026-04-20:`python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py` - 结果:通过 - - 备注:输出 `CodeRabbit nitpick comments: 5 declared, 5 parsed` + - 备注:输出 `CodeRabbit actionable comments: 2`、`CodeRabbit nitpick comments: 2 declared, 1 parsed`,并暴露剩余 review follow-up +- 2026-04-20:运行时条件分支 follow-up + - 结果:已补齐 + - 备注:`YamlConfigSchemaValidator` 现对非 object 的 `if` / `then` / `else` 使用分支级诊断路径;运行时测试新增 `else` 缺失 `if` 回归 - 2026-04-20:`bun run test`(`tools/gframework-config-tool`) - 结果:通过(118 tests) - 2026-04-20:`dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~SchemaConfigGeneratorTests"` - 结果:通过(46 tests) - 2026-04-20:`dotnet test GFramework.Game.Tests/GFramework.Game.Tests.csproj -c Release --filter "FullyQualifiedName~YamlConfigLoaderIfThenElseTests"` - - 结果:通过(7 tests) + - 结果:通过(8 tests) + - 备注:新增 `LoadAsync_Should_Throw_When_Else_Is_Declared_Without_If` 后,运行时回归覆盖保持对称 - 2026-04-20:`dotnet build GFramework.sln -c Release` - - 结果:通过 - - 备注:存在仓库既有 analyzer warning,但无新增错误 + - 结果:通过(历史记录) + - 备注:存在仓库既有 analyzer warning,但无新增错误;本轮只需重新验证受影响测试切片 ### 下一步