
# 产品迭代

迭代属于某个 product 或 ops 项目，位于 `/projects/<id>/iterations`。创建迭代时需指定不可变的 `X.Y` 系列。项目与版本的组合唯一。项目定义其仓库清单。

每个待办带有一个 `iteration_id`。批量移动要求属于同一个项目，并提供待办的当前修订号和请求键。批量移动会原子地更新归属关系，并在两个迭代上都保留历史。已发布或已取消的迭代不能再接收工作。项目进度不计入已关闭的待办，但计入已完成的待办。迭代进度计入当前所有成员，包括已关闭和已完成的工作。

![合成示例工作区中的迭代](/images/iteration.png "一个迭代：日程、追踪阶段、燃起图，以及负载与容量。")

## 范围

迭代依次经过规划中、进行中，最后是已发布或已取消。第一次变为进行中时会记录 `started_at`：此时包含的待办就是它的基线。之后加入的待办，无论是在迭代中新建还是移入，都属于**计划外**（待办上的 `out_of_plan`，`todo_list out_of_plan=true`），并记录由谁添加、何时添加，以及可选的 `iteration_reason` 或移动的 `reason`。离开已开始迭代的待办会被记为移除。开始之前的归属变化属于规划，不会在范围中留下记录。计划外工作不需要任何人批准，其作用是让范围变化可见。

在 Web 应用中，迭代页在其他计数旁显示「计划外」（点击打开筛选后的列表），「范围变更」列出基线、当前范围、新增和移除，以及由谁、何时、为何变更。

## 关闭

`iteration_update` 不会发布或取消迭代，`iteration_close` 才会。它需要当前修订号和请求键，并且迭代中每个未完成的待办（需求、待办、进行中或受阻，且未关闭）都需要一个去向：`move` 到项目的另一个未关闭迭代、`unplan`，或附带原因 `keep`。这些去向与状态变更一起提交；发布时不会遗留去向不明的未完成工作。Aidy 会把去向提议为一次 `iteration_close`，由你确认。

在迭代页上，「发布」和「取消迭代」会打开同一个关闭界面：列出每个未完成的待办及其去向（默认为下一个未关闭的迭代，也可以「退回未规划」，或附带原因「留在本迭代」），可以逐条设置或一次全部设置；「让 Aidy 提议」则交给 Aidy 处理。「编辑迭代」 的状态菜单只提供规划中、进行中和受阻。

没有交付的已取消迭代可以删除（使用 `iteration_delete` 并传入当前修订号），可由其负责人、创建者、项目负责人和成员或 Work 管理员执行。其待办留在项目中，变为未规划，项目历史会记录谁在何时删除了哪个版本。

## 简报

`planning_brief` 通过一次读取度量一个项目及其当前迭代（或指定迭代）：状态计数；风险（逾期、受阻、截止日被推后两次及以上）；本周完成情况和已记录工时；每位指派人的未完成待办和预估分钟数，对比迭代截止日前剩余的工作日（每天 480 分钟）；未预估的待办和没有记录工时的已完成待办；迭代的基线、当前范围以及开始以来的每一次变更；以及按天的燃尽数据，以待办数和预估分钟数统计范围和剩余工作，根据范围变化和完成时间回放得出。项目页和迭代页会绘制这些数据，Aidy 也据此撰写进展汇报（迭代页上的「问 Aidy」）。「负载与容量」会把预估未完成工作超过剩余工作日的指派人标红。

```bash
acahti iteration create --body-file iteration.json
# {"project_id":"turbomesh","version":"1.4","title":"Autumn delivery","owner":"alice"}
acahti mcp call planning_move_todos '{"items":[{"id":42,"revision":3}],"iteration_id":12,"request_key":"move-42-12"}'
acahti iteration close 12 --body-file close.json
# {"revision":4,"status":"released","request_key":"release-1.4","carry":[{"todo_id":43,"action":"move","iteration_id":13}]}
acahti mcp call planning_brief '{"project":"turbomesh"}'
acahti delivery draft --iteration 12
acahti delivery submit --body-file delivery.json
acahti delivery list --iteration 12
acahti delivery view 7
acahti delivery retry 7
```

交付的输入包含 `iteration_id`、`request_key`、`summary`、`changelog`、`todo_ids` 和 `repositories`。交付至少要列出其所交付迭代中的一个待办；没有待办的工作无法交付。`delivery_draft` 列出迭代的待办，已完成的排在前面，并标出已被之前交付包含的待办，同时为每个选中的待办起草一行变更日志（默认选中尚未交付的已完成待办）。交付会列出其包含的待办，`todo_get` 会列出一个待办所属的交付。在「提交交付」中勾选待办；变更日志草稿会随选择更新，直到你手动编辑为止，「让 Aidy 起草」会请 Aidy 生成按功能和修复分组的变更日志。待办页会显示交付了它的版本。项目中的每个仓库都要提供 `name`、完整的提交 `sha`、`branch` 和 `changed`。未变更的仓库还需提供与该 SHA 匹配的现有 `tag`。有变更的仓库会获得同一个新的 `vX.Y.Z` 标签。在分配版本之前，会校验仓库写权限、分支和提交是否存在、未变更仓库的标签，以及提交能否从所选分支到达。现有标签永远不会被移动。

项目在事务中分配 Z，从 1 开始。交付的清单、版本、执行者和变更日志都不可变。重放相同的请求会返回同一个交付；要更改其内容，需要使用新的请求键。分配后失败的版本会被保留。重试会沿用相同的标签和版本。持久化的恢复任务会对中断的分发最多重试五次；之后仍可显式重试。发布标签会触发各仓库现有的标签流水线。部分分发的情况会连同错误和仓库证据一起显示。把迭代标记为已发布并不会部署它。

交付时间线显示变更日志，以及按仓库、标签 ref 和提交 SHA 精确匹配的流水线结果。分发步骤表示标签已发布；流水线成功单独显示，绝不会从分发结果推断。迭代页和每个交付也会显示各自的[追踪](track.md)流程。

Agent 与浏览器使用同一套 REST/MCP 服务。结构化执行步骤（`planning_run_step`、`planning_run_steps`）包含父级关系、依赖、证据、尝试次数和乐观锁修订号。循环依赖和缺失的引用会被拒绝。Trace 和只读的 DAG 视图渲染的正是这些步骤。Aidy 也可以起草和更新迭代；每次写入都需要你确认。

`iteration_list` 使用 `state=current` 时列出未结束的迭代（规划中、进行中或受阻）。没有迭代的待办通过普通的移动命令进行规划。
