
# 追踪

追踪把一项工作从报告一路跟到发布。它把 Acahti 已有的记录串起来：工单和待办，关联到它们的 PR、流水线、Argos 运行和文档，所属迭代、迭代的交付及其标签流水线。失败的 Argos 用例也以同样方式跟踪，从首次失败的运行一直到修复发布。

## 阶段

追踪共有八个阶段，顺序如下：

| 阶段 | 依据 |
|---|---|
| 提交 | 创建了工单；从 Argos 运行发起的工单还会显示该运行 |
| 规划 | 创建了待办，或迭代已规划；关联文档显示在这里 |
| 进行中 | 有待办处于进行中或受阻；所有有效待办都完成后即完成 |
| 评审 | 关联的 PR 已打开、已合并，或未合并即关闭（失败） |
| 构建 | 关联的流水线正在运行、已通过或失败 |
| Argos | 关联的 Argos 运行正在运行、已通过或失败 |
| 交付 | 迭代的交付及其标签流水线 |
| 发布 | 迭代已发布，或工单已关闭或待验证 |

一个流程不会展示全部八个阶段。它按所属类型的模板展示阶段，另外也展示其他有依据的阶段，所以关联到运维待办的 PR 仍会出现在「评审」下：

| 类型 | 跟踪对象 | 内置阶段 |
|---|---|---|
| `bug` | 缺陷类工单 | 提交、分诊（规划）、修复中（进行中）、评审、构建、验证（Argos）、发布 |
| `feature` | 需求类工单 | 提交、规划、进行中、评审、构建、交付、发布 |
| `todo` | 待办 | 规划、进行中、评审、构建、交付、发布 |
| `ops` | 运维项目的待办、杂务类工单 | 规划、进行中 |
| `argos_case` | Argos 用例 | 失败（提交）、已建单（规划）、修复中（进行中）、重新通过（Argos） |
| `iteration` | 迭代和交付 | 规划、进行中、评审、构建、Argos、交付、发布 |

Work 管理员可以修改某个类型的模板：它需要哪些阶段，以及（如有需要）用来替换阶段名称的标签。阶段始终按上面的顺序排列。单个流程在实际情况不同时可以调整：改用其他类型的模板、增加阶段或跳过阶段（被跳过的阶段即使有依据也保持隐藏，其记录仍保留在流程上）。Work 管理员可以调整任何流程；待办或工单的负责人、代理人或创建人，以及迭代的负责人，可以调整自己的流程。

每个阶段处于**已完成**、**当前**、**未开始**、**失败**或**已跳过**状态。当前阶段取最靠后的失败阶段；没有则取最靠后的活动阶段；再没有则取最靠后的已完成阶段的下一个。之前没有依据的阶段记为跳过，已取消的流程会跳过它从未到达的阶段。未完成的流程会报告 `stuck_since`，即它最后一次状态变化的时间。

## 跟踪单个事项

待办和工单页面会显示「追踪」卡片：先是阶段轨道，然后是每个阶段的时间线，包括何时到达、由谁推进、耗时多久（或流程已在此停留多久），以及背后的 PR、流水线、Argos 运行、交付和其他记录，每条都链接到对应页面。卡片标明流程的类型，并标记已调整的流程。迭代页面显示阶段轨道；交付显示它自己的流程。Argos 用例的流程显示在 Argos 用例视图（`/argos/cases?case=<case id>`）中。流程遵循查看者的权限：仓库对象遵循仓库可见性，受限文档保持隐藏，所有成员都能看到 Argos 运行。

PR 页面显示它自己的生命周期：打开、检查、可合并，然后合并或关闭。

## 查看所有未关闭的流程

在顶栏打开「追踪」。三个视图列出未关闭的流程；当前视图保存在页面地址中（`/track?view=tickets`）：

| 视图 | 列出内容 | 分组方式 | 筛选条件 |
|---|---|---|---|
| 工作 | 未关闭的待办，以及没有待办承接的未关闭工单 | 项目 | 项目、类型、负责人、停滞 |
| 工单 | 所有未关闭的工单，包括已有待办承接的工单，以及在关闭前处于待验证的工单 | 项目 | 项目、类型、负责人、停滞 |
| Argos | 当前失败，或在最近 14 天内失败后重新通过的 Argos 用例 | Pack 和分组 | Pack、分组、环境、负责人、停滞 |

在表格的列标题上按类型和负责人筛选。每行按其类型模板和调整结果显示自己的阶段。阶段汇总按当前阶段统计流程数；选择一个阶段即只显示这些流程。可按标题搜索。超过三天没有活动的流程会显示已停滞多久。选择一行即打开对应的待办或工单页面，或 Argos 用例视图。无法读取 Argos 时，Argos 视图会给出提示。

## 跟踪单个人员

「人员」视图（`/track?view=people&login=wei&days=7`）显示某个人在最近 7、14 或 30 天里做了什么：推进的待办和工单、登记的工时、交付、推送的提交、打开和合并的 PR、评审、标签，以及运行、失败和修复的流水线（同一分支上失败之后的一次通过运行）。先列出各项计数，然后是按项目和仓库分列的同样计数，最后是链接到每条记录的时间线。Work 事件来自 Work；PR、推送、评审和标签来自以你的身份读取的此人的仓库活动（因此私有仓库保持隐藏）；流水线来自 Acahti 的流水线索引。你可以查看自己的活动；Work 管理员可以查看任何人的活动。

流程已经会收集仓库依据：PR（标题、正文或源分支）或流水线（提交信息、分支或 PR 标题）中提到某个待办或工单（`todo#123`、`ticket#45`、`todo-123`、`todo/123`、`ticket/45`、`T-123`）时，就会关联到它；交付的标签流水线显示在「交付」下。

## Argos 用例

用例的流程从内置 Argos 读取：它的最新结果、近期失败的结果及其所属运行，以及从该用例发起的工单（按用例，或按它的某次失败运行）和承接这些工单的待办。

| 阶段 | 依据 |
|---|---|
| 提交 | 最近 14 天内看到的首次失败运行，以及该用例 |
| 规划 | 从该用例发起的工单，以及承接它的待办 |
| 进行中、评审、构建 | 这些待办及其 PR 和流水线，与任何待办相同 |
| Argos | 修复已规划后该用例的最新结果：失败，或通过后即完成 |
| 交付、发布 | 这些待办所属的迭代和交付；工单已关闭或待验证 |

在工单创建之前出现的失败只是重复报告，因此没有工单的失败用例会停在「规划」。用例重新通过且没有未关闭的工单或待办时，流程在「Argos」结束。失败记录取自 Argos 总览，它保留最新的 50 条失败结果。

![合成示例工作区中的追踪](/images/track.png)

## 关联 PR、流水线和运行

在 PR 的标题、正文或源分支中，或在提交信息中提到某个待办或工单，PR 事件或流水线到达时 Acahti 就会关联它。引用不区分大小写，可以跟在 `fixes`、`closes` 或 `refs` 之后：`todo#123` 和 `ticket#45` 可出现在任何位置，分支形式为 `todo-123`、`todo/123`、`ticket-45` 和 `ticket/45`，`T-123` 表示待办。单独的 `#123` 是 PR 编号，不会被读取。只关联存在的待办和未归档的工单，每个只关联一次。

要手动关联，把 PR、流水线或 Argos 运行的 URL 粘贴到待办的「关联工作」中。Agent 使用 `planning_todo_links`：`pull` 和 `pipeline` 的 `to_key` 为 `owner/repo#n`，`argos` 使用运行 id。你必须能读取对应的仓库或运行。替换待办的工单和文档关联时，这些关联会保留。

## Agent 访问

```bash
acahti mcp call track_get '{"type":"todo","id":"123"}'
acahti mcp call track_list '{"view":"tickets","project":"turbomesh","stuck_days":7}'
acahti mcp call planning_todo_links '{"id":123,"revision":4,"add":[{"to_type":"pull","to_key":"acme/api#42"}]}'
acahti mcp call track_template_list '{}'
acahti mcp call track_template_update '{"type":"bug","stages":[{"key":"reported"},{"key":"planned","label":"Triaged"},{"key":"in_progress"},{"key":"review"},{"key":"released"}]}'
acahti mcp call track_flow_update '{"type":"todo","id":"123","skip":["review","build"]}'
acahti mcp call track_activity '{"login":"wei","days":7}'
```

```bash
acahti track list --view tickets --project turbomesh --stuck-days 7
acahti track list --view argos
acahti track view ticket 45
acahti track view argos_case nebula.upload
acahti track templates
acahti track template set bug --stages reported,planned=Triaged,in_progress,review,released
acahti track template reset bug
acahti track flow todo 123 --skip review,build
acahti track flow todo 123 --clear
acahti track activity --login wei --days 7
```

`track_get`（`GET /work/track/{type}/{id}`）接收 `type`（`ticket`、`todo`、`iteration`、`delivery` 或 `argos_case`）和字符串 `id`：记录编号，或 Argos 用例 id。它返回根对象（`kind`、字符串 `id`、`title`、`url`）、其 `type`、已调整时的 `override`（`template`、`add`、`skip`、`updated_by`、`updated_at`）、流程的各阶段（`key`、模板重命名时的 `label`、`state`、`at`、`actor`、`nodes`）、关联的节点和边、当前阶段以及 `stuck_since`。`track_list`（`GET /work/track`）接收 `view`（`work`、`tickets` 或 `argos`）、`project` 和 `owner`（work 和 tickets）、`pack`、`group` 和 `env`（argos）、`stuck_days`、`page` 和 `page_size`。它返回 `items`、`total` 和 `unavailable`，后者在无法读取 Argos 时包含 `argos`。每个条目包含其根对象、`type`、`group`（`id` 和 `name`：项目，或用例的 pack 和分组）、`owner`、各阶段状态、`current` 和 `stuck_since`；Argos 条目额外包含 `argos`，其中有 `pack`、`group`、`env` 和最新的 `status`；根对象的 `url` 是它的页面（Argos 用例为 `/argos/cases?case=<id>`）。浏览器通过 `/ui/track` 和 `/ui/track/{type}/{id}` 读取同样的操作。

`track_template_list`（`GET /work/track-templates`）返回每个类型的 `stages`、它的 `builtin` 阶段、`customized`，以及 `stage_keys` 和每个阶段读取的依据。`track_template_update`（`PUT /work/track-templates/{type}`）替换某个类型的阶段，`track_template_reset`（`DELETE`）恢复内置阶段；两者都需要 Work 管理员。`track_flow_update`（`PUT /work/track/{type}/{id}/flow`）接收 `template`、`add` 和 `skip`，替换该流程之前的调整（三者都不传则清除调整），并返回该流程。Aidy 等 Agent 通过这些操作修改模板和流程。

`track_activity`（`GET /work/track/activity`）接收 `login`（默认为你）、`days`（1 到 31，默认 7）和 `until`（`YYYY-MM-DD`，默认今天，Asia/Shanghai），以及 `page` 和 `page_size`。它返回 `login`、`since`、`until`、`counts`（`todos`、`tickets`、`minutes`、`deliveries`、`commits`、`pulls_opened`、`pulls_merged`、`reviews`、`tags`、`pipelines`、`pipelines_failed`、`pipelines_fixed`）、`groups`（按项目或仓库：`kind`、`id`、`name`、`counts`、`total`）、当前页的 `items`（`at`、`kind`、`action`、`ref`、`title`、`url`、`project` 或 `repo`、`status`、`count`、`minutes`）、`total`、`has_more` 和 `unavailable`（无法读取仓库活动时为 `repos`）。
