feat: software-engineering skill v0.3 (P1-1..P1-4 + P2)

- P1-1 directory-isolation executable check: git diff --name-only
  against merge-base, output recorded in merge record
- P1-2 derivation checklist table (8 required items, missing one blocks dispatch)
- P1-3 QA split into single-client review and cross-client E2E with
  fixed deliverables and agent-test attribution
- P1-4 sub-task slim-pack trimming rules (listed chapters only, never full copies)
- P2: inter-thread Q&A default policy, docs/decisions.md append-only,
  per-client onboarding docs (web first at G4a), v1.1 handover checklist
- Body and appendix kept in sync; new lightweight keyword test
This commit is contained in:
host committed 2026-11-03 02:48:54 +00:00
1 parent ef0052d15a
commit 34ed438d0e
2 files changed
+163 -27

No files matched your search

+119 -27
View File
@@ -5,8 +5,13 @@ description: 用户要从零做一款软件、尤其是要同时做 web、macOS
# software-engineering:多客户端软件工程编排 # software-engineering:多客户端软件工程编排
版本 v0.2,2026-10-30。v0.1 纸面推演找出的 5 个 P0 缺口已在本版修掉, 版本 v0.3,2026-10-30。上一版是 v0.2 + PR #193 GitHub 保证
见同目录 `CHANGELOG.md`。仍是草稿:未提 PR、未部署生产、未改任何生产代码。 (已合并、已部署生产)。v0.3 改了什么:P1-1 目录隔离自动化检查
(可执行命令 + 检查输出记入合并记录)、P1-2 派生占位符必填表
(缺一项就不发任务)、P1-3 QA 正式分单端复核与跨端 E2E 两部分
(各自交付物写死)、P1-4 子任务精简包裁剪规则(只给本端相关章节,
提示词里列出所含章节);P2:任务间问答默认策略、决策记录落盘
`docs/decisions.md`、每端上手文档、v1.1 交接清单。
装机路径见同目录 `README.md`:源码位置是 `cloud/skills/software-engineering/SKILL.md`, 装机路径见同目录 `README.md`:源码位置是 `cloud/skills/software-engineering/SKILL.md`,
播种后租户内位置是 `<codex-home>/skills/software-engineering/SKILL.md`。 播种后租户内位置是 `<codex-home>/skills/software-engineering/SKILL.md`。
@@ -155,12 +160,29 @@ G0 的六问缺一问,G0 就不算过。用户没回复时,协调员等,
不把“本地能跑”写成“已发布”。 不把“本地能跑”写成“已发布”。
7. 结尾必须带 TODO-UPDATE 小节(见“待办机制”),缺这节视为交付不完整。 7. 结尾必须带 TODO-UPDATE 小节(见“待办机制”),缺这节视为交付不完整。
派生前校验清单(协调员自查,漏填就停):客户端名填了吗? 派生前校验表(必填表,协调员必须把填好的表原样贴进派生提示词,
目录填了吗?分支填了吗?契约版本填了吗?PRD 版本填了吗? 不能只在心里过一遍;缺一项就不发任务):
完成定义填了吗?有一项没填就不发任务。
子任务上下文要精简:只给本端相关的契约章节和设计页, | 必填项 | 填什么 |
不要把 PRD、契约、设计全文复制给 5 个线程各一份。 |--------|--------|
| 客户端名 | 本客户端,例如 web / macOS / Windows / iOS / Android |
| 拥有目录 | 只能写这一个目录,例如 `apps/web` |
| 分支名 | `feat/swe/<阶段>-<角色>-<简称>`,例如 `feat/swe/client-web` |
| 契约版本 | 冻结的契约版本号,例如 v1 |
| PRD 版本 | 冻结的 PRD 版本号 |
| 设计版本 | 冻结的设计版本(设计页清单见精简包) |
| 完成定义 | 产出文件清单 + 必须跑过的自测命令 + 必须提交的证据 |
| TODO-UPDATE 要求 | 结尾报告必须带 TODO-UPDATE 小节,格式见“待办机制” |
子任务精简包(裁剪规则写死,不是“尽量精简”):只给本端相关的
契约章节、设计页、PRD 故事和冻结决策摘要,绝不把 PRD、契约、
设计全文复制给每个线程。精简包由四部分组成,缺一部分就补齐再发:
① 本端相关的契约章节(列出章节号 / 标题);② 本端相关的设计页
(列出页名);③ 本端相关的 PRD 故事(列出故事编号);④ 冻结决策摘要
(不超过 10 条,列出决策标题)。派生提示词里必须列出精简包所含章节
清单,例如“契约 §任务状态机、§错误码;设计 p2 审批页;PRD 故事 S1、S3;
决策 D1、D4”——只写“已精简”不算数。线程发现缺章节时向协调员要补发,
不自己猜、不去全文里翻旧版。
## 待办机制(不依赖提示词注入) ## 待办机制(不依赖提示词注入)
@@ -200,6 +222,18 @@ TODO-UPDATE
受影响的客户端各收到一条变更通知和一个回归任务。 受影响的客户端各收到一条变更通知和一个回归任务。
- 协调员不批准:提议线程按旧契约做,差异记入已知问题,不悄悄分叉。 - 协调员不批准:提议线程按旧契约做,差异记入已知问题,不悄悄分叉。
## 任务间问答默认策略与决策记录(v0.3 新增)
- 任务间问答默认策略:被问题卡住的线程先按冻结契约做,把假设写成
开放问题记入结尾报告,不无限等协调员答复、不停工等、不按猜测改契约。
协调员在下一轮答复:确认假设、纠正假设(发回归任务)、或升级为契约变更;
答复本身也要记入决策记录。等答复期间线程不阻塞在原地,先做契约内
无争议的部分。
- 决策记录落盘路径:`docs/decisions.md`,由协调员维护,子线程只在报告里
提议、不直接改。只追加不改写历史:一条决策写清日期、议题、决定、理由、
影响端;推翻旧决策时追加新条写明“取代 D-n”,绝不改旧条原文、不删旧条。
决策记录是合并记录和验收清单之外的第三份事实来源,口头决定不算数。
## 目录与分支规则 ## 目录与分支规则
推荐的单仓布局(单客户端项目可删掉不需要的 `apps/*`): 推荐的单仓布局(单客户端项目可删掉不需要的 `apps/*`):
@@ -224,9 +258,17 @@ tests/ # QA 线程专属,含跨端一致性用例
- 合并顺序:共享核心先合,客户端按“自测通过 -> 协调员评审 -> CI 通过 - 合并顺序:共享核心先合,客户端按“自测通过 -> 协调员评审 -> CI 通过
-> 人 / 宿主执行合并”依次合,冲突由协调员判定, -> 人 / 宿主执行合并”依次合,冲突由协调员判定,
不由子线程自行解决后静默推主线。 不由子线程自行解决后静默推主线。
- 目录隔离要有自动化检查,不能只靠人工评审:合并前由人 / 宿主跑一次 - 目录隔离必须有自动化检查,不能只靠人工评审、不能只写“人工评审”。
检查,确认本分支只改了拥有目录(契约变更经批准的除外)。 合并前由人 / 宿主跑(以拥有目录 `apps/web` 为例,基线以合并目标分支
在 Docker 任务共享工作目录的环境里,这一步尤其不能省。 的最新 HEAD 为准):
```
git fetch origin
git diff --name-only $(git merge-base origin/main HEAD)...HEAD
```
逐项核对输出的每个文件是否落在拥有目录内;契约变更经协调员批准的
文件除外,但批准记录必须能对应到具体文件。检查命令、输出文件清单、
例外批准记录必须原样记入合并记录,缺检查输出的合并记录视为不合格,
不给合并决定。在 Docker 任务共享工作目录的环境里,这一步尤其不能省。
## GitHub 保证(每线程一分支、一 PR、一合并门) ## GitHub 保证(每线程一分支、一 PR、一合并门)
@@ -255,7 +297,8 @@ tests/ # QA 线程专属,含跨端一致性用例
### 合并门:缺一不可,与主分支保护 ### 合并门:缺一不可,与主分支保护
- 合并前四项全过:① GitHub Checks 全绿;② 目录归属检查通过 - 合并前四项全过:① GitHub Checks 全绿;② 目录归属检查通过
(只改拥有目录,契约变更经批准除外);③ 契约版本是冻结版; (只改拥有目录,契约变更经批准除外;检查命令与输出文件清单必须
记入合并记录,见“目录与分支规则”);③ 契约版本是冻结版;
④ 协调员评审通过,且无未解决评审意见。有一项不过就不合并。 ④ 协调员评审通过,且无未解决评审意见。有一项不过就不合并。
- CI 怎么查:用只读方式查,例如本平台的 GET /tasks/{id}/pr/checks。 - CI 怎么查:用只读方式查,例如本平台的 GET /tasks/{id}/pr/checks。
它是只读诊断,绝不重跑检查、不批准、不合并;还没建 PR 时它会 409 它是只读诊断,绝不重跑检查、不批准、不合并;还没建 PR 时它会 409
@@ -295,13 +338,15 @@ tests/ # QA 线程专属,含跨端一致性用例
- 每个客户端线程交付前必须自测:单元测试 + 对接契约的集成测试 - 每个客户端线程交付前必须自测:单元测试 + 对接契约的集成测试
+ 一份手工冒烟清单(启动、登录、核心 agent 任务、异常提示)。 + 一份手工冒烟清单(启动、登录、核心 agent 任务、异常提示)。
- QA 线程分两部分:单端复核(复核各客户端自测证据)和跨端 E2E - QA 线程正式分两部分,各自交付物写死,缺一不算 G5 通过:
(QA 主做,出一份跨端一致性矩阵:同一个 agent 任务、同一份数据, ① 单端复核:逐端复核各客户端的自测证据是否属实(命令、结果、冒烟清单),
在各端的结果、错误提示、同步状态是否一致)。 交付物是逐端复核报告(每端通过 / 不通过 + 证据 + 未复核项)。
- agent 专属测试必须列入 QA 模板,不能只测 happy path: ② 跨端 E2E:同一 agent 任务、同一份数据跑遍各端,交付物是跨端一致性矩阵
沙箱越界、危险动作审批、长任务超时和取消、断网续跑、模型 503 重试、 (各端结果、错误提示、同步状态是否一致)+ 缺陷清单 + 回归清单。
token / 配额超限。安全检查点在 G5 单独签字,检查权限边界和密钥处理, - agent 专属测试清单保留,归属如下,不能只测 happy path:
不算 QA 的附带项。 归单端复核(每端都要过):沙箱越界、危险动作审批、token / 配额超限;
归跨端 E2E(同一任务跨端行为一致):长任务超时和取消、断网续跑、模型 503 重试。
安全检查点在 G5 单独签字,检查权限边界和密钥处理,不算 QA 的附带项。
- 未编译端的 QA 口径要写死:iOS / Android / Mac 在 Linux 主机上编不出来时, - 未编译端的 QA 口径要写死:iOS / Android / Mac 在 Linux 主机上编不出来时,
QA 结论写“代码评审 + Web 核心验证”,不写“构建通过”。 QA 结论写“代码评审 + Web 核心验证”,不写“构建通过”。
- 验收清单模板在 `templates/artifacts/acceptance-checklist.md`。 - 验收清单模板在 `templates/artifacts/acceptance-checklist.md`。
@@ -309,6 +354,11 @@ tests/ # QA 线程专属,含跨端一致性用例
不能代替用户勾选通过。验收和发布按端分别做: 不能代替用户勾选通过。验收和发布按端分别做:
web 演示可真跑,未编译端审代码和构建步骤,两者效力不同,分开标注; web 演示可真跑,未编译端审代码和构建步骤,两者效力不同,分开标注;
web 部署、桌面安装包分发、应用商店审核是三条流水线,分开记录回滚方式。 web 部署、桌面安装包分发、应用商店审核是三条流水线,分开记录回滚方式。
- 每端上手文档是 G6 交付物之一:每端一份,写清启动、登录、核心流程、
常见问题;G4 阶段先写 web 版(G4a 交付时随 web 客户端一起交),
桌面、移动版在各自 G4b / G4c 交付时补齐,不拖到 G6 才现写。
- v1.1 交接清单是 G6 收尾必备,三项缺一不算收尾完成:未修缺陷
(带归属和严重程度)、开放问题(含任务间问答里未关闭的假设)、下轮待办。
## 失败、续跑与成本 ## 失败、续跑与成本
@@ -342,12 +392,17 @@ tests/ # QA 线程专属,含跨端一致性用例
- 待办文件是不是协调员唯一维护的最新状态?有没有子线程直接改了待办? - 待办文件是不是协调员唯一维护的最新状态?有没有子线程直接改了待办?
- 合并记录里执行人写了吗?是协调员评审 + 人 / 宿主执行,还是冒充成协调员自己合的? - 合并记录里执行人写了吗?是协调员评审 + 人 / 宿主执行,还是冒充成协调员自己合的?
- GitHub 门全过了吗?每线程交付有 PR 号吗?Checks 全绿吗?目录归属过了吗? - GitHub 门全过了吗?每线程交付有 PR 号吗?Checks 全绿吗?目录归属过了吗?
目录检查命令和输出记入合并记录了吗?
主分支保护开了吗,没开有没有记为风险?合并是 merge commit 吗? 主分支保护开了吗,没开有没有记为风险?合并是 merge commit 吗?
合并记录里 PR 号、合并提交 hash、CI 运行链接齐了吗?合并后删远程分支了吗? 合并记录里 PR 号、合并提交 hash、CI 运行链接齐了吗?合并后删远程分支了吗?
发布打 tag 了吗,回滚方案是 revert 或重部署上一 tag、而不是 force-push 吗? 发布打 tag 了吗,回滚方案是 revert 或重部署上一 tag、而不是 force-push 吗?
密钥进代码、commit、命令行了吗?.gitignore 在首 commit 前检查了吗? 密钥进代码、commit、命令行了吗?.gitignore 在首 commit 前检查了吗?
- 验收清单是不是用户亲手确认的?有没有一项是协调员替用户勾的? - 验收清单是不是用户亲手确认的?有没有一项是协调员替用户勾的?
- 分阶段走了吗?G3.5 没过就开了 G4b / G4c 吗? - 分阶段走了吗?G3.5 没过就开了 G4b / G4c 吗?
- v0.3 新增项:派生校验表 8 项全填且贴进了提示词吗?精简包所含章节
在提示词里列出了吗?QA 单端复核报告和跨端一致性矩阵都齐了吗?
agent 测试清单归属对吗?决策记录是只追加的 `docs/decisions.md` 吗?
web 版上手文档在 G4a 交了吗?v1.1 交接清单三项齐了吗?
有一项为否,就停在当前门禁,不进入下一阶段。 有一项为否,就停在当前门禁,不进入下一阶段。
## 附录:角色模板(播种随附版) ## 附录:角色模板(播种随附版)
@@ -355,6 +410,9 @@ tests/ # QA 线程专属,含跨端一致性用例
下面是 `templates/roles/` 的随附全文。租户任务内只能看到本文件时, 下面是 `templates/roles/` 的随附全文。租户任务内只能看到本文件时,
以本附录为准。主聊协调员派生子任务时,贴本附录对应章节全文, 以本附录为准。主聊协调员派生子任务时,贴本附录对应章节全文,
不要只贴文件名。发布前核对附录与 `templates/roles/` 一致。 不要只贴文件名。发布前核对附录与 `templates/roles/` 一致。
本附录是 v0.3 版的一部分:正文的 v0.3 改动(目录隔离自动化检查、
派生必填表、精简包、QA 拆分、决策记录、上手文档、v1.1 交接清单)
已同步进对应角色章节,正文与附录不一致就是不合格。
(附录正文由生成脚本从 `templates/roles/` 原样拼接,见 CHANGELOG。) (附录正文由生成脚本从 `templates/roles/` 原样拼接,见 CHANGELOG。)
--- ---
@@ -379,8 +437,13 @@ tests/ # QA 线程专属,含跨端一致性用例
3. 每个子任务提示词必须包含:角色模板全文(来自 SKILL.md 附录)、 3. 每个子任务提示词必须包含:角色模板全文(来自 SKILL.md 附录)、
本阶段输入的版本号、拥有目录、只读目录、分支名、完成定义、 本阶段输入的版本号、拥有目录、只读目录、分支名、完成定义、
禁止事项、TODO-UPDATE 要求。缺一项不派生。 禁止事项、TODO-UPDATE 要求。缺一项不派生。
派生前校验:客户端名、目录、分支、契约版本、PRD 版本、完成定义全填了吗? 派生前校验表(必填表,填好的表原样贴进提示词,缺一项就不发任务):
子任务上下文要精简,只给本端相关的契约章节和设计页。 客户端名、拥有目录、分支名、契约版本、PRD 版本、设计版本、
完成定义、TODO-UPDATE 要求,共 8 项。
子任务精简包(裁剪规则写死):只给本端相关的契约章节、设计页、
PRD 故事和冻结决策摘要(不超过 10 条),绝不把 PRD、契约、设计全文
复制给每个线程;提示词里必须列出精简包所含章节清单,只写“已精简”不算数;
线程缺章节时向你要补发,不自己猜。
## 派生顺序(分阶段,默认不 5 端齐开) ## 派生顺序(分阶段,默认不 5 端齐开)
@@ -397,13 +460,21 @@ tests/ # QA 线程专属,含跨端一致性用例
G4c:移动端 iOS / Android 各 1 个线程。用户明确签字接受并行成本和风险时, G4c:移动端 iOS / Android 各 1 个线程。用户明确签字接受并行成本和风险时,
才可以在记录里写明例外原因后并行开 G4b / G4c。 才可以在记录里写明例外原因后并行开 G4b / G4c。
- G5:QA 分单端复核和跨端 E2E,安全检查点单独签字。 - G5:QA 分单端复核和跨端 E2E,安全检查点单独签字。
单端复核交付物是逐端复核报告(每端通过 / 不通过 + 证据 + 未复核项),
归单端复核的 agent 测试:沙箱越界、危险动作审批、token / 配额超限;
跨端 E2E 交付物是跨端一致性矩阵 + 缺陷清单 + 回归清单,
归跨端 E2E 的 agent 测试:长任务超时和取消、断网续跑、模型 503 重试。
两部分交付物缺一不算 G5 通过。
- G6:你按端分别准备验收清单和演示产物,交用户逐项确认;发布和回滚也按端分开记。 - G6:你按端分别准备验收清单和演示产物,交用户逐项确认;发布和回滚也按端分开记。
## 你的合并规则(评审与执行拆分) ## 你的合并规则(评审与执行拆分)
- 子线程交付物 = 分支 + 产出文件清单 + 自测命令和结果 + 已知问题 + TODO-UPDATE。 - 子线程交付物 = 分支 + 产出文件清单 + 自测命令和结果 + 已知问题 + TODO-UPDATE。
缺证据或缺 TODO-UPDATE 的不给合并决定,先打回补齐。 缺证据或缺 TODO-UPDATE 的不给合并决定,先打回补齐。
- 合并前检查:只改了拥有目录吗(合并前由人 / 宿主跑目录检查)? - 合并前检查:只改了拥有目录吗(合并前由人 / 宿主跑目录检查:
`git diff --name-only $(git merge-base origin/main HEAD)...HEAD`,
逐项核对是否落在拥有目录内,契约变更经批准的除外;检查命令与输出
文件清单必须原样记入合并记录,缺检查输出不给合并决定)?
契约是冻结版本吗?CI 通过吗?有没有把“未验证”写成“已完成”? 契约是冻结版本吗?CI 通过吗?有没有把“未验证”写成“已完成”?
有一项不过就不给合并决定。 有一项不过就不给合并决定。
- 你的决定写成合并记录:哪个分支、谁评审、CI 结果、执行人是谁 - 你的决定写成合并记录:哪个分支、谁评审、CI 结果、执行人是谁
@@ -415,6 +486,15 @@ tests/ # QA 线程专属,含跨端一致性用例
契约版本号加一,通知所有受影响客户端线程做回归;不批准的: 契约版本号加一,通知所有受影响客户端线程做回归;不批准的:
提议线程按旧契约做,差异记入已知问题。 提议线程按旧契约做,差异记入已知问题。
## 任务间问答与决策记录(协调员)
- 被问题卡住的线程先按冻结契约做,把假设写成开放问题记入结尾报告,
不无限等你答复、不停工等;你在下一轮答复(确认、纠正并发回归任务、
或升级为契约变更),答复记入决策记录。
- 决策记录落盘 `docs/decisions.md`,由你维护,只追加不改写历史;
一条决策写清日期、议题、决定、理由、影响端;推翻旧决策追加新条
写明“取代 D-n”,绝不改旧条原文、不删旧条。
## 失败处理 ## 失败处理
- 有进度的中断任务:断点续跑。 - 有进度的中断任务:断点续跑。
@@ -591,7 +671,11 @@ tests/ # QA 线程专属,含跨端一致性用例
# 角色模板:客户端开发(每客户端 1 个线程) # 角色模板:客户端开发(每客户端 1 个线程)
协调员派生你时,必须把下面占位符填好再发给你。 协调员派生你时,必须把下面占位符填好再发给你。
没填好的不要开工,先向协调员要: 没填好的不要开工,先向协调员要(派生前校验表共 8 项:客户端名、
拥有目录、分支名、契约版本、PRD 版本、设计版本、完成定义、
TODO-UPDATE 要求,缺一项就不发任务)。派生提示词里的精简包必须
列出所含章节(契约章节、设计页、PRD 故事、冻结决策摘要),只写
“已精简”时先向协调员要清单再开工;缺章节不自己猜:
- 本客户端:{{CLIENT}},例如 web / macOS / Windows / iOS / Android - 本客户端:{{CLIENT}},例如 web / macOS / Windows / iOS / Android
- 拥有目录:{{APPS_DIR}},例如 `apps/web` - 拥有目录:{{APPS_DIR}},例如 `apps/web`
@@ -706,11 +790,15 @@ agent 类产品还要参与 G3.5 可行性 spike:任务能创建、能跑出
## 产出 ## 产出
1. 测试用例:按 PRD 验收标准写,每个用例写清前置条件、步骤、期望结果。 1. 测试用例:按 PRD 验收标准写,每个用例写清前置条件、步骤、期望结果。
单端复核先复核各客户端的自测证据,跨端 E2E 再做下面的矩阵,不要一个人包全端。 QA 正式分两部分,各自交付物写死,缺一不算 G5 通过:
2. 跨端一致性矩阵:同一个 agent 任务、同一份数据,在已选各端的结果、 ① 单端复核:逐端复核各客户端的自测证据是否属实,交付物是逐端复核报告
文案、状态词、同步状态是否一致;不一致的标明是缺陷还是刻意差异。 (每端通过 / 不通过 + 证据 + 未复核项);
3. agent 专属测试(缺一项不算测完):沙箱越界、危险动作审批、 ② 跨端 E2E:同一 agent 任务、同一份数据跑遍各端,交付物是跨端一致性矩阵
长任务超时和取消、断网续跑、模型 503 重试、token / 配额超限。 (各端结果、文案、状态词、同步状态是否一致;不一致的标明是缺陷还是刻意差异)
+ 缺陷清单 + 回归清单。
2. agent 专属测试(缺一项不算测完),归属如下:
归单端复核(每端都要过):沙箱越界、危险动作审批、token / 配额超限;
归跨端 E2E(同一任务跨端行为一致):长任务超时和取消、断网续跑、模型 503 重试。
4. 安全检查点(G5 单独签字):权限边界是否按契约实现、密钥是否外泄、 4. 安全检查点(G5 单独签字):权限边界是否按契约实现、密钥是否外泄、
agent 是否能读工作目录外文件。安全检查不算 QA 的附带项。 agent 是否能读工作目录外文件。安全检查不算 QA 的附带项。
5. 缺陷清单:每个缺陷写清复现步骤、影响客户端、严重程度、归属线程。 5. 缺陷清单:每个缺陷写清复现步骤、影响客户端、严重程度、归属线程。
@@ -752,6 +840,10 @@ iOS / Android / Mac 在 Linux 主机上编不出来时,你的结论写
3. 发布说明草稿,按端分别写:新能力、已知问题、回滚方式 3. 发布说明草稿,按端分别写:新能力、已知问题、回滚方式
(至少写清“出问题先停哪个端”)。web 部署、桌面安装包分发、 (至少写清“出问题先停哪个端”)。web 部署、桌面安装包分发、
应用商店审核是三条流水线,分开记录,不要写成一次全上。 应用商店审核是三条流水线,分开记录,不要写成一次全上。
4. 每端上手文档:每端一份,写清启动、登录、核心流程、常见问题;
web 版在 G4a 交付时先交,桌面、移动版在各自 G4b / G4c 交付时补齐。
5. v1.1 交接清单:未修缺陷(带归属和严重程度)、开放问题
(含任务间问答里未关闭的假设)、下轮待办;三项缺一不算 G6 收尾完成。
## 用户确认规则 ## 用户确认规则
@@ -0,0 +1,44 @@
"""software-engineering 技能 v0.3:P1/P2 关键词断言(轻量)。
只断言正文与附录都含有 v0.3 的关键概念,不逐字背诵全文:
版本号与上一版、目录隔离可执行检查、派生必填表、精简包所含章节、
QA 两部分交付物与 agent 测试归属、决策记录落盘与只追加、
上手文档与 v1.1 交接清单。正文改了附录没同步时,附录部分就会失败。
"""
import unittest
from pathlib import Path
SKILL = Path(__file__).resolve().parents[1] / "skills" / "software-engineering" / "SKILL.md"
# 正文与附录都要有的关键词
BOTH = ("v0.3", "git diff --name-only", "精简包", "所含章节",
"单端复核", "跨端一致性矩阵", "沙箱越界", "模型 503",
"docs/decisions.md", "只追加", "上手文档", "v1.1 交接清单")
# 派生必填表 8 项:正文表格与协调员附录都要出现
CHECKLIST = ("客户端名", "拥有目录", "分支名", "契约版本",
"PRD 版本", "设计版本", "完成定义", "TODO-UPDATE")
class SoftwareEngineeringV03TestCase(unittest.TestCase):
def test_v03_in_body_and_appendix(self):
text = SKILL.read_text(encoding="utf-8")
main, sep, appendix = text.partition("## 附录:角色模板")
self.assertTrue(sep, "appendix marker missing")
self.assertIn("v0.2", main, "header must name the previous version")
self.assertIn("GitHub 保证", main, "header must name the previous GitHub guarantees")
for kw in BOTH:
self.assertIn(kw, main, kw)
self.assertIn(kw, appendix, "appendix: " + kw)
for kw in CHECKLIST:
self.assertIn(kw, main, kw)
self.assertIn(kw, appendix, "appendix: " + kw)
def test_v03_no_full_copy_rule(self):
text = SKILL.read_text(encoding="utf-8")
self.assertIn("绝不把 PRD、契约", text)
if __name__ == "__main__":
unittest.main()