feat: rename bugfix-ship/requirement-flow to short-ship/long-ship with shared ship records

short-ship and long-ship share one ship-id record under .pouch/ship/<id>/.
specifier writes PRDs into spec/; delivery-loop appends evidence pointers.
Old names stay as deprecation stubs so existing installs keep working.
This commit is contained in:
2026-10-13 23:11:58 +08:00
parent 93341b3c69
commit af6e139d30
47 changed files with 1497 additions and 222 deletions
+171
View File
@@ -0,0 +1,171 @@
# Ship 记录契约
## 目录
- [布局](#布局)
- [current.yaml](#currentyaml)
- [short 与 long](#short-与-long)
- [任务](#任务)
- [证据指针](#证据指针)
- [旧 specifier 目录](#旧-specifier-目录)
## 布局
```text
.pouch/ship/<ship-id>/
current.yaml # 总账:kind、状态、stopAt、指针
spec.md # 短需求说明(short 和 long 都有)
tasks.yaml # 本 ship 的任务 DAG
status.md # 给人看的一页摘要
spec/ # 仅 long:PRD 版本、评审、handoff
brief.md
prd-v001.html
review.yaml
decisions.yaml
risks.yaml
handoff.yaml # 仅 approved 后
```
`status.md` 给人看;Agent 以 `current.yaml` 为准。两份不一致时改 `status.md`。
## current.yaml
必填:`shipId`、`kind`、`status`、`title`、`spec`、`tasks`、`evidence`。
`shipId` 必须等于目录名。
```yaml
shipId: add-export-button
kind: short
title: 列表页增加导出按钮
status: in_progress
stopAt: review_ready
source:
kind: user
ref: null
parentShipId: null
childShipIds: []
spec:
path: spec.md
revision: null
specStatus: null
prd: null
approvedRevision: null
reviews: null
handoff: null
tasks:
path: tasks.yaml
delivery:
stopAt: review_ready
state: change_ready
evidence:
testRuns: []
artifacts: []
deploys: []
prs: []
commits: []
```
`kind`:`short` | `long`。
`status`:`draft`、`spec_review`、`approved`、`in_progress`、`blocked`、`done`、`parked`、`superseded`。
`delivery.state` 使用 delivery-loop 内部里程碑:`change_ready`、`verified`、
`pr_opened`、`merged`、`regression_passed`、`artifact_built`、`published`、`deployed`。
`source.kind`:`user` | `hunt` | `ack` | `pr` | `feishu`。修 ACK 缺陷时
`source.kind: ack` 且 `ref` 为缺陷任务 id。
## short 与 long
同一套字段,厚度不同。
| 字段 | short | long |
| --- | --- | --- |
| `spec.md` | 四段:要做什么、不做什么、可观察验收、怎么验。有故障证据时加复现和根因 | 同一四段作摘要 |
| `spec/` | 不要创建 | specifier 写入 PRD、评审、决策、风险、handoff |
| `spec.revision` 等 | 保持 `null` | 与 PRD 版本同步 |
| `tasks.yaml` | 恰好 1 条 | DAG;`dependsOn` 指向本文件内 id |
| 子项 | 无 | 默认是 task。只有该切片有独立 `stopAt` 并单独发布时才晋升为子 ship,写入 `childShipIds` |
范围变大时保持同一 `shipId`,把 `kind` 改成 `long`,补 `spec/` 并拆任务。
`spec.md` 不要写成 HTML PRD。long 的评审稿是 `spec/prd-vNNN.html`。
## 任务
`tasks.yaml` 只描述本 ship 的工作项,不是 ACK 缺陷板。
```yaml
shipId: add-export-button
tasks:
- id: T-01
title: 在列表页增加导出按钮
dependsOn: []
expected:
- 登录用户在列表页看到「导出」
verification:
- 浏览器打开列表页,按钮可见且可点
status: open
stopAt: review_ready
```
允许的任务 `status`:`open`、`in_progress`、`blocked`、`verified`、`merged`、`done`。
long 的子任务默认 `stopAt` 为 `pr_opened` 或 `merged`,不要单独打生产 tag 或升级生产。
父 ship 在依赖任务完成后做集成回归,再按父记录的 `delivery.stopAt` 继续。
从 `spec/handoff.yaml` 建任务时复制 `id`、`title`、`dependsOn`、`expected`、
`verification`,不要写进 `.pouch/ack/tasks.yaml`。
## 证据指针
不要把 tester 快照、镜像层或 compose 日志复制进 ship 目录。追加指针:
```yaml
evidence:
testRuns:
- path: .pouch/tester/runs/20261013T031000Z-smoke-ab12.yaml
result: pass
suite: smoke
artifacts:
- sha: 0123456789abcdef0123456789abcdef01234567
digest: sha256:abc
ref: harbor.example.com/app:1.2.3
venue: ci
deploys:
- env: test
revision: 0123456789abcdef0123456789abcdef01234567
health: pass
prs:
- url: https://git.example.com/app/-/merge_requests/12
status: opened
commits:
- sha: 0123456789abcdef0123456789abcdef01234567
role: baseline
```
delivery-loop 阶段与指针:
| 阶段 | 至少追加 |
| --- | --- |
| `change_ready` | `commits` `role: baseline` |
| `verified` | `testRuns` |
| `pr_opened` | `prs` |
| `merged` | `commits` `role: merged` |
| `regression_passed` | `testRuns`(回归) |
| `artifact_built` / `published` | `artifacts` |
| `deployed` | `deploys` |
`path` 相对项目根。文件不存在则校验失败。用 `scripts/append_evidence.py` 追加后立刻
`validate_ship.py`。
## 旧 specifier 目录
打开某个 id 时按这个顺序:
1. `.pouch/ship/<id>/` 已存在:用它。若同时还留着
`.pouch/specifier/features/<id>/`,报告旧路径为遗留,不要两处同时写。
2. 只有 `.pouch/specifier/features/<id>/`:把它移到 `.pouch/ship/<id>/spec/`,按旧
`current.yaml` 生成 ship `current.yaml`(`kind: long`),用 `brief.md` 补
`spec.md` 摘要,再校验。
3. 两处都没有:由入口 skill 调用 `create_ship.py` 新建。