Back to skills
SKILL.md
Pdlc Test Setup
ASecurity立测试地基(探测技术栈 → 验证并生成 test-commands.yml → 脚手架测试目录 → 接本地钩子)
- 16 stars
- 0 votes
- 0 copies
- 1 view
- Added September 6, 2026
Works with
Security analysis
100/100npx -y skills add kanfu-panda/pdlc-skills --skill pdlc-test-setup --agent claude-codeAre you the author of Pdlc Test Setup?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/kanfu-panda-pdlc-test-setup)---
name: pdlc-test-setup
description: 立测试地基(探测技术栈 → 验证并生成 test-commands.yml → 脚手架测试目录 → 接本地钩子)
argument-hint: [项目目录] [--refresh] [--autonomous]
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
layer: 3
stage: engineering
artifact_type: surface
produces:
- docs/00_standards/test-commands.yml
requires: []
next_step: null
terminal_state: null
recommended_model: sonnet
recommended_effort: medium
---
# 立测试地基
给项目一键立起「客观 check」的地基:**探测技术栈 → 逐条验证命令真能跑 → 写 `docs/00_standards/test-commands.yml` → 脚手架测试目录 → 接本地钩子**。
<!-- @include templates/prompts/iron-law.md(已内联于下方,无需另读) -->
⛔ **IRON LAW · 不可违反的硬门禁**
以下规则为**不可协商**的执行约束:
1. **文件必须落盘**:所有带编号(功能ID / 缺陷ID)的文档,必须作为实际文件写入磁盘,不可仅在对话中输出。
2. **阶段必须落章**:每个阶段完成后必须在状态机 `docs/.pdlc-state/<feature-id>.json` 追加 history,不可跳过。
3. **测试必须存在**:进入 `/pdlc-implement` 前,对应测试必须存在且处于红灯状态。违反则中止。
4. **自检必须执行**:段二自检为强制步骤,不得以"已经很好了"为由跳过。
5. **防循环**:段三修复为单次,不递归。无法自动修复的问题记录到报告,继续往下走。
6. **状态必推进**:成功执行某 phase 后 `current_stage` 必须变更。收尾时若发现 `current_stage` 未推进,视为失败并报错,**不得静默返回**(防止外层循环拿滞后的状态空转烧额度)。唯一例外:命中人工点主动 block 时,`current_stage` 保持不变但必须写 `last_phase_result.ok=false` + `blocked_reason`。
**违反任一条 = 立即中止当前命令,输出违规详情,等待人工介入。**
<!-- @include-end templates/prompts/iron-law.md -->
<!-- @include templates/prompts/noninteractive.md(已内联于下方,无需另读) -->
## 非交互模式(`--autonomous`)
若本命令的参数含 `--autonomous`,本命令进入**无人值守**模式,按以下规则处理原本需要人应答的交互点。**参数是唯一真源**:不带 `--autonomous` 即为交互模式,一切照旧正常询问用户;绝不回读状态机 `run_mode` 兜底(「掉出 autonomous」是安全的失败方向)。
1. **流程性确认**(如「测试已绿是否继续」「是否覆盖已有文件」)→ **不询问**,按预设默认前进,并把决策追加到状态机 `history[].auto_decisions[]`:
```json
{ "point": "<确认点描述>", "chose": "<所选默认>", "at": "<ISO 8601>" }
```
2. **真需人判断**(PRD 关键取舍、评审「需人工确认」项、真实循环依赖等无法安全默认的点)→ **不猜**:
- `current_stage` 保持不变(不推进)
- 写 `last_phase_result.ok = false` 且 `blocked_reason = "<原因>"`
- 末行输出哨兵:`<<<PDLC blocked reason="<原因>">>>`
- 立即结束命令,交还人类
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 -->
## 为什么需要它
pdlc 的命门是「`checks` 只认命令退出码,绝不用模型自评」——`pdlc-tdd` / `pdlc-implement` / `pdlc-review`
与外层循环全都从 `docs/00_standards/test-commands.yml` 取命令。但**在此之前没有任何东西帮你把这个文件立起来**,
没有它,整条客观化链路就是空的。本命令把这块地基变成 turnkey。
> ⛔ **本命令最重要的一条纪律**:**写进 `test-commands.yml` 的每条命令,必须先被真跑过一次、亲眼看到退出码。**
> 一条"看起来对但跑不了"的命令**比留空更坏**——它会让下游每个阶段都拿到假的 `checks`,
> 而整个 pdlc 的可信度正建立在这些 checks 是真的之上。**猜出来的命令一律不写。**
## `--refresh`:让这份 yml 跟上项目的演进
项目会漂移——脚本改名、runner 换代、工具从依赖里移除、子项目增删。这份 yml 一旦过期,
下游所有 `checks` 就开始失真。`--refresh` 是**重新探测 + 给出 diff**,而不是从头再来:
1. **逐条复跑现有命令**,按 `check-commands.md` 的三态判定谁还活着(跑不通 ≠ 检查没过)。
2. **重新探测候选**,与现状对比,得出变更清单。
3. **按方向决定自不自动**(这条是安全底线):
<!-- @include templates/prompts/check-commands.md(已内联于下方,无需另读) -->
## 跑 check 命令:退出码的三态语义
命令取自 `docs/00_standards/test-commands.yml`(唯一真源)。逐条真跑,**按退出码分三态**——
不是两态。这是 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 -->
4. **不管自动与否,全部变更都要在报告里列出**:改了什么、为什么、依据是哪次真跑的退出码。
自动应用的也要能一眼看出来,便于事后 `git diff` 复核。
> ⚠️ **最危险的"自动修复"是把坏掉的 check 留空**——闸门瞬间松了,报告还是绿的。
> 所以留空 / 删除 / 降阈值 / **替换**一律走人工确认,`--autonomous` 也不豁免。
>
> **替换也算**,哪怕换上去的命令能跑、看起来更严:原命令的规则往往已不可考,没法证明新命令与它等价——
> 新命令可能在这一维更严、在另一维更松。**方向不可判,就不能当作变严自动应用**(与三态「查不了 ≠ 没问题」
> 同一条纪律)。能自动应用的只有一种:原来**留空**的项,这次探测到命令并真跑验证通过——那是从「没测」到
> 「测了」,方向确定。
**从哪来的过期信号**:不用你盯着——`pdlc-tdd` / `pdlc-implement` / `pdlc-review` 每次跑 check
时遇到"命令跑不了"都会提示,`/pdlc-quality` 的报告里还有专门的「配置健康度」一节。
看到提示再来 `--refresh` 即可。
## 段一:探测与验证
### 1.1 技术栈探测
扫描特征文件,识别语言 / 包管理器 / 测试框架:
| 特征文件 | 栈 | 典型 unit | 典型 coverage | 典型 lint |
|---|---|---|---|---|
| `Cargo.toml` | Rust | `cargo test` | `cargo llvm-cov --fail-under-lines <阈值>` | `cargo clippy -- -D warnings` |
| `package.json` | Node | `pnpm test` / `npm test` | `vitest run --coverage.thresholds.lines=<阈值>` | `npx eslint .` |
| `pyproject.toml` / `requirements.txt` | Python | `pytest` | `pytest --cov --cov-fail-under=<阈值>` | `ruff check .` |
| `go.mod` | Go | `go test ./...` | `go test ./... -cover` | `golangci-lint run` |
| `pom.xml` / `build.gradle` | JVM | `mvn test` / `./gradlew test` | jacoco check | `mvn checkstyle:check` |
| 仅 `*.sh` | Shell | 项目自有测试脚本 | —(通常无) | `shellcheck <文件>` |
**多语言 / monorepo**:逐个子项目探测;`test-commands.yml` 只能有一组命令,所以要么用能覆盖全仓的聚合命令
(如 `pnpm -r test`),要么与用户确认以哪个子项目为准。**探测不到唯一答案时不要自己拍板**(见 §1.3)。
### 1.2 逐条验证(不可跳过)
对每个候选命令**真的跑一次**,按退出码归类:
| 观察到的结果 | 结论 | 动作 |
|---|---|---|
| 退出码 0 | 命令可用且当前通过 | **采纳** |
| 退出码非 0、非 127,且输出像测试/lint 报告 | 命令可用,只是当前有失败项 | **采纳**(地基是"命令能跑",不是"当前全绿") |
| 退出码 127 / `command not found` / 工具未安装 | 命令不可用 | **留空**,在报告里写明缺什么 |
| 无对应配置(如没配覆盖率工具) | 该项本项目暂无 | **留空** |
| 命令挂起 / 需要交互 | 不适合做自动 check | **留空**,报告里说明 |
> ⚠️ **留空是合法且诚实的结果**,与状态机里「没有检查命令可跑的阶段 → `checks: {}` 留空」同一条纪律。
> 宁可空着并在报告里提示怎么补,也不要写一条没验证过的命令。
**覆盖率达标线写死在命令参数里**(如 `--cov-fail-under=85`),不做二次解释——这样"达标"就是退出码本身,
不需要任何一方去解析百分比数字。默认阈值 **85%**;项目已有更高要求则沿用已有。
### 1.3 需要人拍板的点(`--autonomous` 下 block,不猜)
以下属判断题而非流程题,**不得自动选**,须写明原因交还人类:
- 探测到**多个**并列候选(如同时有 `jest` 和 `vitest` 配置),无法判定以哪个为准
- **零候选**(项目还没有任何测试框架)——装哪个框架是技术选型,必须人定
- monorepo 里以哪个子项目 / 哪条聚合命令为准
- 覆盖率阈值定多少(若项目无既有约定)
探测到**唯一**候选且验证通过 → 属流程性确认,`--autonomous` 下自动采纳并在报告里留痕。
## 段二:落地
### 2.1 写 `docs/00_standards/test-commands.yml`
以 本 skill 目录下的 `assets/test-commands-template.yml` 为骨架。**这是 surface 型产物**——就地编辑,不做 `-v2` 累积。
- **文件已存在** → **不覆盖**。改为逐条校验现有命令是否仍能跑:
- 仍能跑 → 保持原样(用户的选择优先于探测结果)
- 已跑不通(工具改名 / 脚本删了)→ 报告里列出,**建议**改法,等人确认。`--autonomous` 下同样**不改原值**——
建议的替换命令哪怕已真跑通过,也只写进报告的「⚠️ 待人工」,yml 里保持原样
- 缺失的项(空字符串)→ 若这次探测到可用命令,提议补上
- **文件不存在** → 用本次验证通过的命令生成;未验证通过的项留空字符串。
### 2.2 脚手架测试目录(已有则不动)
按栈惯例建空目录 + 一个占位说明,**不生成业务测试用例**:
- Rust `tests/`、Node `src/__tests__/` 或 `tests/`、Python `tests/`、Go 同包 `*_test.go`、JVM `src/test/java/`
- **跟随项目既有布局**,不新造平行目录。守卫侧(`/pdlc-tdd`、`/pdlc-implement`)的测试定位规则
是布局无关的,所以这里不必迁就任何预设结构
### 2.3 接本地钩子(不进 CI)
在**本地** git 钩子里跑基础 check(`husky` / `lefthook` / `pre-commit` / 原生 `.git/hooks`,按项目已有的来):
- **pre-commit**:`lint`(快,秒级)
- **pre-push**:`unit`(+ `coverage` 若已配)
> **不新建 CI workflow**:这些 check 本地秒级可得,放 CI 只会让每次迭代都烧配额。
> 已有 CI 的项目也不改它的触发条件——那需要项目所有者单独授权。
### 2.4 老项目:可选的轻量底线回填
仅当用户要求:为**当前覆盖率最低**的若干核心模块补特征化测试(characterization test,锁住现有行为),
把覆盖率抬到阈值线。**这不是补齐测试**,只是让地基能立住。深度用例仍走 `/pdlc-tdd`。
## 段三:自检(强制)
<!-- @include templates/prompts/self-audit.md(已内联于下方,无需另读) -->
## 段二:自检(强制)
重新阅读本次产出物,按质量关卡清单逐项检查。勾选已通过,标注未通过原因。
> **注意**:自检清单的具体内容由各命令自行定义,本片段只规定结构。
## 段三:修复(单次,不递归)
针对自检段标注为未通过的项:
- **可自动修复**:直接修复(如补缺字段、修正格式、补齐缺失段落)
- **修复后回验**:再次运行自检,确认被修复项现在通过
- **无法自动修复**:记录到自审报告,不再尝试,流程继续
⚠️ 单次修复原则:若一轮修复后仍有项未通过,**不再递归修复**,防止死循环。
<!-- @include-end templates/prompts/self-audit.md -->
### 自检清单(必须全部检查)
- [ ] `test-commands.yml` 里**每一条非空命令**,都在本次会话中被真跑过、看到过退出码
- [ ] **收尾复跑一遍**:从写好的 yml 里逐条读命令再跑一次,确认与写入时的结论一致(防止写错路径 / 引号)
- [ ] 留空的项,报告里都写明了「为什么空」和「怎么补」
- [ ] 覆盖率阈值已写死在命令参数里,不依赖任何一方解析百分比
- [ ] 测试目录跟随项目既有布局;若写了 `test-commands.yml`,其 `unit` 命令能定位到这些测试
- [ ] 钩子是**本地**的,没有新建或修改任何 CI workflow
- [ ] 已存在的 `test-commands.yml` 没有被静默覆盖
- [ ] (`--refresh` 时)所有变更已在报告里列出;**没有任何"让闸门变松"的改动被自动应用**
- [ ] (`--refresh` 时)已存在但跑不通的命令**原值未动**;替换方案只写在报告里等人确认,没有以「变严」为由自动替换
## 段四:修复(单次,不递归)
<!-- @include templates/prompts/loop-prevention.md(已内联于下方,无需另读) -->
## 防循环规则
本命令所有的自检-修复循环均受以下约束:
1. **单次检查**:同一个自检清单在本次命令执行中只跑一次(起始 + 修复后验证共两次读)
2. **单次修复**:发现的问题只尝试修复一轮
3. **不递归**:修复后不再重新触发自检的全量重跑
4. **失败降级**:无法自动修复的问题 → 记录到自审报告 → 流程继续 → 最终报告标注待人工处理
这是为了防止 agent 在"修完再查、查完再修"的往返中陷入死循环。
<!-- @include-end templates/prompts/loop-prevention.md -->
- 复跑发现某条命令与写入时结论不一致 → 修正或改为留空
- 无法自动修复 → 记入报告,交还人类
## 段五:交接
<!-- @include templates/prompts/handoff.md(已内联于下方,无需另读) -->
## 段四:交接(Handoff)
命令完成后必须输出以下格式的最终消息:
```
✅ <阶段名> 完成:<主要产出物路径>
📊 自检:<通过数>/<总数> 通过(若有未通过,附要点)
📦 状态快照:docs/.pdlc-state/<feature-id>.json
👉 下一步:/pdlc-<next_step>
(如果有分叉)或 /pdlc-<alt>(条件:<选择依据>)
```
**规则:**
- 主流程命令(写状态机的命令;下一跳见正文里「本命令的状态机取值」)必须显式输出"下一步",不可省略
- 工具型命令(Layer 3)可以没有 `next_step`,此时输出 `👉 下一步:(本次流程结束,无后续)`
- 分叉场景必须说明**选择条件**,例如"若需补充测试用例 → `/pdlc-tdd`;若测试已齐 → `/pdlc-review`"
<!-- @include-end templates/prompts/handoff.md -->
**本命令的 handoff 输出:**
```
✅ 测试地基已立:docs/00_standards/test-commands.yml
unit : <命令> (退出码 <N>,已验证)
coverage : <命令 | 留空> (<验证结论 | 为什么空>)
lint : <命令> (退出码 <N>,已验证)
e2e : <命令 | 留空> (<验证结论 | 为什么空>)
🪝 本地钩子:pre-commit → lint · pre-push → unit
📁 测试目录:<路径列表>
⚠️ 待人工:<留空项怎么补 / 需要拍板的选型>
👉 下一步:/pdlc-tdd <功能描述> —— 本命令只立地基,深度用例走 TDD
```
## 诚实边界(务必如实说明,不要夸大)
- 本命令**只立地基 + 可选补底线**,**不生成完整测试套件**。AI 生成的测试容易浅、容易只测 happy path,
真正的用例设计仍走 `/pdlc-tdd`(测试先行、红灯门)。
- 留空的项就是**当前没有**,不要为了让输出好看而填一条没验证过的命令。
- 覆盖率阈值只是一条线,**过线不等于测得好**——它挡的是"几乎没测",不保证用例有效。
---
**目标项目**: $ARGUMENTS
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.