# W1-T3 独立复审报告(聚焦修复) ## 状态 完成。仅读取实现、契约、来源数据与本地 O*NET CSV,并独立执行测试和来源审计;未修改任何实现文件,仅写入本报告。 ## Verdict **FAIL** 第一轮 Critical 已关闭,I-1、I-2 的当前数据问题已关闭;I-3 的“逐条可追溯数据”已关闭,但对应的回归测试仍未关闭:当前测试只精确断言 5/47 条 O*NET 技能来源和 10/137 条非空 Importance,且没有任何 CSV 驱动的来源完整性测试。多数不存在或伪造的 O*NET 行、错误 Importance 仍会通过测试。该项属于 Important,阻断 T4。 ## 评审对象与依据 实现文件: - `D:\1\zhi\zhilai\mydreamjob-server\src\main\resources\db\migration\V35__skill_cloud_taxonomy.sql` - `D:\1\zhi\zhilai\mydreamjob-server\src\main\resources\db\migration\V36__skill_cloud_seed.sql` - `D:\1\zhi\zhilai\mydreamjob-server\src\test\java\com\mydreamjob\skill\SkillTaxonomyMigrationTest.java` - `D:\1\zhi\zhilai\mydreamjob-server\src\test\java\com\mydreamjob\skill\SkillCloudSeedDataIntegrationTest.java` 依据: - 修订后的 `execution-contract.md`、`design.md`、`tasks.md` - `changes/n03-skill-cloud/data/source-manifest.md` - `docs/skill-taxonomy-sources.md` - 第一轮报告 `changes/n03-skill-cloud/.superpowers/sdd/reviews/W1-T3.md` - 修复报告日志 `mydreamjob-server/target/skill-taxonomy-fix-green.log` - 本地 O*NET 31.0 CSV 与 `changes/n03-skill-cloud/data/esco-skill-lookup.json` - ESCO 官方只读 API(用于职位 URI 真实性核验) ## 独立测试结果 环境: - `JAVA_HOME=D:\java\jdk` - Maven:`D:\maven\apache-maven-3.9.7\bin\mvn.cmd` - 工作目录:`D:\1\zhi\zhilai\mydreamjob-server` 执行: ```powershell $env:JAVA_HOME='D:\java\jdk' & 'D:\maven\apache-maven-3.9.7\bin\mvn.cmd' '-Dtest=SkillTaxonomyMigrationTest,SkillCloudSeedDataIntegrationTest' test ``` 结果: ```text SkillCloudSeedDataIntegrationTest: Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 SkillTaxonomyMigrationTest: Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 Total: Tests run: 8, Failures: 0, Errors: 0, Skipped: 0 BUILD SUCCESS Total time: 40.195 s ``` ## 第一轮 Finding 关闭状态 | 第一轮 Finding | 状态 | 独立证据 | | --- | --- | --- | | C-1:混合来源未授权,职位与关系来源被替换 | **关闭** | `execution-contract.md:7,20,56` 已明确授权“ESCO 主来源 + O*NET `software_skills` 补充”;`design.md:32-43` 与 `source-manifest.md:35-43` 同步;V36 中 10 个职位均使用 ESCO occupation URI,25 条 ESCO 技能和 47 条 O*NET 补充技能分源导入。 | | I-1:金融/风控/教育产品经理代理映射不明确或 URI 不真实 | **关闭** | V36:6-28 明确代理 SOC;V35:93-96 将目标来源与 Importance 来源拆列;V36:274-413 的 137 条非空热度均设置 `importance_is_proxy=1`。独立调用 ESCO 官方 API,10 个职位行对应的 8 个唯一 URI 全部返回 200,标题分别为 web developer、software developer、software tester、financial analyst、risk manager、ICT product manager、instructional designer、data analyst。 | | I-2:manifest 分类遗漏,测试只要求至少一个分类 | **当前数据关闭** | manifest 10 个职位的分类清单与 V36:59-127 的实际 68 个分类逐项一致,测试也已改为精确比较完整清单;独立解析确认 68/68 分类至少关联 1 条技能。剩余测试弱点见 Minor-1。 | | I-3:Importance 缺少逐技能来源映射和有效验证 | **部分关闭,仍为 Importance 阻断** | V35:94-110 已增加 SOC、Element ID、代理标记和完整性约束;V36:274-413 的 137/137 条非空热度均带完整字段,并可精确核对 CSV。但测试只覆盖少量样本,不能阻止多数来源或热度被篡改;详见 Important-1。 | ## 来源审计方法与数量 ### 1. SQL 结构审计 独立解析 V36 的 `INSERT` 行,结果: | 对象 | 数量 | | --- | ---: | | 来源版本 | 2 | | 行业 | 3 | | 职位 | 10 | | 技能分类 | 68 | | 技能 | 72(ESCO 25,O*NET 47) | | 技能别名 | 72 | | 职位技能关系 | 139 | | 非空 Importance | 137 | | 空 Importance | 2 | | 每个职位非空 Importance 最小值 | 12 | V36 仅有 7 条 `INSERT` 语句,没有 `CREATE`、`ALTER`、`DROP`、`UPDATE`、`DELETE`。`com.mydreamjob.skill` 主代码包不存在,未提前实现 T4;V1-V34 没有改动。 ### 2. ESCO 来源审计 - 25/25 条 `source_type='ESCO'` 技能的 URI 都能在 `esco-skill-lookup.json` 中找到。 - 10/10 个职位行的 `source_version_id=1`,职位来源均为 ESCO occupation URI。 - 10 个职位使用 8 个唯一 ESCO occupation URI;`BACKEND_DEVELOPER`、`DEVOPS_ENGINEER`、`QUANTITATIVE_DEVELOPER` 复用 software developer URI,V36:47 已明确标注为项目代理。 - 对 8 个唯一 URI 独立调用 `https://ec.europa.eu/esco/api/resource/occupation?uri=...&language=en`,全部 HTTP 200,返回的 URI 与请求一致。 ### 3. O*NET `software_skills` 审计 - 使用本地 `mydreamjob-server/target/onet-31/software_skills.csv`(31,821 行)。 - 47/47 条 O*NET 技能的 `(O*NET-SOC Code, Workplace Example, Element ID)` 三元组精确命中 CSV,无缺失或伪造组合。 - 当前测试对这 47 条来源只有正则格式检查,另精确断言的来源样本为 5 条。 ### 4. Importance 审计 - 使用本地 `work_activities.csv`、`knowledge.csv`、`essential_skills.csv`、`transferable_skills.csv`,共解析出 99,231 个 `(SOC, Element ID, Data Value)` 的 `IM/Importance` 键。 - 137/137 条非空 Importance 均可按 `(importance_source_code, importance_element_id, importance)` 精确命中至少一个 CSV。 - 137/137 条均满足 `importance_source_code` 和 `importance_element_id` 非空,且 `importance_is_proxy=1`。 - 2/2 条空 Importance 的 SOC、Element ID 均为 NULL,`importance_is_proxy=0`。 - 当前测试对 137 条非空热度中的 10 条做精确值断言,其余 127 条只检查字段存在,不检查数值是否真实。 ## 阻断项 ### Important-1:回归测试不能覆盖大多数 O*NET 来源与 Importance 篡改 **位置** - `SkillCloudSeedDataIntegrationTest.java:132-139`:47 条 O*NET 来源只验证正则格式。 - `SkillCloudSeedDataIntegrationTest.java:141-145`:仅精确断言 5 条 O*NET `software_skills` 行。 - `SkillCloudSeedDataIntegrationTest.java:152-163`:只验证非空字段是否存在及来源版本名称是否为 O*NET。 - `SkillCloudSeedDataIntegrationTest.java:165-187`:仅精确断言 10 条 Importance 及 2 条 NULL。 **独立量化** - O*NET 技能总数为 47,精确来源断言为 5,剩余 42 条不存在“CSV 行必须存在”的回归保护。 - 非空 Importance 总数为 137,精确值断言为 10,剩余 127 条即使被改成任意 0-5 的数值,现有测试仍会通过。 - 测试文件未读取 `software_skills.csv`、`work_activities.csv`、`knowledge.csv`、`essential_skills.csv` 或 `transferable_skills.csv`,因此无法证明“当前值来自 O*NET 31.0 CSV”。 **影响** 当前数据库中的 47/47 技能来源和 137/137 Importance 已由本次复审全量核对为真实;但数据正确性只存在于当前 SQL 快照,没有被自动化测试保护。未来修改若把未抽样的来源替换为格式合法但不存在的三件套,或把未抽样的 Importance 改成错误值,测试仍会通过,随后直接影响词云排序和匹配结果。 **修复方向** - 增加覆盖全部 47 条 O*NET 技能来源的精确来源清单或 CSV 驱动断言。 - 增加覆盖全部 137 条非空 Importance 的精确映射断言;若 CSV 不进入正常测试运行环境,至少提交一份受版本控制的完整映射基线,并校验行数、键集合和值。 - 对 137/137 条映射逐项验证 `SOC + Element ID + Data Value`,而不是只验证非空和应用层来源版本。 ## 未决问题 ### Minor-1:每个分类至少关联一个技能未进入断言 `SkillCloudSeedDataIntegrationTest.java:89-113` 验证完整分类清单,但只对职位的技能总数和非空热度总数要求 `>= 10`,没有验证每个分类的关联技能数 `>= 1`。当前 68/68 分类均通过独立数据审计,因此不阻断;后续若新增或删改分类,建议补一条分组断言。 ### Minor-2:Importance 越界值测试仍缺失 V35:102-104 定义了 0-5 的 CHECK,但 T3 测试覆盖的是 provenance 缺失、代理标记非法和成功带来源更新,没有直接断言 `importance < 0` 或 `> 5` 在 H2 `MODE=MySQL` 下失败。MySQL 8.4 会执行 CHECK,当前没有发现生产不可兼容语法,但真实 MySQL 尚未在本次环境中执行。 ### Minor-3:执行计划中的契约哈希未同步修订版 当前 `execution-contract.md` 的 SHA-256 为 `98d869bc3b7e29b6fefffd973e561be50ba21ef4f59f4146ccd47cf8164957da`,与 `.spec-superflow.yaml` 一致;但 `.superpowers/sdd/execution-plan.yaml` 仍记录旧哈希 `9ae4be4a8561d7f303804c84d75061bbf2c8b3be2e7c79495689c19ba09d028e`。不影响 T3 数据正确性,建议在 W1 复评通过后同步执行计划。 ## 未阻断的确认项 - V35 的新增列、provenance CHECK、代理标记 CHECK 在 H2 `MODE=MySQL` 下通过测试。 - `importance_source_code`、`importance_element_id` 的字段长度足以容纳当前 O*NET SOC 和 Element ID。 - V36 保持纯数据迁移,未提前引入 T4 Java 业务代码。 - 未修改 V1-V34。 ## 阻断项汇总 T3 当前不通过。第一轮 C-1、I-1、I-2 的阻断已关闭,I-3 的当前数据已清除,但对应的自动化回归保护仍不足,必须补齐 Important-1 后才能交给 T4。