# W1-T2 独立评审报告 ## 状态 完成。本次评审未修改任何实现文件,仅写入本报告。 ## Verdict **PASS** T2 已建立执行契约要求的七张词库表、关键字段、外键、唯一约束、CHECK 约束和两个查询索引;迁移可执行,且未顺带实现 T3 种子数据或 Java 业务代码。未发现阻断 T3 的 Critical 或 Important finding。 ## 评审对象与依据 评审对象: - `D:\1\zhi\zhilai\mydreamjob-server\src\main\resources\db\migration\V35__skill_cloud_taxonomy.sql` - `D:\1\zhi\zhilai\mydreamjob-server\src\test\java\com\mydreamjob\skill\SkillTaxonomyMigrationTest.java` 对照依据: - `D:\1\zhi\zhilai\changes\n03-skill-cloud\execution-contract.md` - `D:\1\zhi\zhilai\changes\n03-skill-cloud\design.md` - `D:\1\zhi\zhilai\changes\n03-skill-cloud\tasks.md` - T2 RED/GREEN 日志 - `git diff --cached`、`git diff HEAD` 和 `git diff --check` - JDK 17 下的独立测试执行结果 ## 独立检查结果 1. **七张表及关键列存在。** V35 第 5、17、28、44、60、77、88 行分别创建 `skill_source_versions`、`skill_industries`、`skill_occupations`、`skill_categories`、`skills`、`skill_aliases`、`occupation_skills`。测试通过真实 `DatabaseMetaData` 查询七个表的全部预期列,见测试第 55-74、223-240 行,不是 SQL 文本断言。 2. **外键真实存在。** V35 第 40-41、57、74、85、105-108 行建立行业、来源版本、职位、分类、技能和别名之间的 9 条外键;测试第 86-94 行通过 `getImportedKeys` 逐条验证。 3. **唯一约束真实存在。** V35 第 14、25、39、53、71-72、83-84、98 行覆盖来源版本、行业编码、行业内职位编码、职位内分类编码、技能编码、技能来源、别名归一化值、技能别名和职位技能关系;测试第 76-84 行逐项验证唯一索引。 4. **CHECK 约束符合契约。** 分类模板限定为 `PROGRAMMING_LANGUAGE`、`FRAMEWORK`、`TOOL`、`GENERAL`,见 V35 第 54-56 行;技能来源限定为 `ESCO`、`O*NET`、`PROJECT`,见第 73 行;关系类型限定为 `ESSENTIAL`、`OPTIONAL`、`PROJECT`,见第 102-104 行。非法模板、非法来源和非法关系类型均通过实际失败插入验证,见测试第 159-169、182-186 行。 5. **`importance` 可空且无默认权重。** V35 第 93 行定义 `DECIMAL(4,2)` 且没有 `NOT NULL` 或 `DEFAULT`;第 99-101 行只约束为空或位于 0.00-5.00。测试插入时省略该列并断言查询结果为 `null`,随后验证 `4.25` 可保存,见测试第 133-153 行。 6. **中文名称非空。** 行业、职位、分类和技能的中文名称均定义为 `NOT NULL`,见 V35 第 20、32、48、63 行;测试第 176-181 行通过插入 `name_zh=null` 并断言失败。 7. **两个查询索引真实存在。** V35 第 109-110 行建立 `(occupation_id, category_id)` 与 `(occupation_id, importance)` 索引;测试第 96-97 行通过数据库元数据验证。`occupation_id + importance` 可被 MySQL 正向或反向扫描用于热度降序查询。 8. **迁移范围正确。** `git diff --name-status HEAD` 在迁移和主代码范围内仅显示新增 `V35__skill_cloud_taxonomy.sql` 及新测试文件;V1-V34 未修改,V36 尚不存在,`src/main/java` 无变更,未顺带实现 T3 或 Java 业务代码。 9. **测试失败有效性、隔离和清理。** RED 日志第 60-125 行显示 V35 缺失时两项测试分别因缺表失败;测试使用独立的 `integrationdb_skill_taxonomy` H2 数据库,见第 32-33 行;`@AfterEach` 按外键逆序清理插入数据,见第 196-221 行。未发现仅源码文本断言、共享默认 H2 库污染或明显漏清理。 10. **MySQL/H2 兼容性。** `AUTO_INCREMENT`、InnoDB、`utf8mb4_unicode_ci`、`DATETIME DEFAULT/ON UPDATE CURRENT_TIMESTAMP`、表内 `KEY`、CHECK 和命名外键均属于 MySQL 8.4 支持的语法;H2 在 `MODE=MySQL` 下已成功执行整份迁移。未发现仅 H2 成立的 DDL 结构。由于本机没有 Docker,且本地 MySQL 服务无可用测试凭据,本报告未进行真实 MySQL 样库执行;该验证限制不阻断仅要求 H2 迁移测试的 T2。 ## 独立测试结果 执行环境与命令: ```powershell $env:JAVA_HOME='D:\java\jdk' & 'D:\maven\apache-maven-3.9.7\bin\mvn.cmd' -Dtest=SkillTaxonomyMigrationTest test ``` 结果: ```text Java version: 17.0.16 Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 BUILD SUCCESS Total time: 36.770 s ``` 提供的 GREEN 日志与独立执行结果一致:JDK 17.0.16、2 项测试全部通过、`BUILD SUCCESS`。RED 日志也证明测试确实依赖真实 V35 迁移结果。 ## Findings ### Critical 无。 ### Important 无。 ### Minor 1. **迁移测试只断言列存在,不直接断言全部列类型和可空性。** 测试第 223-240 行收集的是列名;当前 DDL 的类型和可空性经人工核对符合 design/契约,因此不阻断,但未来类型回归不会全部被测试发现。建议后续在数据库元数据断言中补充 `importance DECIMAL(4,2) nullable`、各 `name_zh NOT NULL` 及关键 ID 列类型检查。 2. **`importance` 的越界分支未行为测试。** 测试覆盖了 `null` 和 `4.25`,但未尝试 `-0.01` 或 `5.01`,因此当前 CHECK 上下界只经人工核对,见 V35 第 99-101 行。风险较低,可在 T3 或端到端回归中补充。 3. **约束失败断言捕获所有 `DataAccessException`,未锁定具体约束。** 测试第 330-332 行通过这一点;当前各失败用例的其余字段均合法,因此实际原因基本可确定,但测试信息量和诊断精度略低。建议后续断言约束名或 SQL 状态/错误码,进一步防止因无关错误而误通过。 4. **测试文件末尾存在多余空白行,`git diff --check` 报告 `new blank line at EOF`。** 证据为测试文件第 334 行。纯格式问题,不阻断 T3。 ## 未决问题 - 本报告仅在 H2 `MODE=MySQL` 下实际执行了迁移;真实 MySQL 8.4 执行应在已有 MySQL 凭据或 Docker 环境中由后续发布级验证补充。静态检查未发现 MySQL 不兼容语法。 - 分类必须属于职位属于服务层校验责任,T2 只提供基础外键;该跨列一致性须在 T4/T8 按 design 第 117、170 行落实并验证。 ## 阻断项 无。