speckit 实践:用 Patch 机制管理 Spec 变更(1)

用 Patch 机制管理 Spec 变更

对于已简化成线性流程的项目:

spec → plan → 实施 → review

其实可以进一步演化成带 Patch 回路的闭环流程:

spec → plan → 实施 → review → patch → review → patch → review → skill

其中 patch 并不需要单独文件,而是直接追加到 spec.mdplan.md

核心原则:已确认的 spec 内容原则上不直接修改。新增需求、遗漏需求、review 发现的问题,都以 Patch 形式追加,保证可追溯性(traceability)。


1. 核心理念

线性流程 spec → plan → 实施 → review 演化为带 Patch 回路的闭环:

spec → plan → 实施 → review ↻ (patch → review) → skill
  • Patch 不单独建文件,直接追加到 spec.mdplan.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"requiredplaceholder="请选择年份",宽度 !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} 条数据,并刷新列表
    • 失败时提示 本年度数据已存在

MonitorManageApisrc/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. 新增 computedexpiringSoonCount / 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 通过。

posted @ 2026-06-29 14:53  bleemyoung  阅读(3)  评论(0)    收藏  举报