You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

7.8 KiB

N03 SDD W3 聚焦复审报告

复审对象

  • 代码基线:cd9220b,修复差异仍位于工作区,未提交。
  • 复审范围:W3-I1、W3-I2 两项 Important finding 的聚焦修复。
  • 环境:JAVA_HOME=D:\java\jdk,Maven D:\maven\apache-maven-3.9.7\bin\mvn.cmd。
  • 对照报告:changes/n03-skill-cloud/.superpowers/sdd/reviews/W3-wave.md。

Verdict

FAIL

W3-I1 的原始 /skills/match operationId 冲突已修复,W3-I2 要求的运行时 401 契约、Markdown 文档和静态 OpenAPI 已对齐;但本次为满足全局 operationId 唯一性而修改了两处既有 cancel 契约,新增一项 Important 问题。

因此 W3 仍不能判定通过,不能进入收尾或 TO-11。

W3-I1:operationId 冲突

关闭状态

原始 finding 已关闭。

  • SkillCloudController.java:44 显式设置 operationId=getWordCloud。
  • SkillCloudController.java:92 显式设置 operationId=getSkillMatch。
  • SkillCloudController.java:140 显式设置 operationId=getLearningPath。
  • 静态 OpenAPI 三个 Skill Cloud operationId 与上述值完全一致:
    • /skills/word-cloud = getWordCloud
    • /skills/match = getSkillMatch
    • /skills/learning-path = getLearningPath
  • docs/verify_openapi.py:165-168 对三个 operationId 做精确断言。
  • SkillCloudControllerTest.skillOperationIdsAreExactAndGloballyUnique 通过运行时 /v3/api-docs 校验三个接口的 operationId,并确认每个目标 operationId 只对应目标路径。

新增问题 N-I1(Important):修改了既有 OpenAPI 契约

docs/verify_openapi.py:27-31 新增了对全文档 operationId 的无条件唯一性断言。为让该断言通过,本次修复还修改了与 N03 无关的两个既有接口:

  • POST /interviews/{interviewId}/cancel:cancel → cancelInterview
  • POST /profile/me/deletion/cancel:cancel → cancelAccountDeletion

问题如下:

  1. operationId 属于 OpenAPI 公共契约,常用于客户端和 SDK 生成。修改既有 operationId 属于兼容性破坏,即使 HTTP 路径和运行时行为不变,也可能导致生成客户端的方法名变化或升级失败。
  2. 两个 cancel 重复值是本次变更前已经存在的历史问题,不是 N03 引入的问题,也不在 W3-I1 的修复范围内。
  3. InterviewController.java:132-136 和 AccountDeletionController.java:112-115 仍使用方法名 cancel,且没有显式 operationId;因此静态 OpenAPI 被改为两个新名称后,静态契约与运行时 SpringDoc 文档发生漂移。
  4. SkillCloudControllerTest.skillOperationIdsAreExactAndGloballyUnique 的名称虽然包含 “GloballyUnique”,但实际只验证三个 Skill Cloud operationId 各自只出现一次,并没有验证全文档唯一性。真正强制全文档唯一性的是 verify_openapi.py,而它迫使本次变更修改历史契约。

严重级别:Important。

最小修复建议:

  • 将 docs/openapi-rc.json 中两个既有接口的 operationId 恢复为 cancel,不要在本变更中修改既有接口契约。
  • 将 docs/verify_openapi.py 的检查改为“新增接口不得产生新冲突”,而不是“修复全部历史冲突”。例如:
    • 保留已知历史重复集合 {'cancel'};
    • 断言除该允许集合外没有其他重复 operationId;
    • 断言 getWordCloud/getSkillMatch/getLearningPath 各出现且仅出现一次;
    • 断言它们不与历史或未来任何非允许 operationId 冲突。
  • 如果项目要求彻底消除全局 operationId 重复,应另开变更,同时在两个既有 Controller 上显式设置 operationId,并评估客户端兼容性与迁移方案。

W3-I2:401 运行时与文档契约

关闭状态

本次要求范围内的 finding 已关闭。

  • 运行时实现仍由全局 Security 入口返回:
    • code=401
    • message="not authenticated"
    • timestamp=""
    • 不包含 requestId
    • 不包含 data
  • SkillCloudControllerTest.anonymousRequestUsesSecurityEntryPointContract 对三个接口执行上述字段级断言,并额外断言响应字段集合恰好为 code/message/timestamp。
  • SkillCloudAuthorizationIntegrationTest.anonymousAndInvalidJwtUseSecurityEntryPointContract 同时覆盖匿名请求和 Bearer invalid-token。
  • docs/skill-cloud-api.md 已明确区分 401 裸 JSON 与统一 ApiResponse,示例与运行时一致。
  • 静态 OpenAPI 三个 Skill Cloud 401 响应均引用 UnauthorizedResponse,示例均为:
    • code=401
    • message="not authenticated"
    • timestamp=""
    • 无 requestId、无 data
  • docs/verify_openapi.py:173-185 精确校验上述静态 401 契约。

非阻断观察(Minor)

SkillCloudController.java:66、114、162 的 401 注解仍使用 @Schema(implementation = ApiResponse.class)。因此运行时 /v3/api-docs 的 401 schema 仍可能展示通用 ApiResponse,而静态 OpenAPI 已改为 UnauthorizedResponse。本次要求明确检查的是 Markdown 文档和静态 OpenAPI,且该问题不阻碍运行时行为或本 finding 的既定修复;如运行时 API 文档也被视为发布契约,应另行聚焦修正控制器注解并补充运行时 OpenAPI 断言。

独立验证结果

T2–T9 目标测试

命令:

$env:JAVA_HOME='D:\java\jdk'
& 'D:\maven\apache-maven-3.9.7\bin\mvn.cmd' '-Dtest=SkillTaxonomyMigrationTest,SkillCloudSeedDataIntegrationTest,SkillTaxonomyRepositoryTest,SkillCloudQueryServiceTest,SkillMatchServiceTest,SkillLearningPathServiceTest,SkillCloudControllerTest,SkillCloudAuthorizationIntegrationTest,SkillCloudEndToEndIntegrationTest' test

结果:

Tests run: 73, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Total time: 55.399 s

分类统计:

  • SkillTaxonomyMigrationTest:2
  • SkillCloudSeedDataIntegrationTest:8
  • SkillTaxonomyRepositoryTest:6
  • SkillCloudQueryServiceTest:8
  • SkillMatchServiceTest:16
  • SkillLearningPathServiceTest:10
  • SkillCloudControllerTest:15
  • SkillCloudAuthorizationIntegrationTest:3
  • SkillCloudEndToEndIntegrationTest:5

OpenAPI 静态校验

命令:

python docs\verify_openapi.py

结果:

paths: 129
All checks passed!

结论:静态校验通过,但该通过依赖于 N-I1 所描述的既有 operationId 修改,不能据此判定 W3 通过。

打包

命令:

$env:JAVA_HOME='D:\java\jdk'
& 'D:\maven\apache-maven-3.9.7\bin\mvn.cmd' -DskipTests package

结果:

BUILD SUCCESS

完整 mvn test 项目级回归

命令:

$env:JAVA_HOME='D:\java\jdk'
& 'D:\maven\apache-maven-3.9.7\bin\mvn.cmd' test

结果:

Tests run: 1395, Failures: 2, Errors: 9, Skipped: 0
BUILD FAILURE

所有 Skill Cloud 目标测试在全量套件中通过;失败仍集中在既有或环境相关测试:

  • CareerProgressServiceTest.fullAggregation_returnsCorrectSummaries:时间依赖失败。
  • JobReviewDimensionControllerTest.listReviews_shouldReturnDimensionScores:旧 Mock 签名导致 500。
  • JobReviewDimensionServiceTest.listReviews_shouldReturnDimensionScoresWithoutN1:旧 Repository stub 导致 NPE。
  • LocalResumeStorageServiceTest:Windows JUnit 临时目录 AccessDeniedException,8 个错误。

因此不能声称完整 mvn test 通过。上述 2 failures + 9 errors 仍是项目级 blocker,未形成正式豁免前不能关闭变更或进入 TO-11。

剩余阻断项

  1. N-I1(Important):恢复既有 cancel operationId,并调整校验脚本,使唯一性检查只拦截新增冲突,不以修改历史契约为代价。
  2. 项目级验证 blocker:完整 mvn test 仍有 2 failures + 9 errors,需修复或正式豁免。
  3. Minor:运行时 /v3/api-docs 的 401 schema 仍可能需要从通用 ApiResponse 切换为 UnauthorizedResponse,以避免静态/运行时 OpenAPI 漂移。