diff --git a/cloud/skills/software-engineering/SKILL.md b/cloud/skills/software-engineering/SKILL.md index d73179b..fd493f0 100644 --- a/cloud/skills/software-engineering/SKILL.md +++ b/cloud/skills/software-engineering/SKILL.md @@ -640,6 +640,100 @@ tests/ # QA 线程专属,含跨端一致性用例 - 路线选择(web + PWA / WebView 壳,iOS / Android 原生后置)必须在 G0 由用户定,不能由某个客户端线程中途自己改路线、自己把原生端加回 MVP。 +## 跨任务产物传递(artifact pass) + +问题:任务 worktree 互相隔离,回归任务默认拿不到核心任务的代码。 +此前回归只能按契约自己写一套独立 fixture 测试来“猜”契约, +这种回归绝不能声称“重跑了核心代码”。本节是唯一的补救机制: +核心产物作为显式产物,经协调员复核后传给回归,回归跑同一份代码。 + +### 产物清单(manifest) + +核心任务交付时必须同时写出产物清单文件,例如 +`artifacts/ARTIFACT_MANIFEST.json`,格式只含下列字段, +不含任何密钥、口令、token: + +``` +{ + "artifact_version": "1", + "source_task_id": "<核心任务 id 全文,协调员记录>", + "source_project_id": "<核心任务项目 id 全文>", + "contract_version": "<契约版本,例如 v1.1>", + "files": [ + {"path": "shared/todo_v11.py", "sha256": "<64 位小写 hex>", "bytes": 4811}, + {"path": "tests/test_todo_v11.py", "sha256": "<64 位小写 hex>", "bytes": 2417} + ] +} +``` + +清单里的 hash 必须由核心任务用 `sha256sum` 实测算出, +不许手写、不许照抄上一轮、不许用文件名代替 hash。 +`tests/TEST_RUN.txt` 必须是真实跑测试的输出,不许手写。 + +### 协调员传递前三方核对(缺一不可) + +协调员在清理核心任务租户之前,必须先把核心产物取出来, +否则清理后产物不可恢复,回归无物可跑。取出来后独立重算: + +1. 核心任务结尾报告里报的 hash; +2. 产物清单文件里的 hash; +3. 协调员自己对取出的文件重算的 hash。 + +三处全对上才算“已核验产物”,协调员才能往下传。 +任一处对不上就停:不传、不派生回归、不接受核心交付, +先查是取错文件、写错清单还是核心任务本身算错,修好后 +重新走一遍三方核对。协调员绝不把未经核验的 hash 塞进回归提示词。 + +### 回归任务双通道核对(先核对,再跑测试) + +协调员派生回归时,必须双通道给齐,缺一通道不派生: + +- 通道一(提示词清单):回归提示词里贴出已核验的产物清单全文 + (每个文件路径、sha256、字节数)。 +- 通道二(文件产物):回归提示词里贴出核心文件的完整原文, + 回归任务按原文原样写盘到相同路径(含产物清单文件本身), + 写盘后自己跑 `sha256sum` 重算,再与通道一的清单逐项比对。 + +回归任务的第 0 步永远是核对,不是跑测试: + +- 全对上:才能跑测试,并在结尾写 `ARTIFACT-VERIFY` 一节, + 列出每个文件的期望 hash、实测 hash、是否一致,最后写 + `ARTIFACT-VERIFY-OK`。 +- 任一文件对不上:立刻停下来,结尾只报 + `ARTIFACT-HASH-MISMATCH`,不跑测试、不写自己的 fixture、 + 不猜契约、不把失败写成通过。协调员收到不匹配报告后, + 不接受该回归的任何测试结论,重新传递或重新跑核心任务。 + +### 回归跑同一份代码的硬规则 + +- 回归直接跑核心代码与核心测试原样,例如 + `python3 -m unittest discover -s tests -v`,输出如实记入 + `tests/TEST_RUN.txt`,不许手写。 +- 回归如需补测,只能新增“import 核心模块”的测试, + 绝不复制核心实现、绝不写一套功能等价的 fixture 来冒充核心代码。 + 补测失败是缺陷,不是让回归顺手改核心代码的理由。 +- 回归任务只读核心产物文件:不改核心代码、不改核心测试、 + 不改契约版本、不加新功能。核心代码有缺陷时,缺陷回核心线程修, + 修完产生新的产物清单版本(artifact_version 加一、hash 全变), + 旧核验立即作废,协调员与回归必须按新清单重新走三方核对 + 与双通道核对,不得沿用旧 hash 冒充新代码已回归。 +- 产物传递不改变验收规则:回归通过不等于用户验收通过, + 验收仍由用户逐项确认;产物传递也不改变清理规则, + 清理仍按精确 id 逐项核对,绝不按名字前缀删。 + +### 协调员回归提示词模板(必填字段) + +回归提示词除“协调员派生子任务的必填字段”外,必须再含: + +1. 已核验产物清单全文(通道一)。 +2. 核心文件完整原文(通道二),并写明“先原样写盘、算 hash、 + 对不上就停,不要硬跑”。 +3. 核心任务 id 与项目 id 前缀(供复核,不供猜测)。 +4. 回归范围:只跑清单里的核心代码与测试,不加新功能、 + 不重写 fixture、不改核心文件。 +5. 结尾必填 `ARTIFACT-VERIFY` 一节与 `ARTIFACT-VERIFY-OK` + 或 `ARTIFACT-HASH-MISMATCH` 其中之一,缺这节视为交付不完整。 + ## 校验(协调员每过一个门禁自查一次) - 每个子任务提示词里有没有角色模板全文、拥有目录、分支名、完成定义、TODO-UPDATE 要求? @@ -673,6 +767,10 @@ tests/ # QA 线程专属,含跨端一致性用例 PostgreSQL、Drizzle 或 Prisma 二选一、Vitest),G2 冻结后有没有 未经用户特别要求就换语言?iOS / Android 是不是仍写成后置占位, 未编译 / 未验证有没有标注为未发布? +- 跨任务产物传递走了吗?核心产物清理前取出了吗?三方核对全对上了吗? + 回归提示词里产物清单与文件原文双通道齐了吗?回归结尾有 + ARTIFACT-VERIFY 一节与 ARTIFACT-VERIFY-OK 吗?回归是跑同一份 + 核心代码,还是自己写 fixture 猜契约? 有一项为否,就停在当前门禁,不进入下一阶段。 ## 附录:角色模板(播种随附版) @@ -806,6 +904,20 @@ full-auto-executor + installation id。质量门禁全部自动且阻塞合并 一条决策写清日期、议题、决定、理由、影响端;推翻旧决策追加新条 写明“取代 D-n”,绝不改旧条原文、不删旧条。 +## 跨任务产物传递(协调员) + +- 回归任务拿不到核心代码时,绝不让回归自己写 fixture 猜契约: + 走技能正文“跨任务产物传递”一节。 +- 清理核心租户前先取出核心产物(代码、测试、产物清单 + `artifacts/ARTIFACT_MANIFEST.json`), + 独立重算 sha256,与核心报告、清单文件三方核对,全对上才传。 +- 派生回归时双通道给齐:提示词里贴已核验产物清单全文, + 再贴核心文件完整原文,令回归先原样写盘、算 hash、对不上就停。 +- 回归结尾没有 ARTIFACT-VERIFY 一节、没有 ARTIFACT-VERIFY-OK, + 或报了 ARTIFACT-HASH-MISMATCH,结论一律不接受,重新传递或重跑核心。 +- 核心修完缺陷出新产物时,旧核验作废,按新清单重新走三方核对 + 与双通道核对,不得沿用旧 hash。 + ## 失败处理 - 有进度的中断任务:断点续跑。 @@ -1148,6 +1260,12 @@ agent 类产品还要参与 G3.5 可行性 spike:任务能创建、能跑出 5. 缺陷清单:每个缺陷写清复现步骤、影响客户端、严重程度、归属线程。 6. 回归清单:契约从 v1 升到 v2 时,哪些用例必须重跑;G5 缺陷修完回 G5 回归, 回归范围按契约变更影响面定,不是每次都全量重测。 +7. 跨任务产物传递:回归第 0 步永远是核对,不是跑测试。 + 按协调员给的已核验产物清单与文件原文原样写盘,跑 `sha256sum` + 逐项比对;全对上写 ARTIFACT-VERIFY-OK 才能跑同一份核心代码 + 与核心测试;任一文件对不上就停,报 ARTIFACT-HASH-MISMATCH, + 不跑测试、不写 fixture、不猜契约。补测只能 import 核心模块, + 不能复制核心实现,不能写功能等价的 fixture 冒充核心代码。 ## 未编译端的口径 @@ -1166,6 +1284,7 @@ iOS / Android 原生后置占位不进 QA 通过表,标注“未编译 / 未 - 不替开发线程改代码“顺手修掉”,修了就测不出原缺陷。 - 不把“没测”写成“通过”。没测的端和用例要单独列出。 +- 不在 hash 未核对通过时跑测试,不用自己写的 fixture 冒充核心代码。 --- diff --git a/cloud/tests/test_software_engineering_artifactpass.py b/cloud/tests/test_software_engineering_artifactpass.py new file mode 100644 index 0000000..9f9d0a6 --- /dev/null +++ b/cloud/tests/test_software_engineering_artifactpass.py @@ -0,0 +1,37 @@ +"""software-engineering 技能的跨任务产物传递:轻量关键词断言。 + +只断言正文与附录都含有产物传递的关键概念,不逐字背诵全文: +产物清单文件名、sha256sum 实测、hash 不一致就停、核对通过标记、 +回归跑同一份代码而非自己写 fixture 猜契约。正文改了附录没同步时, +本测试在附录部分就会失败(与 GitHub 保证测试同款口径)。 +""" + +import unittest +from pathlib import Path + +SKILL = Path(__file__).resolve().parents[1] / "skills" / "software-engineering" / "SKILL.md" + +KEYWORDS = ("跨任务产物传递", "ARTIFACT_MANIFEST", + "sha256sum", "ARTIFACT-VERIFY-OK", + "ARTIFACT-HASH-MISMATCH", "三方核对", + "双通道", "fixture") + + +class SoftwareEngineeringArtifactPassTestCase(unittest.TestCase): + def test_artifact_pass_in_body_and_appendix(self): + text = SKILL.read_text(encoding="utf-8") + main, sep, appendix = text.partition("## 附录:角色模板") + self.assertTrue(sep, "appendix marker missing") + for kw in KEYWORDS: + self.assertIn(kw, main, kw) + self.assertIn(kw, appendix, "appendix: " + kw) + + def test_artifact_pass_forbids_fixture_substitution(self): + text = SKILL.read_text(encoding="utf-8") + main = text.partition("## 附录:角色模板")[0] + self.assertIn("绝不复制核心实现", main) + self.assertIn("跑同一份", main) + + +if __name__ == "__main__": + unittest.main()