10 KiB
W1-T3 独立评审报告
状态
完成。本次评审只读取实现、来源数据、契约和日志,并独立执行测试;未修改任何实现文件,仅写入本报告。
Verdict
FAIL
存在 1 项 Critical 和 3 项 Important。当前 V36 虽然能在 H2 下通过既有测试,但没有落实已批准的“ESCO 负责职位—技能—分类主关系”方案,且部分金融职位使用与目标职位不符的 O*NET SOC 替代来源;同时 T1 清单中的多个技能分类没有导入。上述问题均阻断 T4。
评审对象与依据
评审对象:
D:\1\zhi\zhilai\mydreamjob-server\src\main\resources\db\migration\V36__skill_cloud_seed.sqlD:\1\zhi\zhilai\mydreamjob-server\src\test\java\com\mydreamjob\skill\SkillCloudSeedDataIntegrationTest.java
对照依据:
changes/n03-skill-cloud/execution-contract.mdchanges/n03-skill-cloud/design.mdchanges/n03-skill-cloud/tasks.mdchanges/n03-skill-cloud/data/source-manifest.mddocs/skill-taxonomy-sources.mdV35__skill_cloud_taxonomy.sql- 本地 ESCO lookup、O*NET 31.0 CSV、实现者 RED/GREEN 日志
独立检查结果
1. 数量与基本约束
独立解析和 H2 测试结果一致:
| 项目 | 结果 |
|---|---|
| 行业 | 3 |
| 职位 | 10 |
| 技能分类 | 50 |
| 技能 | 53 |
| 技能别名 | 53 |
| 职位技能关系 | 137 |
| 非空 Importance | 133 |
| 空 Importance | 4 |
每个职位均有 10 至 17 条职位技能关系,非空 Importance 数量均不少于 10。全部技能有中文标准名、非空 source_code 和至少一个别名;normalized_alias 无重复。当前 137 条关系的 category_id 均与同一 occupation_id 对应,未发现现有种子内的跨职位分类错配。
2. ESCO 与 O*NET 来源核验
- V36 的 25 个
source_type='ESCO'URI 均可从changes/n03-skill-cloud/data/esco-skill-lookup.json找到,英文标题与 lookup 一致。 - V36 的 28 个 O*NET 技能来源三元组
O*NET-SOC|Workplace Example|Element ID均能在software_skills.csv精确命中;未发现伪造组合。 - V36 注释声明的 43 组(SOC、Importance、语义元素)映射值均能在本地 O*NET CSV 中命中。其中
Scikit-learn的当前工作区值已按 CSV 精确大小写修复。 - lookup 中本身存在明显误匹配,例如 Angular→computer programming、Spring Boot→install deicing boot、Node.js→apply electrolytes to cathodes and anodes、React→react to emergency situations in a live performance environment、Redis→redistribute wagered money、Microsoft Power BI→Microsoft Access。当前 V36 没有使用这些错误 URI,因此它们不是本批次已导入数据的直接错误,但该 lookup 不能作为未经复核的可信自动映射源。
3. 独立测试
执行命令:
$env:JAVA_HOME='D:\java\jdk'
& 'D:\maven\apache-maven-3.9.7\bin\mvn.cmd' '-Dtest=SkillTaxonomyMigrationTest,SkillCloudSeedDataIntegrationTest' test
结果:
SkillCloudSeedDataIntegrationTest: Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
SkillTaxonomyMigrationTest: Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
Total: Tests run: 7, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
该结果与实现者 GREEN 日志一致。
Findings
Critical
C-1:V36 用 O*NET/项目映射替代了已批准的 ESCO 职位—技能—分类主关系
证据:
- 执行契约第 55 行要求“使用 ESCO 作为职位—技能—分类主关系,O*NET Importance 作为 heat”。
- 设计 D1 第 32-42 行同样规定 ESCO 负责职位—技能—分类关系;来源清单第 34-39、51、60-63 行要求保留原上游来源 ID,并由项目维护跨源重要性映射。
- V35 第 34 行将
skill_occupations.source_code定义为ESCO 职位来源 ID。 - V36 第 30-39 行将 10 个职位的
source_code全部写成 ONET SOC,并将source_version_id指向 ONET 来源版本。 - V36 第 203-340 行 137 条职位技能关系的
source_version_id全部为 O*NET。 - 本地只有 ESCO 技能 lookup,没有 ESCO 职位—技能关系数据;V36 已导入的 25 个 ESCO 技能只提供了技能 URI,未提供任何 ESCO 职业关系。
影响:这不是字段命名的小问题,而是数据治理来源发生实质变化:职位节点被标成 ONET SOC,职位技能关系改由 ONET software_skills、项目分类和代理 Importance 人工组装。下游接口即使运行正确,也无法证明返回的是契约批准的 ESCO 主关系。该变化命中执行契约第 136 行的 Rewind 条件“数据来源发生实质变化”。
Important
I-1:两个金融职位使用不能代表目标职位的替代 SOC,且替代映射未获批准或写入来源清单
证据:
- V36 第 34 行将“金融数据分析师”写成
13-2031.00。本地occupation_data.csv中该 SOC 的标题是 Budget Analysts;原计划目标13-2051.00是 Financial and Investment Analysts。 - V36 第 35 行将“风控建模工程师”写成
13-2053.00。本地 CSV 中该 SOC 的标题是 Insurance Underwriters;原计划目标13-2054.00是 Financial Risk Specialists。 - V36 第 16-17 行仅以 SQL 注释说明替换;
source-manifest.md第 22-23 行没有批准代理 SOC,也没有记录替换后的目标语义。 13-2051.00和13-2054.00在本地四份 Importance CSV 中确实没有行,但“原目标无数据”不等于可以用语义不同的职业覆盖其来源 ID。
影响:Budget Analysts 与 Insurance Underwriters 的 O*NET 活动分布不能代表金融数据分析师和风控建模工程师。尤其是 Insurance Underwriters 作为风控建模工程师的热度来源,会导致技能热度与目标职位脱节。必须在来源清单和契约中明确代理规则与语义合理性,或重新选择可代表目标职位的来源;不能直接把替代 SOC 写入目标职位的 source_code。
I-2:T3 清单中的多个技能分类未落表,测试只要求至少一个分类因而漏检
证据:
source-manifest.md第 18-27 行给出了每个职位的首批技能分类范围,第 30 行明确这些分类是“每个职位首批应覆盖的能力域”。- V36 第 42-91 行为每个职位固定导入 5 个分类,共 50 个。
- 前端开发缺少清单中的“浏览器与调试”“测试”。
- DevOps 缺少“配置管理与 IaC”“可观测性”“安全”等独立能力域。
- 风控建模缺少“模型验证”等能力域。
- 教学设计师缺少“无障碍与规范”等能力域。
- 测试第 70-71 行只断言
category_count >= 1,因此即使只导入一个分类也会通过。
影响:已批准的 T3 分类覆盖范围没有完整交付,后续接口会缺少部分可筛选分类;当前测试无法阻止该类回归。
I-3:Importance 缺少逐技能来源映射和有效验证,现有数据大量依赖同值代理
证据:
- V36 第 5-15 行说明所有技术技能使用“Working with Computers”等职业活动代理值,而不是 O*NET software_skills 自身的 Importance。
- V36 第 203-340 行的 133 条非空关系实际只形成 39 个不同的
(occupation, importance)组合;多个技能共享同一代理值,例如同一职业内多数技术技能全部为同一个值。 - V35 第 93-95 行只保存
importance和source_version_id,没有保存用于推导热度的 O*NET Element ID;V36 的注释不是机器可追溯的数据。 - 测试第 106-127 行只精确校验前端 JavaScript 的
4.88和 Figma 的null,其余 132 条重要性记录或错误来源元素不会被发现。
影响:词云热度会因大量同值技能而主要退化为 nameZh ASC 排序,无法证明每个技能的热度确实来自对应 O*NET 来源。若继续该口径,应新增可追溯的 Importance 映射记录并扩大测试,或者重新定义可接受的代理规则和排序语义。
Minor
-
“45 个 Importance 原值”的核验数量不实。 V36 第 5-15 行声明了 43 个职业/能力域映射,133 条非空关系只有 39 个不同
(occupation, importance)组合;报告中“45 个 Importance 原值”没有可复现证据。这是核验报告计数问题,不代表已发现任意 CSV 伪造值。 -
最终提交可能漏掉 Scikit-learn 大小写修复。 当前工作区是
Scikit-learn,与 CSV 一致;但git status显示 V36 为AM,即该修复尚未 staged。提交前必须确保修正包含在最终 T3 提交中。 -
测试主要验证行数、非空值和两个单点值,不是完整来源契约测试。 当前即使将除 JavaScript 外的 Importance 改错、将非空 ESCO/O*NET source code 改成任意非空字符串,或只保留每个职位一个分类,测试仍可能通过。分类跨职位错配也不会被测试发现,因为数据库没有覆盖
(occupation_id, category_id)的复合外键。
已确认没有问题的部分
- V36 是纯数据迁移:只有 7 个
INSERT,未包含UPDATE/DELETE/DROP/ALTER/CREATE。 git diff HEAD在本任务实现范围内只显示 V36 和 T3 测试;V1-V35 未修改,src/main/java/com/mydreamjob/skill不存在,未提前实现 T4 业务代码。- 当前 137 条关系的技能分类均与所属 occupation 对应;所有技能、别名、来源版本和关系均满足 V35 现有外键及唯一约束。
- 28 个 ONET 技能来源组合和 25 个 ESCO URI 均可从本地来源文件核实,没有发现伪造 ONET software row 或伪造 ESCO URI。
未决问题
- 必须决定是恢复 ESCO 职位—技能—分类主关系,还是正式修改 design、source manifest 和执行契约,承认以 O*NET SOC 与项目映射作为主关系。后者属于数据来源实质变化,应走 Rewind。
- 必须确认“代理 Importance”是否属于已批准方案;若属于,需记录每个技能或能力域的 O*NET Element ID、代理理由和质量规则,并重新定义同值排序的产品语义。
- 若继续使用
13-2031.00和13-2053.00,需要提供可审查的职位语义映射依据并更新来源清单;否则应更换代表 SOC。 - 本机未进行真实 MySQL 迁移验证,仅验证 H2
MODE=MySQL。该限制沿用 T2 的未决项。
阻断项
T3 不通过。C-1、I-1、I-2、I-3 均必须在开始 T4 前处理;其中 C-1 和 I-1 优先触发规划/契约 Rewind 或获得明确的来源变更批准。既有 7 项测试通过不能覆盖这些来源和分类语义问题。