/pdlc-quality
质量闸门——跑真实 check、对照质量目标、出可核对报告,由人签字放行
Claude Code
$ npx -y skills add kanfu-panda/pdlc-skills --skill pdlc-quality --agent claude-code
Codex
$ npx skills add kanfu-panda/pdlc-skills --skill pdlc-quality -a codex -y
Cursor
$ npx skills add kanfu-panda/pdlc-skills --skill pdlc-quality -a cursor -y
Gemini CLI
$ npx skills add kanfu-panda/pdlc-skills --skill pdlc-quality -a gemini-cli -y
GitHub Copilot
$ npx skills add kanfu-panda/pdlc-skills --skill pdlc-quality -a github-copilot -y
OpenCode
$ npx skills add kanfu-panda/pdlc-skills --skill pdlc-quality -a opencode -y
Windsurf
$ npx skills add kanfu-panda/pdlc-skills --skill pdlc-quality -a windsurf -y
SKILL.md
pdlc-quality.SKILL.mdname: pdlc-quality
description: 质量闸门——跑真实 check、对照质量目标、出可核对报告,由人签字放行
argument-hint: "[--init] [--autonomous]"
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
layer: 3
stage: quality
artifact_type: ledger
produces:
# 主产物(ledger 型,一次一份可看趋势);.md 是真源,.html 是同数据的可视化视图
- docs/07_reviews/quality/<YYYY-MM-DD>.md
- docs/07_reviews/quality/<YYYY-MM-DD>.html
# 仅 --init 时创建(surface 型,就地编辑不累积)
- docs/00_standards/quality-targets.yml
- docs/00_standards/e2e-flow-map.yml
requires:
- docs/00_standards/test-commands.yml
next_step: null
terminal_state: null
recommended_model: sonnet
recommended_effort: medium
质量闸门与报告
跑真实 check → 对照质量目标 → 出可核对的报告 → **人签字放行**。
<!-- @include templates/prompts/iron-law-tool.md(已内联于下方,无需另读) --> ⛔ **IRON LAW · 不可违反的硬门禁(工具型命令)**
本命令不是主链路上的阶段:**不追加 `history`,不改 `current_stage` / `next_step` / `last_phase_result`**,也不为此分配功能ID。以下规则不可协商:
1. **文件必须落盘**:正文要求创建的文件必须作为实际文件写入磁盘,不可仅在对话中输出(只要求在对话里输出的,照正文办)。 2. **自检必须执行**:产出后按本命令的自检项逐项核对,不得以"已经很好了"为由跳过。 3. **防循环**:修复只做一次,不递归。修不了的问题记进报告,继续往下走。
**违反任一条 = 立即中止当前命令,输出违规详情,等待人工介入。** <!-- @include-end templates/prompts/iron-law-tool.md --> <!-- @include templates/prompts/noninteractive.md(已内联于下方,无需另读) -->
非交互模式(`--autonomous`)
若本命令的参数含 `--autonomous`,本命令进入**无人值守**模式,按以下规则处理原本需要人应答的交互点。**参数是唯一真源**:不带 `--autonomous` 即为交互模式,一切照旧正常询问用户;绝不回读状态机 `run_mode` 兜底(「掉出 autonomous」是安全的失败方向)。
1. **流程性确认**(如「测试已绿是否继续」「是否覆盖已有文件」)→ **不询问**,按预设默认前进,并把决策追加到状态机 `history[].auto_decisions[]` (写状态机的命令:推进时给状态推进脚本传 `--decision "<确认点描述>=<所选默认>"`,可重复;脚本写成下面的样子):
{ "point": "<确认点描述>", "chose": "<所选默认>", "at": "<ISO 8601>" }2. **真需人判断**(PRD 关键取舍、评审「需人工确认」项、真实循环依赖、**测试与设计 / PRD 矛盾**等无法安全默认的点)→ **不猜**。 改测试、改检查命令让它变绿,永远不是「流程性默认」,不能记成 `--decision`:
- `current_stage` 保持不变(不推进)
- 写 `last_phase_result.ok = false` 且 `blocked_reason = "<原因>"`(写状态机的命令:给状态推进脚本传 `--blocked "<原因>"`)
- 末行输出哨兵:`<<<PDLC blocked reason="<原因>">>>`
- 立即结束命令,交还人类
- **守卫拦截也走这一条**:前置守卫(缺设计文档、缺测试、测试没红等)在 `--autonomous` 下拦住本命令时,
不能只输出 ⛔ 就停——同样写 `ok=false` + `blocked_reason`(写明哪条守卫、缺什么)并输出哨兵。 否则状态机里仍是上一阶段的 `ok=true`,循环驱动只看到 `current_stage` 没动,会把「被拦」误报成「卡住」,真实原因丢失。 3. **破坏性操作**(发布 / 部署 / 打 tag / 触发 CI / DROP / force-push 等不可逆·外发操作)→ `--autonomous` **无效**,仍必须人工显式确认。 4. **顺手的 sidecar 产物**(如缺失时创建 `CHANGELOG.md`、补全文档 PDLC-TRACE 的创建时间等本阶段职责内、可安全默认的辅助改动)→ 视为流程性默认,**直接做并记入 `auto_decisions[]`**;这类改动不新增外部副作用,不属破坏性操作。
> 进入 autonomous 模式时,在状态机顶层写 `run_mode: "autonomous"` 仅供留痕(复盘区分人工 vs 循环产出)。 <!-- @include-end templates/prompts/noninteractive.md -->
这个命令的立身之本
**一切判定来自客观数据**:覆盖率数字来自覆盖率工具、E2E 覆盖来自 flow→test 映射 + 真跑结果、lint 来自退出码。 **AI 只负责把这些数据整理成报告,不参与"达标与否"的判定**,放行由人。
> ⛔ 绝不允许出现的行为:用"我看了一下代码,测试挺全的"这类判断替代真实数据; > 用上一次的结果冒充本次;命令没跑通却按通过处理;覆盖率没测量却写一个数字。 > **量不到就如实写"未测量"**——这与状态机里「无命令可跑 → `checks: {}`」是同一条纪律。
前置:两份真源
| 文件 | 作用 | 缺失时 | |---|---|---| | `docs/00_standards/test-commands.yml` | 怎么量(命令) | **中止**,提示先跑 `/pdlc-test-setup` | | `docs/00_standards/quality-targets.yml` | 量到多少算达标 | 走 `--init` 交互创建(见下) | | `docs/00_standards/e2e-flow-map.yml` | 核心流 → E2E 测试 的映射 | 若 targets 里声明了 `core_flows` 则**必须有**,否则 E2E 判定无法机械化 |
`--init`:首次建立目标声明
1. 读 本 skill 目录下的 `assets/quality-targets-template.yml` 作骨架。 2. **从 PRD 自动抽 `core_flows` 草稿**:扫 `docs/01_requirements/prd/`,提取标记为 **P0 / P1** 的功能流程, 生成候选清单(含来源 PRD 路径)**供人确认**——降低首次声明的摩擦,但**最终清单必须人确认**,不自动落盘。 3. 覆盖率达标线:默认与 `test-commands.yml` 的 coverage 命令参数对齐;两者不一致要提示人对齐 (**以命令参数为准**——那才是真正的强制点)。 4. 同时生成 `e2e-flow-map.yml` 骨架(每条 flow 一个空 `tests` 列表待填)。
段一:跑真实 check
用 `bash scripts/pdlc-checks.sh --only coverage,lint,e2e <项目根>` 逐条真跑,记录**命令原文 + 退出码 + 关键输出**(脚本在 stderr 逐条回显)。 退出码的三态语义、以及「命令跑不了 = yml 过期信号」按下面的规则处理:
<!-- @include templates/prompts/check-commands.md(已内联于下方,无需另读) -->
跑 check 命令:退出码的三态语义
**用脚本跑,不要手写 `checks`**:
bash scripts/pdlc-checks.sh --only <本阶段要的项,如 unit,lint> <项目根>
脚本是本 skill 自带的 `scripts/pdlc-checks.sh`。它读 `docs/00_standards/test-commands.yml`(唯一真源),逐条真跑,按下表映射,**stdout 只有一行 JSON**—— **原样**写进 `last_phase_result.checks`,不改键名、不改值、不补不删。每条命令的退出码与输出末尾回显在 stderr,报告里引用那几行即可。脚本退出码 `2`(没有 yml 等)= 没有可跑的 check → `checks: {}`。
> 为什么不手写:键名、布尔类型、三态这几件事是确定性的,交给模型写,真机上同一份项目轮与轮之间就换一种错法 > (键名照抄 yml 的 `unit`、值写成 `"4 passed, 1 failed"`、`127` 写成 `false`)。 > 环境里没有 `bash` 时才按下表手工映射。
脚本按退出码分三态——不是两态。这是 IRON LAW「checks 只认客观事实」在执行层的落法:
| 观察到的 | 含义 | 写进 `checks` | |---|---|---| | 退出码 `0` | 通过 | 对应键 = `true` | | 退出码非 0(命令**跑起来了**,只是没过) | 未通过 | 对应键 = `false` | | 退出码 `127` / `command not found` / 脚本文件不存在 / 该项为空字符串 | **无法判定** | **省略该键,或写 `null`**——**绝不能是 `false`** |
> ⛔ **唯一的红线是不许写 `false`**:那是**会误导人的虚报**——它说的是"检查失败了", > 于是有人去查代码,但真正的问题是**配置过期**,代码可能完全没毛病。 > > **省略键与 `null` 等价,两种都可以**:对消费方而言无法区分(`jq '.checks.lint_clean'` > 在两种情况下都返回 `null`)。`null` 甚至更明确——省略是歧义的("没看"还是"看了判不出"), > `null` 明说"看了,判不出"。**别在这上面纠结,力气花在不写 `false` 上。** > > 这与「没有检查命令可跑的阶段 → `checks: {}`」同源。
「跑不了」= `test-commands.yml` 过期信号(顺带检测,零额外成本)
命令跑不起来,几乎总意味着**这份 yml 已经跟不上项目了**——脚本改名、runner 换了、 工具从依赖里移除、子项目路径调整。真实项目里这类漂移是常态(例如某前端框架升级后 移除了内置 lint 子命令,而 yml 里那条命令还在)。
由于**各阶段本来就在跑这些命令**,这个信号是白捡的。检测到时:
1. 在本阶段的报告里单列一条:**「`test-commands.yml` 疑似过期」**,写明是哪一项、 观察到什么(退出码 / 报错原文)、以及为什么判定为"跑不了"而非"没通过"。 2. 提示补救:`/pdlc-test-setup --refresh`(重新探测并给出 diff)。 3. **不要自作主张改 yml**——本阶段的职责是干活,不是改配置;只报告,不动手。
变更方向决定自动化程度(`--refresh` 时适用)
更新这份 yml 等于**改变"通过"的定义**,所以按**方向**区别对待:
| 方向 | 例子 | 处理 | |---|---|---| | **让闸门变严** | 空着的 `e2e` 现在能跑了、覆盖率阈值上调 | **可自动应用**,报告留痕 | | **平移替换** | 命令改名但语义相同,且新命令**已验证能跑** | **可自动应用**,报告留痕 | | **让闸门变松** | 删掉某条 check、把命令改成空、下调阈值 | **必须人确认**,绝不自动 |
> ⚠️ 这条方向规则是防「自动修复把闸门修没了」:lint 命令坏掉时,**把它留空**是最省事的 > "修法",结果闸门悄悄松了、报告还是绿的——比不更新更危险。 > **变严可以自动,变松必须由人签字。** <!-- @include-end templates/prompts/check-commands.md -->
补充两条本命令特有的:
- 命令为空字符串(项目未配置该项)→ 如实记为「留空,未测量」,**不得因此判为通过**
- 覆盖率数字从工具输出中**摘取原文**,不重新计算、不四舍五入到好看的数
段二:三项机械核对
2.1 覆盖率
拿实测数字对 `quality-targets.yml` 的达标线。真正的强制点是命令参数里的阈值(如 `--cov-fail-under=85`)—— **退出码就是判定**;yml 里的数字用于报告展示与趋势。两处不一致 → 报告里提示对齐。
2.2 E2E 覆盖矩阵(B2 的第一个地基)
对每条 `core_fl
Read more
name: pdlc-quality description: 质量闸门——跑真实 check、对照质量目标、出可核对报告,由人签字放行 argument-hint: "[--init] [--autonomous]" allowed-tools: Read, Write, Edit, Glob, Grep, Bash layer: 3 stage: quality artifact_type: ledger produces: # 主产物(ledger 型,一次一份可看趋势);.md 是真源,.html 是同数据的可视化视图 - docs/07_reviews/quality/<YYYY-MM-DD>.md - docs/07_reviews/quality/<YYYY-MM-DD>.html # 仅 --init 时创建(surface 型,就地编辑不累积) - docs/00_standards/quality-targets.yml - docs/00_standards/e2e-flow-map.yml requires: - docs/00_standards/test-commands.yml next_step: null terminal_state: null recommended_model: sonnet recommended_effort: medium
质量闸门与报告
跑真实 check → 对照质量目标 → 出可核对的报告 → **人签字放行**。
<!-- @include templates/prompts/iron-law-tool.md(已内联于下方,无需另读) --> ⛔ **IRON LAW · 不可违反的硬门禁(工具型命令)**
本命令不是主链路上的阶段:**不追加 `history`,不改 `current_stage` / `next_step` / `last_phase_result`**,也不为此分配功能ID。以下规则不可协商:
1. **文件必须落盘**:正文要求创建的文件必须作为实际文件写入磁盘,不可仅在对话中输出(只要求在对话里输出的,照正文办)。 2. **自检必须执行**:产出后按本命令的自检项逐项核对,不得以"已经很好了"为由跳过。 3. **防循环**:修复只做一次,不递归。修不了的问题记进报告,继续往下走。
**违反任一条 = 立即中止当前命令,输出违规详情,等待人工介入。** <!-- @include-end templates/prompts/iron-law-tool.md --> <!-- @include templates/prompts/noninteractive.md(已内联于下方,无需另读) -->
非交互模式(`--autonomous`)
若本命令的参数含 `--autonomous`,本命令进入**无人值守**模式,按以下规则处理原本需要人应答的交互点。**参数是唯一真源**:不带 `--autonomous` 即为交互模式,一切照旧正常询问用户;绝不回读状态机 `run_mode` 兜底(「掉出 autonomous」是安全的失败方向)。
1. **流程性确认**(如「测试已绿是否继续」「是否覆盖已有文件」)→ **不询问**,按预设默认前进,并把决策追加到状态机 `history[].auto_decisions[]` (写状态机的命令:推进时给状态推进脚本传 `--decision "<确认点描述>=<所选默认>"`,可重复;脚本写成下面的样子):
{ "point": "<确认点描述>", "chose": "<所选默认>", "at": "<ISO 8601>" }2. **真需人判断**(PRD 关键取舍、评审「需人工确认」项、真实循环依赖、**测试与设计 / PRD 矛盾**等无法安全默认的点)→ **不猜**。 改测试、改检查命令让它变绿,永远不是「流程性默认」,不能记成 `--decision`:
- `current_stage` 保持不变(不推进)
- 写 `last_phase_result.ok = false` 且 `blocked_reason = "<原因>"`(写状态机的命令:给状态推进脚本传 `--blocked "<原因>"`)
- 末行输出哨兵:`<<<PDLC blocked reason="<原因>">>>`
- 立即结束命令,交还人类
- **守卫拦截也走这一条**:前置守卫(缺设计文档、缺测试、测试没红等)在 `--autonomous` 下拦住本命令时,
不能只输出 ⛔ 就停——同样写 `ok=false` + `blocked_reason`(写明哪条守卫、缺什么)并输出哨兵。 否则状态机里仍是上一阶段的 `ok=true`,循环驱动只看到 `current_stage` 没动,会把「被拦」误报成「卡住」,真实原因丢失。 3. **破坏性操作**(发布 / 部署 / 打 tag / 触发 CI / DROP / force-push 等不可逆·外发操作)→ `--autonomous` **无效**,仍必须人工显式确认。 4. **顺手的 sidecar 产物**(如缺失时创建 `CHANGELOG.md`、补全文档 PDLC-TRACE 的创建时间等本阶段职责内、可安全默认的辅助改动)→ 视为流程性默认,**直接做并记入 `auto_decisions[]`**;这类改动不新增外部副作用,不属破坏性操作。
> 进入 autonomous 模式时,在状态机顶层写 `run_mode: "autonomous"` 仅供留痕(复盘区分人工 vs 循环产出)。 <!-- @include-end templates/prompts/noninteractive.md -->
这个命令的立身之本
**一切判定来自客观数据**:覆盖率数字来自覆盖率工具、E2E 覆盖来自 flow→test 映射 + 真跑结果、lint 来自退出码。 **AI 只负责把这些数据整理成报告,不参与"达标与否"的判定**,放行由人。
> ⛔ 绝不允许出现的行为:用"我看了一下代码,测试挺全的"这类判断替代真实数据; > 用上一次的结果冒充本次;命令没跑通却按通过处理;覆盖率没测量却写一个数字。 > **量不到就如实写"未测量"**——这与状态机里「无命令可跑 → `checks: {}`」是同一条纪律。
前置:两份真源
| 文件 | 作用 | 缺失时 | |---|---|---| | `docs/00_standards/test-commands.yml` | 怎么量(命令) | **中止**,提示先跑 `/pdlc-test-setup` | | `docs/00_standards/quality-targets.yml` | 量到多少算达标 | 走 `--init` 交互创建(见下) | | `docs/00_standards/e2e-flow-map.yml` | 核心流 → E2E 测试 的映射 | 若 targets 里声明了 `core_flows` 则**必须有**,否则 E2E 判定无法机械化 |
`--init`:首次建立目标声明
1. 读 本 skill 目录下的 `assets/quality-targets-template.yml` 作骨架。 2. **从 PRD 自动抽 `core_flows` 草稿**:扫 `docs/01_requirements/prd/`,提取标记为 **P0 / P1** 的功能流程, 生成候选清单(含来源 PRD 路径)**供人确认**——降低首次声明的摩擦,但**最终清单必须人确认**,不自动落盘。 3. 覆盖率达标线:默认与 `test-commands.yml` 的 coverage 命令参数对齐;两者不一致要提示人对齐 (**以命令参数为准**——那才是真正的强制点)。 4. 同时生成 `e2e-flow-map.yml` 骨架(每条 flow 一个空 `tests` 列表待填)。
段一:跑真实 check
用 `bash scripts/pdlc-checks.sh --only coverage,lint,e2e <项目根>` 逐条真跑,记录**命令原文 + 退出码 + 关键输出**(脚本在 stderr 逐条回显)。 退出码的三态语义、以及「命令跑不了 = yml 过期信号」按下面的规则处理:
<!-- @include templates/prompts/check-commands.md(已内联于下方,无需另读) -->
跑 check 命令:退出码的三态语义
**用脚本跑,不要手写 `checks`**:
bash scripts/pdlc-checks.sh --only <本阶段要的项,如 unit,lint> <项目根>
脚本是本 skill 自带的 `scripts/pdlc-checks.sh`。它读 `docs/00_standards/test-commands.yml`(唯一真源),逐条真跑,按下表映射,**stdout 只有一行 JSON**—— **原样**写进 `last_phase_result.checks`,不改键名、不改值、不补不删。每条命令的退出码与输出末尾回显在 stderr,报告里引用那几行即可。脚本退出码 `2`(没有 yml 等)= 没有可跑的 check → `checks: {}`。
> 为什么不手写:键名、布尔类型、三态这几件事是确定性的,交给模型写,真机上同一份项目轮与轮之间就换一种错法 > (键名照抄 yml 的 `unit`、值写成 `"4 passed, 1 failed"`、`127` 写成 `false`)。 > 环境里没有 `bash` 时才按下表手工映射。
脚本按退出码分三态——不是两态。这是 IRON LAW「checks 只认客观事实」在执行层的落法:
| 观察到的 | 含义 | 写进 `checks` | |---|---|---| | 退出码 `0` | 通过 | 对应键 = `true` | | 退出码非 0(命令**跑起来了**,只是没过) | 未通过 | 对应键 = `false` | | 退出码 `127` / `command not found` / 脚本文件不存在 / 该项为空字符串 | **无法判定** | **省略该键,或写 `null`**——**绝不能是 `false`** |
> ⛔ **唯一的红线是不许写 `false`**:那是**会误导人的虚报**——它说的是"检查失败了", > 于是有人去查代码,但真正的问题是**配置过期**,代码可能完全没毛病。 > > **省略键与 `null` 等价,两种都可以**:对消费方而言无法区分(`jq '.checks.lint_clean'` > 在两种情况下都返回 `null`)。`null` 甚至更明确——省略是歧义的("没看"还是"看了判不出"), > `null` 明说"看了,判不出"。**别在这上面纠结,力气花在不写 `false` 上。** > > 这与「没有检查命令可跑的阶段 → `checks: {}`」同源。
「跑不了」= `test-commands.yml` 过期信号(顺带检测,零额外成本)
命令跑不起来,几乎总意味着**这份 yml 已经跟不上项目了**——脚本改名、runner 换了、 工具从依赖里移除、子项目路径调整。真实项目里这类漂移是常态(例如某前端框架升级后 移除了内置 lint 子命令,而 yml 里那条命令还在)。
由于**各阶段本来就在跑这些命令**,这个信号是白捡的。检测到时:
1. 在本阶段的报告里单列一条:**「`test-commands.yml` 疑似过期」**,写明是哪一项、 观察到什么(退出码 / 报错原文)、以及为什么判定为"跑不了"而非"没通过"。 2. 提示补救:`/pdlc-test-setup --refresh`(重新探测并给出 diff)。 3. **不要自作主张改 yml**——本阶段的职责是干活,不是改配置;只报告,不动手。
变更方向决定自动化程度(`--refresh` 时适用)
更新这份 yml 等于**改变"通过"的定义**,所以按**方向**区别对待:
| 方向 | 例子 | 处理 | |---|---|---| | **让闸门变严** | 空着的 `e2e` 现在能跑了、覆盖率阈值上调 | **可自动应用**,报告留痕 | | **平移替换** | 命令改名但语义相同,且新命令**已验证能跑** | **可自动应用**,报告留痕 | | **让闸门变松** | 删掉某条 check、把命令改成空、下调阈值 | **必须人确认**,绝不自动 |
> ⚠️ 这条方向规则是防「自动修复把闸门修没了」:lint 命令坏掉时,**把它留空**是最省事的 > "修法",结果闸门悄悄松了、报告还是绿的——比不更新更危险。 > **变严可以自动,变松必须由人签字。** <!-- @include-end templates/prompts/check-commands.md -->
补充两条本命令特有的:
- 命令为空字符串(项目未配置该项)→ 如实记为「留空,未测量」,**不得因此判为通过**
- 覆盖率数字从工具输出中**摘取原文**,不重新计算、不四舍五入到好看的数
段二:三项机械核对
2.1 覆盖率
拿实测数字对 `quality-targets.yml` 的达标线。真正的强制点是命令参数里的阈值(如 `--cov-fail-under=85`)—— **退出码就是判定**;yml 里的数字用于报告展示与趋势。两处不一致 → 报告里提示对齐。
2.2 E2E 覆盖矩阵(B2 的第一个地基)
对每条 `core_fl
Author: kanfu-panda Repo: github.com/kanfu-panda/pdlc-skills License: MIT pdlc-skills is built on one rule: an AI saying "done" doesn't count — exit codes do.
Other skills on pdlc.
pdlc-adopt
已有代码、还没有 PDLC 文档的老项目接入——只读扫描后逆向生成基线文档并做健康检查,不改代码;空目录新项目用 /pdlc-bootstrap
pdlc-bootstrap
空目录从一句话描述初始化新项目(服务 / 应用拆分、技术栈、目录骨架与 PDLC 文档目录);已有代码的项目用 /pdlc-adopt
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about pdlc-quality.
- Which coding agents can use pdlc-quality?
- pdlc-quality installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

