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.
 
 
 

9.5 KiB

W1-T3 独立复审报告(聚焦修复)

状态

完成。仅读取实现、契约、来源数据与本地 O*NET CSV,并独立执行测试和来源审计;未修改任何实现文件,仅写入本报告。

Verdict

FAIL

第一轮 Critical 已关闭,I-1、I-2 的当前数据问题已关闭;I-3 的“逐条可追溯数据”已关闭,但对应的回归测试仍未关闭:当前测试只精确断言 5/47 条 ONET 技能来源和 10/137 条非空 Importance,且没有任何 CSV 驱动的来源完整性测试。多数不存在或伪造的 ONET 行、错误 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

执行:

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

结果:

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 主来源 + ONET software_skills 补充”;design.md:32-43 与 source-manifest.md:35-43 同步;V36 中 10 个职位均使用 ESCO occupation URI,25 条 ESCO 技能和 47 条 ONET 补充技能分源导入。
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。