# Ship 记录契约 ## 目录 - [布局](#布局) - [current.yaml](#currentyaml) - [short 与 long](#short-与-long) - [任务](#任务) - [证据指针](#证据指针) - [旧 specifier 目录](#旧-specifier-目录) ## 布局 ```text .pouch/ship// current.yaml # 总账:kind、状态、stopAt、指针 spec.md # 短需求说明(short 和 long 都有) tasks.yaml # 本 ship 的任务 DAG status.md # 给人看的一页摘要 1-spec/ # 规格、评审、根因和 handoff 2-develop/ # 开发任务和变更 3-test/ # 任务验证与集成回归 4-review/ # PR、审核与合并 5-build/ # 合并后的构建/obtain 6-publish/ # 发布产物 7-deploy/ # 部署与健康检查 stage.yaml # 阶段状态和包含的步骤 activity.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`。 阶段目录由 `create_ship.py` 初始化,由 `next_step.py` 在派发和收到结果时追加活动记录; 大日志留在原测试、构建或部署位置,阶段目录只保存摘要和路径。 新建 ship 使用可排序的 `YYYYMMDD-短语`,例如 `20261014-dynamic-editor`。旧的无日期 记录仍可读取和校验,不要为了改名移动既有 ship 目录。 ## 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 manager: lastStep: null lastResult: null inFlight: null 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。 `manager` 由入口主会话维护,可选。`lastStep` / `lastResult` / `lastSummary` 记录刚结束的那一步; `inFlight` 在 worker 未返回时写成步骤名,返回后清掉。worker 不要写这些字段。 `lastResult`:`pass` | `fail` | `blocked` | `ask`。 ## 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//` 已存在:用它。若同时还留着 `.pouch/specifier/features//`,报告旧路径为遗留,不要两处同时写。 2. 只有 `.pouch/specifier/features//`:把它移到 `.pouch/ship//spec/`,按旧 `current.yaml` 生成 ship `current.yaml`(`kind: long`),用 `brief.md` 补 `spec.md` 摘要,再校验。 3. 两处都没有:由入口 skill 调用 `create_ship.py` 新建。