Files
git-learn/.agents/skills/dev-flow/SKILL.md
T
zhuyongxin 24a71e78f1 Harden dev-flow: pre-authorization marker, alternatives log, check script
- Record rejected answers in decision.md at the moment they are rejected

- Allow explicit pre-authorized Build via a pre-authorized marker line

- Land scripts/check-dev-flow.sh and derive devflow/index.md from archives

- Add dev-flow process artifacts (decisions, prd) for open changes
2026-09-18 18:23:18 +08:00

193 lines
9.7 KiB
Markdown

---
name: dev-flow
description: 轻量开发流程:想清楚 → 做出来 → 收好尾。编排 OpenSpec 的 propose / apply / archive 三个能力,并为每个非平凡变更留下 decision.md——记录为什么这么做、否决了哪些备选、代价是什么。在用户显式调用 /dev-flow,或明确要求走开发流程时使用。
---
# Dev Flow
三个阶段,两个确认点,不分档。
```text
Think 想清楚 → Build 做出来 → Close 收好尾
⏸ 确认点 1 ⏸ 确认点 2
授权进入实现 是否归档
```
**每个非平凡变更留下一份 `decision.md`**——记录代码和规格承载不了的东西:**为什么这么做,以及放弃了什么。**
## 能力来源
dev-flow 编排已有能力,**不重复实现它们**:
| 阶段 | 能力 | 用途 |
|---|---|---|
| Think | `grill-with-docs` | 澄清:一次一问、能查代码的自己查、术语沉淀进 `CONTEXT.md` |
| Think | `openspec-propose` | 生成 `proposal.md` / `design.md` / `specs/` / `tasks.md` |
| Build | `openspec-apply-change` | 按规格实现 |
| Build | `diagnose` / `tdd` | 按需:bug 排查 / 测试驱动 |
| Close | `openspec-archive-change` | 归档 |
**按能力绑定,不按路径绑定**:优先用平台原生 skill;不可用时读本地 `SKILL.md` 并按其协议执行;仍不可用时按最小等价协议直接产出文件。**不可用时在 `decision.md` 里注明。**
**不使用 `to-prd`**:它把 PRD 发布到 issue tracker(本仓库没有),且内容与 `proposal.md` + `specs/` 重复。
**不设 `audit` 阶段**:`zoom-out` 保留为按需能力(不熟悉代码区域时拉高视角),但它不是一个必须走的关卡。
### 冲突裁决
被组合的子 skill 与本流程会冲突——这是组合的固有代价。**靠规则裁决,不靠内置。**
> **子 skill 管"这一步怎么做";dev-flow 管"做多少、结果放哪"。**
> **冲突时,流程赢。**
当前组合里,由 dev-flow 覆盖子 skill 默认的有三处:
| 子 skill 的默认 | dev-flow 的覆盖 |
|---|---|
| `grill-with-docs` 要求 relentlessly 追问 | **范围收窄**:只问答案会改变产物的问题 |
| ADR 写入 `docs/adr/`,用 `ADR-FORMAT.md` | **落点改为 `decision.md`**,格式用 `decision-note.md`,**不创建 `docs/adr/`** |
| 假设根目录 `CONTEXT.md` | 用 **`devflow/glossary/CONTEXT.md`** |
**归属规则解决不了的冲突,不要靠内置解决,而是不组合它。**
> 理由:内置只在被组合 skill **消失**时才消除冲突。只要它还装在目录里(用户可以直接调用),
> 内置就只是让 dev-flow 多出一份**会漂移的私有副本**——重复实现加上版本漂移,两个问题。
> `to-prd` 就是这么处理的:直接排除,而不是改造成 dev-flow 的版本。
## Think — 想清楚
**进入**:用户给出需求——粗略想法、issue、草稿、已有 PRD 都算。
**动作**:
1. **澄清** —— 用 `grill-with-docs` 的方法,但按上面的 **「冲突裁决」** 覆盖它的默认:
范围收窄(只问答案会改变产物的问题)、ADR 落点为 `decision.md`、`CONTEXT.md` 用 `devflow/glossary/` 下那份。
**被否决的答案当场记进 `decision.md` 的 `## Alternatives considered`**(一行一条:问过什么、为什么输)——这是 Q&A 形态,见 `references/decision-note.md`)。
2. **读上下文**:`devflow/glossary/CONTEXT.md`,并搜索 `devflow/rejected/` 与已归档的 `decision.md`——
**避免重新提出已经被否决过的方案。**
3. 写 `openspec/changes/<slug>/proposal.md`,并用 OpenSpec 补全 `design.md` / `specs/` / `tasks.md`。
4. **写下 `decision.md` 的 `## Problem` 和 `## Alternatives considered`。**
理由在这一刻最新鲜;留到事后补写会变成回忆录。
**退出**:proposal 能说清做什么、范围、非目标;`decision.md` 有 `## Problem` 和至少一条备选(或用 `<!-- alternatives-not-recorded -->` 显式声明没有)。
**⏸ 确认点 1** —— 向用户汇报方案方向、关键假设、主要风险,然后**等待明确的实现授权**。
> 未获授权不得进入 Build。
> **方案讨论中的任何一次确认,都不等于实现授权。**
> 快节奏交付下可以预授权,但必须显式:Think 退出时在 `decision.md` 写下
> `<!-- pre-authorized: 日期 + 范围/原因 -->`。静默跳过不允许——旁路是有意识的选择,不是遗忘。
> 授权状态以这行标记为准,恢复会话时读它,不靠对话记忆。
## Build — 做出来
**进入**:确认点 1 已过。
**动作**:
- 按 `tasks.md` 的纵向切片实现,按 `specs/` 验收。
- **分步验证**:每完成一层再继续,不要一次写完再验。
- **tasks/design 里提到"参考 XXX 实现"的,实现前先完整读它**——设计文档点名参考而实现时没看,是返工最常见的来源。
- **冲突先分类再处理**:
| 分类 | 处理 |
|---|---|
| 规格不准(遗漏、边界未覆盖、验收口径缺失) | 暂停,修正 OpenSpec,再继续 |
| 代码偏离(实现没按规格做) | 修正代码,不改 OpenSpec |
| 不确定、或涉及设计方向 | **暂停,问用户** |
- 遇到 bug 或行为不明 → 用 `diagnose`;需要测试驱动 → 用 `tdd`。两者都不强制。
**退出**:tasks 完成或剩余已明确记录;已运行验证,或记录了未验证的原因;已知限制已列出。
Build 结束**自动进入 Close**,中间不设确认点。
## Close — 收好尾
**进入**:实现达到可交接状态。
**动作**:
1. **补齐 `decision.md`**——把 `## Decision` 校准为**实际发布的做法**(现在时),补 `## Consequences` 和 `## Verification`。
2. **执行收尾检查**(见下)。
3. 检查澄清阶段的新术语**已**沉淀进 `devflow/glossary/CONTEXT.md`(写入时机在术语确认的当场,见「冲突裁决」;这里只查漏)。
4. 有被否决的提案 → 确认**已在否决发生时**写入 `devflow/rejected/<class>/`(这里只兜底检查)。
**退出**:`decision.md` 五节齐全;收尾检查通过;用户已被询问是否归档。
## 核心规则
| 规则 | 说明 |
|---|---|
| **必须写 `decision.md`** | 每个非平凡变更 |
| **`## Alternatives considered` 强制** | 没有记录"打败了什么"的决策会招来重新争论 |
| **备选是记录的,不是编造的** | 当时没记录就写 `<!-- alternatives-not-recorded -->` |
| **实现前必须有授权** | 确认点 1 |
| **冲突先分类再处理** | 三分法 |
| **一个事实只有一个权威** | 见下表 |
**"非平凡"的判据**:改变行为、架构、跨文件或跨包的契约、流程或工具、测试策略、磁盘/线缆/配置格式,或其他维护者可能重新考察的决策。
**豁免**:纯机械或局部编辑。**小修不值得触发本流程**——dev-flow 是显式触发的 opt-in 流程,轻的第一道防线是不进来;后来发现重要时,允许事后补录 `decision.md`(retrofit 已验证)。
### 事实的唯一权威
| 内容 | 权威 |
|---|---|
| 为什么这么做、放弃了什么、代价 | `decision.md` |
| 实现设计、接口影响 | `design.md` |
| 可观察行为、验收场景 | `specs/` |
| 执行切片与完成状态 | `tasks.md` |
| 跨项目术语 | `devflow/glossary/CONTEXT.md` |
| 未实施的提案 | `devflow/rejected/` |
**任何一句话只能在一个地方是权威。出现第二处,就是错**——两边会各自腐化,而且没人知道以哪边为准。
## 为什么这么轻
这三条是有意为之。**不要"补全"它们。**
1. **义务挂在已有动作上。** 写规划产物的时刻,就是写 `decision.md` 的时刻。不设独立的归档阶段,不做事后提取。
2. **确认点只有两个。** 进入实现、是否归档。不新增。
3. **"是否该写"是判断。** 规则 + 收尾看一眼。机器只校验**已经写下**的东西是否合规,不用脚本强制这件事本身。
## 收尾检查
1. `openspec/changes/<slug>/decision.md` 存在
2. 含 `## Alternatives considered`,或显式的 `<!-- alternatives-not-recorded -->`
3. `## Verification` 里没有"已确认 X 存在"这类**不可重跑的结论**
纯机械改动可以豁免。**豁免必须显式,但可以廉价**——目的是让"跳过"变成有意识的选择,而不是静默遗忘。
> **已落地**:`scripts/check-dev-flow.sh <slug>` 执行上述三项检查;`--index` 扫描归档派生 `devflow/index.md`(不手写);`--all` 检查全部活跃 change。
## 目录
```text
openspec/changes/<slug>/
├── proposal.md design.md specs/ tasks.md
└── decision.md ← 人向:为什么、放弃了什么、代价
↓ 随归档一起冻存
devflow/
├── glossary/CONTEXT.md ← 跨项目术语
├── rejected/<class>/ ← 未实施的提案(否决发生时写入,不是 Close 时)
└── index.md ← scripts/check-dev-flow.sh --index 派生,不手写
```
`rejected/` 的保留条件:它**仍能防止一个诱人的、有意义的错误**。否则整体删除。
**边界**:`decision.md` 的 Alternatives 记"变更内"的方案备选;`rejected/` 收"整个提案被否决"的方向。提案在确认点 1 被整个否决时,当场写入 `rejected/`——那时流程已终止,Close 不会执行。
## 触发规则
- 用户输入 `/dev-flow`。
- 用户明确要求走开发流程。
不要因为任务涉及 OpenSpec、跨模块、架构决策或 devflow 目录就自动触发。
未被这样要求之前,按普通工程任务处理。
**`decision.md` 义务只覆盖经本流程的非平凡变更**——不经 dev-flow 的普通工程任务没有这个义务。
## 相关文档
- `references/phases.md` — 三阶段契约与判断细则
- `references/decision-note.md` — `decision.md` 格式规范、校准案例、反模式
- `skill-workbench/docs/dev-flow/background-and-evolution.md` — 背景、技术演进、设计取舍