speckit 实践:用 Patch 机制管理 Spec 变更(1)
用 Patch 机制管理 Spec 变更
对于已简化成线性流程的项目:
spec → plan → 实施 → review
其实可以进一步演化成带 Patch 回路的闭环流程:
spec → plan → 实施 → review → patch → review → patch → review → skill
其中 patch 并不需要单独文件,而是直接追加到 spec.md 和 plan.md。
核心原则:已确认的 spec 内容原则上不直接修改。新增需求、遗漏需求、review 发现的问题,都以 Patch 形式追加,保证可追溯性(traceability)。
1. 核心理念
线性流程 spec → plan → 实施 → review 演化为带 Patch 回路的闭环:
spec → plan → 实施 → review ↻ (patch → review) → skill
- Patch 不单独建文件,直接追加到
spec.md和plan.md。 - 已确认的 spec 不直接改;新增 / 遗漏 / review 发现的问题,以 Patch 形式追加,保证可追溯性(traceability)。
2. 固化规则
这些规则可以写进全局规则 / Prompt,让 Agent 在执行时自动遵守。
需求变更规则
需求变更规则:
1. 已确认的 spec 内容原则上不直接修改。
2. 新增需求、遗漏需求、review 发现的问题,以 Patch 形式追加。
3. 同步更新 plan 的 Patch。
4. Patch 必须说明:
- 新增内容
- 原因
- 实施方案
5. 实施完成后重新进行 review。
Agent 执行提示词
如果在实施或 review 过程中发现遗漏:
1. 不直接修改已有 spec 内容。
2. 在 spec.md 追加:
## Patch N
3. 在 plan.md 追加:
## Patch N
4. 根据 Patch 实施代码修改。
5. 重新 review。
Patch 应记录:
- 新增需求
- 发现原因
- 实施方案
3. 推荐目录结构
推荐最终形成这种结构,每个需求一组文件:
specs/
└── 001-login/
├── spec.md
├── plan.md
├── review.md
└── skill.md
其中 spec / plan 内部各自维护 Requirements / Design 与 Patch 段落:
spec
├── Requirements
├── Patch 1
├── Patch 2
plan
├── Design
├── Patch 1
├── Patch 2
4. Patch 模板骨架
下面两侧模板可直接复制填空。
spec.md Patch 模板(WHAT 层)
## Patch
### 补充修改(YYYY-MM-DD)
#### PC-NNN:<变更标题>
`<页面/组件路径>` MUST <需求行为>:
- <新增内容 1>
- <新增内容 2>
- <校验规则 / API 字段 / 默认值 / 边界行为 等>
> 相关 Plan 实施步骤:<plan 链接>
plan.md Patch 模板(HOW 层)
### Patch YYYY-MM-DD: spec PC-NNN 实施步骤 **[DONE]**
> 本 Patch 对应 `spec.md` 的 `## Patch` 中 PC-NNN(<标题>),覆盖 <实施范围>。
#### PC-NNN-A:<实施分组标题>
NN. 在 `<文件路径>` <位置> <做什么>
- <位置说明 / 组件属性 / computed 属性 / 事件处理 等>
- <顺序/依赖说明>
#### PC-NNN-B:补充验证项
NN. 验证 <功能点>
- <验证项 1>
- <pnpm ts:check / pnpm build:local 通过 等>
5. 简单改造:先上车后补票
不是所有改动都要从头走完整 spec 流程。代码先行、回头补 Patch 完全合理——没必要为了加个 year picker 就走一遍 spec → plan → 实施。
场景对照
| 场景 | 推荐方式 |
|---|---|
| 小修小补(加/删字段、隐藏列、调样式) | 代码先行,回头补 Patch |
| 涉及范围/接口契约/交互流程变更 | 先走 spec → plan → 实施 |
| 不确定影响面的改动 | 先补 spec,对齐后再实施 |
WHAT vs HOW:什么时候只补 spec
- spec.md 记的是 需求/行为(WHAT)——年份可筛选、6 列隐藏,这些是需求契约。
- plan.md 记的是 实施步骤(HOW)——步骤 38 在哪个位置插代码、用什么组件属性,这些是给 AI 或新人看的执行指引。
简单改造的 "HOW" 一目了然(加个 date-picker、注释几行),plan 里再写一遍纯粹是重复劳动。只有涉及多文件联动、状态管理变更、交互逻辑复杂度高的 Patch 才有必要补 plan。这类小改动只补 spec 的 Patch 段落即可。
真实案例:PC-006/007/008(纯 spec 补录)
下面是 spec.md 中 ## Patch → ### 补充修改(2026-06-29) 下的真实写法,展示一个 Patch 段落并列多个变更点。这组正是「先上车后补票」的典型:代码先改完,回头只在 spec 补录 WHAT,不附 plan。
PC-006:管理视图新增「年份」搜索条件
管理视图(monitorManage/index.vue)MUST 在搜索区新增 年份 筛选条件:
- 使用
el-date-picker组件,type="year",prop="year",required,placeholder="请选择年份",宽度!w-240px - 年份字段 MUST 为必填筛选条件,表单校验规则为
[{ required: true, message: '请选择年份', trigger: 'change' }] - 默认值为当前年份(
new Date()),查询和导出时转换为YYYY字符串(getFullYear().toString())传给接口 - API 请求类型
MonitorManagePageReqVO新增year?: string字段 年份筛选参与列表查询和导出,与其他筛选条件联动
PC-007:管理视图表格隐藏设备相关字段列
管理视图(monitorManage/index.vue)表格 MUST 隐藏以下 6 个字段列,只保留注释代码:
设备型号(deviceModel)安装位置(installLocation)检测频次(detectFrequency)准确度等级(accuracyLevel)检定频次(verificationFrequency)检定类型(verificationType)
这些字段的列定义保留为注释,以便后续需要时恢复。表格仅展示:工序、参数类别、排放源、设施名称、记录频次、数据缺少处理、负责部门、说明和操作列。
PC-008:管理视图新增「沿用上一年度」按钮与 mock API
管理视图(monitorManage/index.vue)MUST 在操作按钮区新增 沿用上一年度 按钮:
- 按钮位置:操作按钮区最左侧,
新增排放源按钮之前 - 按钮样式:
type="primary" plain,使用ep:plus图标 - 权限标识:
carbon:monitor-manage:copy_last_year - 点击行为:
- 先弹出确认弹窗,文案
确认沿用上一年度数据? - 确认后调用 mock API
copyLastYear({ year }) - 成功时提示
沿用成功,共复制 {copiedCount} 条数据,并刷新列表 - 失败时提示
本年度数据已存在
- 先弹出确认弹窗,文案
MonitorManageApi(src/api/carbon/monitorManage/index.ts)MUST 新增 mock 函数 copyLastYear(params: { year: string }): Promise<{ copiedCount: number }>:
- 深拷贝当前内存
records中所有记录,分配新的自增 ID,追加到数组头部 - 返回
{ copiedCount }表示复制条数 - mock 阶段直接抛出
Error('沿用上一年度失败,请稍后重试'),用于测试错误路径(正式联调时替换为真实接口调用)
与下一节复杂案例的互补关系
本节是「小改动只补 spec」的特例;下一节 PC-005 则是「复杂变更需补 plan」的对照。两者互补,不冲突——判断依据是改动范围与交互复杂度。
核心原则:spec 最终要反映真实实现。顺序可以灵活,但 traceability(可追溯性)不能丢。
6. 真实主对照案例:PC-005(spec ↔ plan 同变更)
与上一节「小改动只补 spec」相对,这里是需要补 plan 的复杂变更:同一变更(PC-005)在 spec 与 plan 两端都有写法,形成 WHAT ↔ HOW 双向对照。
教学点——双向交叉引用约定:两端各写一句指向对方的引用构成闭环:spec 末尾写
> 相关 Plan 实施步骤:[plan.md#...]指向 plan;plan 开头写本 Patch 对应 spec.md 的 ## Patch 中 PC-005反向指向 spec。
A. spec.md Patch(WHAT 层)— PC-005:计量器具台账状态统计入口
meterLedger/index.vue MUST 在操作按钮区与表格之间增加 即将到期(30天内)、已过期 两张状态统计入口卡:
- 语义:
即将到期用 warning 色,已过期用 danger 色;数字取全局 mock 统计,不受其他筛选影响。 - 交互:点击卡片 →
status置为对应值 + 重置第 1 页 + 刷新;再次点同一卡不取消,换卡替换不叠加;通过「重置」清空筛选。 - 边界:仅 mock 快筛,不定义真实 API contract;统计数字始终为全局总数。
相关 Plan 实施步骤:plan.md#patch-2026-06-26-spec-pc-005-实施步骤
B. plan.md Patch(HOW 层)— Patch 2026-06-26: spec PC-005 实施步骤 [DONE]
本 Patch 对应
spec.md的## Patch中 PC-005(计量器具台账状态统计入口),覆盖在表格上方增加两张状态统计入口卡片的实施。
PC-005-A:实现 UI 与交互(步骤 33–36)
- 33. 模板插入卡片区:位于操作按钮区与表格
ContentWrap之间,div水平排列两张卡;warning/danger 语义背景,左侧数字右侧文字,cursor: pointer+ hover;激活态加深边框。 - 34. 新增 computed:
expiringSoonCount/expiredCount从全量 mock 过滤计数;activeStatusFilter判断激活态;统计数字不受其他筛选影响。 - 35. 事件
handleStatusFilterClick(status):同 status 不操作,否则设searchForm.status+ 重置pageNo=1+getList();重置按钮清空 status。 - 36. 全量数据源:
src/api/carbon/meterLedger/index.ts新增getAllMeterLedgerRecords()返回全量 mock 数组。
PC-005-B:补充验证项(步骤 37)— 两卡片显示全局统计数;点击后列表按 status 过滤且回第 1 页;激活态视觉反馈;同卡再点不变、换卡替换;重置清空;数字不受其他筛选影响;pnpm ts:check / pnpm build:local 通过。

浙公网安备 33010602011771号