Files
obsidian-vault/output/研究文章/Trellis × 飞书实现闭环初步方案.md
T
2026-08-31 09:21:12 +08:00

764 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Trellis × 飞书实现闭环初步方案
> 状态:V1 两个全局 skill 已实现并完成本地结构、契约 fixture 与独立前向验证;真实 Base POC 尚未运行
> 更新时间:2026-07-26
> 范围:只讨论“如何发现待实现工作、如何在 Inline / Trellis 之间路由、如何在完成后回写飞书”;不展开具体 coding 规则。
> 证据分层:文中明确区分「Trellis 官方文档事实」、「现有 Matt 文档提取」和「本文推导 / 推荐」。
> 版本注意:本机 `trellis --version` 已核对为 `0.6.8`,本次在线文档导航显示 `0.6.9`。两者在个别配置名称 / 默认值上可能有差异;真实项目 POC 必须以目标项目实际生成的 `.trellis/` 文件、本地脚本和安装版本为准。
## 1. 结论先行
目前已确认把实现侧闭环定义为:
1. **飞书 Base 管“待做什么、由谁做、依赖谁、当前业务状态”**,是 Spec / Ticket 队列和对外状态的事实源。
2. **Trellis 管复杂工作的本地执行上下文**:任务、PRD、技术设计、实施计划、检查上下文、归档和 journal。
3. **repo 管实现与验证事实**:代码、测试、ADR、差异和可回放的验证结果。
4. **普通小功能继续 Inline**,不为了状态同步强行创建 Trellis 任务;**复杂功能严格使用“1 Spec = 1 Trellis task”**,Ticket 只作为该 task 内可刷新的实施计划和验收单元,不再映射为 Trellis child task。
5. 已实现两个职责分离的全局显式 skill:
- **`start-work-feishu`**:识别当前飞书用户,列出其负责的 Spec / Ticket,让用户选择,然后路由到 Inline 或 Trellis。
- **`close-work-feishu`**:承担“部分收口、最终收口、对账重放”。它按 Spec 查找全部子 Tickets,分析可收口项并交给用户 review / 确认;只有被确认的 Tickets 或 Spec 才写入 `已完成`。
6. **Trellis 路径的 Spec 最终收口必须以归档事件为准,不能以 `finish` 事件为准**。官方明确:`after_finish` 只表示当前 session 解除任务指针,任务可能仍在其他 session 继续;外部系统 done 应接 `after_archive`。Ticket 的部分收口可提前进行,但不得因此关闭 Spec。[官方:架构全景](https://docs.trytrellis.app/zh/advanced/architecture)
7. **不把 lifecycle hook 当成唯一保障**。官方规定 hook 失败只警告、不阻断主任务操作;因此必须由显式 close skill 完成飞书写入与回读。本方案中 hook 至多记录可重放的 pending / outbox 事件。[官方:`config.yaml` 配置](https://docs.trytrellis.app/zh/advanced/configuration)
8. **所有完成态都以人类 review 为必要门禁**。Agent 可以分析哪些 Ticket 已满足验收,但不能自行将它们或父 Spec 置为 `已完成`。
## 2. 本文如何区分事实与方案
| 标签 | 含义 | 能否当成已存在能力 |
|---|---|---|
| **[官方事实]** | 来自用户给出的 5 篇 Trellis 官方文档 | 可,但仍应以项目当前生成文件和安装版本为准 |
| **[Matt 提取]** | 来自已完成的《Matt 工作流 × 飞书 CLI 全流程总结》 | 可作为当前飞书 POC 和工作流合约 |
| **[推导 / 推荐]** | 基于上述事实对新闭环的设计 | 未标记实现时不能当成已有能力 |
| **[V1 已实现]** | 已写入全局 skill 并完成本地验证的合约 | 可用于 fixture;真实 Base 能力仍需目标项目 POC |
本文不会把本方案的 skill、字段、任务元数据或 CLI 语法误写成 Trellis 内置能力。
## 3. Trellis 官方文档事实整理
### 3.1 定位与事实源
**[官方事实]** Trellis 将自己定位为“Team-level Agent Harness with built-in LLM wiki”:
- Agent Harness 管 workflow state、hook、skill、sub-agent 和平台适配。
- LLM wiki 把 spec、task、research、journal 放在仓库文件里。
- workflow、spec、task 受 Git 跟踪;workspace memory 按 developer 隔离。
- 它的核心思路是把 AI coding 当成“工作流 + 知识管理”,而不是一次性聊天。
来源:[官方:架构全景](https://docs.trytrellis.app/zh/advanced/architecture)
Trellis 本地内容的职责边界如下:
| 内容 | 位置 | 职责 |
|---|---|---|
| Workflow 合约 | `.trellis/workflow.md` | Plan → Execute → Finish、skill 路由和每轮 next action |
| 团队稳定规范 | `.trellis/spec/` | 可跨任务复用的团队知识 |
| 任务事实 | `.trellis/tasks/<task>/` | PRD、设计、实施计划、research、实现 / 检查 context manifest |
| 开发者记忆 | `.trellis/workspace/<developer>/` | 开发者 journal 和索引 |
| 当前任务指针 | `.trellis/.runtime/sessions/<session-key>.json` | 把一个 AI session / 窗口指向一个任务 |
来源:[官方:架构全景](https://docs.trytrellis.app/zh/advanced/architecture)
### 3.2 任务结构和上下文加载
**[官方事实]** 典型任务目录包含:
```text
.trellis/tasks/<task>/
├── task.json
├── prd.md
├── design.md
├── implement.md
├── implement.jsonl
├── check.jsonl
└── research/
```
- `task.json` 承载状态、优先级、负责人、分支、PR URL、父子关系和扩展元数据。
- `prd.md` 承载需求、约束、验收标准和 out-of-scope。
- 复杂任务使用 `design.md` 和 `implement.md`。
- `implement.jsonl` / `check.jsonl` 分别列实现与检查所需的 spec / research 文件。
- 实现 / 检查的标准读取顺序是“JSONL entries → `prd.md` → 可选 `design.md` → 可选 `implement.md`”。
来源:[官方:架构全景](https://docs.trytrellis.app/zh/advanced/architecture)
### 3.3 任务状态与生命周期
**[官方事实]** 默认状态是:
```mermaid
flowchart LR
NoTask["no_task\n当前 session 无 active task"] -->|create| Planning["planning\n需求与规划"]
Planning -->|start| Progress["in_progress\n实现、验收、收尾"]
Progress -->|archive| Completed["completed\n归档前写入"]
Progress -.->|finish| Detached["只清除当前 session 指针\n不等于任务完成"]
```
- `no_task` 由 hook 在没有 active task 时合成。
- 创建任务后是 `planning`,启动后是 `in_progress`。
- `completed` 由 archive 在归档前写入,正常不会作为 live breadcrumb 长时存在。
- active task 按 session 隔离;同一仓库的不同窗口可以做不同任务。
来源:[官方:架构全景](https://docs.trytrellis.app/zh/advanced/architecture)
**[官方事实]** 任务 lifecycle hook 是“命令事件”,不是通用 status watcher:
| 事件 | 确切含义 | 是否可作为外部 done 判定信号 |
|---|---|---|
| `after_create` | 任务目录已创建 | 否 |
| `after_start` | 任务进入 `in_progress` | 可用于写“进行中” |
| `after_finish` | 当前 AI session 已解除任务指针;任务可能在其他 session 继续 | **否** |
| `after_archive` | 任务已归档 | **是,官方指定的完成事件;但它不证明外部写入已成功** |
来源:[官方:架构全景](https://docs.trytrellis.app/zh/advanced/architecture)
### 3.4 Finish 边界
**[官方事实]** Trellis 把实现、工作 commit 和收尾记账分开:
1. implement / check 产出通过检查的 diff。
2. 主会话做最终验证并更新 spec。
3. 工作 commit 先发生。
4. `/trellis:finish-work` 如果发现当前任务改动未提交会停止,之后才归档任务并写 workspace journal。
`/trellis:finish-work` 不是提交功能代码的命令。
来源:[官方:架构全景](https://docs.trytrellis.app/zh/advanced/architecture)
本文之后所说的“`finish-work` 之后收口”,统一解释为:**目标项目已按它的 workflow 完成最终验证,且对应 task 已真正 archive**。它绝不等同于底层 `task.py finish`,后者只是 session detach。官方 native `finish-work` 与本地 Trellis × Matt 的 `archive --no-commit` 收尾也不同;实现 skill 不猜测用户输入的名称,而是回读 archived task 证明这个门禁。
### 3.5 Workflow 的可定制点和不可随意更改的边界
**[官方事实]** `.trellis/workflow.md` 集中定义:
- Phase 和分步说明。
- Skill Routing,即“用户意图 → auto-trigger skill”。
- `[workflow-state:STATUS]` 每轮面包屑。
- `task.py` 命令参考。
可添加自定义状态、新 Phase、Plan 分支或新 skill 路由,但有三类约定受脚本依赖:
- `[workflow-state:STATUS]...[/workflow-state:STATUS]` 标签格式。
- `## Phase X` + `#### X.Y` 标题层级。
- 真实 `task.py` 子命令名。只改 Markdown 不会改变 CLI。
面包屑文本下一条用户消息生效;Phase / step 正文和 skill routing 下一个 session 生效。
来源:[官方:定制 Workflow](https://docs.trytrellis.app/zh/advanced/custom-workflow)
### 3.6 Skill 与 sub-agent 的选型
**[官方事实]** 三种扩展点的职责不同:
| 扩展点 | 适合的问题 | 本闭环中的判断 |
|---|---|---|
| Command | 用户显式决定进入的会话边界 | 可作为手动补偿入口,但本文不预设具体命令 |
| Sub-agent | 需要隔离 prompt / 角色约束的子进程 | 不是 Spec / Ticket 选择和飞书状态回写的必需条件 |
| Skill | 根据意图自动触发、能力或阶段级的可复用工作流 | **适合本闭环的主要扩展点** |
Skill 的 `description` 应该写“什么情况下触发”,正文应再做触发自检、列明动手前必读文件、给出固定输出格式。Codex 的项目级 skill 在 `.codex/skills/{name}/SKILL.md`,官方同时使用 `.agents/skills/` 作为跨平台共享层。
来源:[官方:定制 Skill](https://docs.trytrellis.app/zh/advanced/custom-skills)
**[官方事实]** Trellis 原生提供 `trellis-implement`、`trellis-check`、`trellis-research` 三个 sub-agent。Codex 也可使用 inline 模式,由主会话通过 skill 读取同一批 task artifacts;自定义 sub-agent 若要拿到同类上下文,要约定 task-local JSONL 并遵守相同读取顺序。
来源:[官方:定制 Sub-agent](https://docs.trytrellis.app/zh/advanced/custom-agents)
### 3.7 `config.yaml` 和 lifecycle hook
**[官方事实]** `.trellis/config.yaml` 是应跟仓库提交的项目级共享配置,控制 session journal commit、任务 lifecycle hook、package 映射和 Codex 派发模式。
- 不应把机器身份、token、API key 或机器绝对路径放进该文件。
- 开发者身份放 `.trellis/.developer`;凭证放环境变量或常规密钥管理。
- `hooks` 支持 `after_create`、`after_start`、`after_finish`、`after_archive`,命令会收到指向当前 `task.json` 的 `TASK_JSON_PATH`。
- Hook 失败只打印警告,不会阻断任务操作。
- 在当前在线配置文档中,`codex.dispatch_mode` 记为默认 `inline`,`sub-agent` 用于选择旧派发模式。但这一点存在明确的本地版本差异,见 3.8;本方案不应依赖该默认值。
- `session_auto_commit` 默认为 `true`。若团队希望手动 review / commit Trellis 记账改动,可设为 `false`。
来源:[官方:`config.yaml` 配置](https://docs.trytrellis.app/zh/advanced/configuration)
### 3.8 在线文档与本机可执行事实的版本边界
**[本机验证]** 2026-07-26 实际执行:
```text
trellis --version -> 0.6.8
lark-cli --version -> 1.0.76
```
在线 Trellis 文档导航已显示 `v0.6.9` changelog;本机 0.6.8 已安装模板中,`codex.dispatch_mode` 的默认值是 `auto`,`inline` 是显式退出 sub-agent 派发,`sub-agent` 只是 `auto` 的兼容别名。这与当前在线配置页的描述不一致。
因此:
- 本文只依赖稳定的 task / artifact / lifecycle 语义,不把 `dispatch_mode` 当成飞书闭环的主集成点。
- 真正实现时,以目标项目的 `trellis --version`、`.trellis/config.yaml`、已生成 agent / skill 文件和 `python3 ./.trellis/scripts/task.py --help` 为可执行事实源。
- `trellis update` 后必须检查本地 workflow 覆盖和 `.new` / migration 差异,不直接假设在线文档与目标项目已同步。
## 4. 从现有 Matt 文档提取的“实现管理”
本节只提取实际开发时的管理思想,不扩展 implement / tdd / code-review 的编码规则。本节来源均为[本地文档:《Matt 工作流 × 飞书 CLI 全流程总结》](<./Matt 工作流 × 飞书 CLI 全流程总结.md>)。
### 4.1 三类事实源不重叠
**[Matt 提取]**
| 系统 | 管理内容 |
|---|---|
| Feishu Base | 当前状态、类别、负责人、进度、时间、父子关系和阻塞关系 |
| Feishu Wiki / Docs | Spec、Triage Notes、Agent / Human Brief 等长文档 |
| repo | 代码、测试、ADR、领域上下文和被拒绝 enhancement 的决定 |
直接含义是:新闭环不应该在 Trellis 中复制一份“飞书当前业务状态”,也不应该把完整 Wiki Spec 长期复制为第二份权威文档。
### 4.2 Spec 和 Ticket 的管理含义
**[Matt 提取]**
- Spec 是“问题、方案、验收边界”的聚合产物;完整内容在 Wiki,Base 保存可查询摘要和状态。
- Ticket 是 tracer-bullet 垂直切片;每张 Ticket 是 Base 记录,V1 不建独立 Wiki,而是沿 `所属父项` 找到父 Spec 和完整文档。
- Ticket 的 `前置依赖` 使用真实 Base record ID 建图。
- 当一张 Ticket 所有 blocker 都已完成且它尚未认领时,它才是可执行 frontier。
因此,“当前用户的 Ticket”不能只做 `负责人 = 当前用户` 的扫描;列表还应该区分“可开始、可恢复、被阻塞”。
### 4.3 实现状态机和完成门禁
**[Matt 提取]** 主执行流包含:
```text
ready-for-agent / ready-for-human
→ 进行中
→ 阻塞 ⇄ 进行中
→ 待评审 ⇄ 进行中
→ 已完成
```
关键一致性规则:
- `状态=阻塞` 时,`阻塞原因` 和 `下一步` 必须非空。
- 设置 `已完成` 前必须有具体 `验证证据`;无法验证时要写“未运行”和原因,不能伪装完成。
- `完成度`、`下一步`、`阻塞原因` 需与状态一致。
- Base create / update 后必须 `record-get` 或完整分页回读,`ok:true` 本身不是最终证据。
### 4.4 身份和责任分离
**[Matt 提取]**
- API 执行者是 bot。
- CLI 工作流真实发起人写入 `最后更新人`。
- `负责人` 是当前执行责任人,不因 bot 执行 API 而被覆盖。
- 每次 Base create / update 都刷新 `最后更新人`。
这意味着“当前用户”应从已验证的 Feishu CLI 用户身份取得,不能将 macOS 用户名、Trellis `.developer` 文本或 bot 身份直接当成飞书 `负责人`。
### 4.5 当前已完成与未闭环的部分
**[Matt 提取]** 当前飞书硬依赖适配已覆盖 setup、Spec、Tickets 和 Triage;`implement`、`tdd`、`code-review` 等下游流程只是通过公共 issue-tracker 合约消费同一 Base。
所以当前真正的缺口不是“再建一套开发规范”,而是:
1. 实现前如何从 Base 得到当前用户可执行的工作。
2. 如何将选中的 Spec / Ticket 和 Inline 会话或 Trellis task 稳定关联。
3. 实现结束后如何把实际验证证据、代码引用和终态回写 Base。
4. 外部回写失败时如何可见、可重试,而不是把任务误报为已闭环。
### 4.6 本地 Trellis × Matt 覆盖层的实现管理原则
**[Matt 提取]** 本仓库现有 [Trellis × Matt 工作流](<../AI-RD-Workflow/40-workflows/trellis-matt/CN/workflow.md>) 已经把实际开发分成三种模式:
| 模式 | 管理含义 |
|---|---|
| Inline | 简单、局部、根因明确且一个上下文可完成;不创建 Trellis task |
| Matt without Trellis | 不属于 Inline,但仍可单会话完成;用最匹配的工程方法,不为“看起来正式”创建 task |
| Trellis + Matt | 跨会话、多项稳定决策、多交付物或 durable research;Trellis 管生命周期,Matt 管当前阶段方法 |
与本闭环直接相关的管理原则是:
- **一个 lifecycle owner,一个 method owner**:Trellis 管 task 状态与恢复;实现方法不再自建第二套任务状态。
- `prd.md`、条件性的 `design.md` / `implement.md` 是 task-level 执行事实;跨会话任务用 `Current Checkpoint` 记录已完成、证据、下一步和 blocker。
- 实现 agent 不修改 Trellis 状态、requirements 或 acceptance criteria,不执行 Git 写操作;主会话负责完整 diff、最终验收、checkpoint 和用户沟通。
- 飞书的选择、外部写入确认和状态回读也应归主会话,不下放给 coding sub-agent。
- 本地覆盖不使用旧的 commit-first `trellis-finish-work`,而是以 `archive --no-commit` + `add_session.py --no-commit` 记账;commit / push / PR 仍只由用户明确授权。
这里有一个必须在设计中显式消歧的术语冲突:
- 你说的 **Inline 开发** = 不创建 Trellis task。
- Trellis 的 **Codex `dispatch_mode: inline`** = 已经处在 Trellis task 里,只是由主 Codex agent 直接实现。
两者不能共用一个判断条件。
## 5. 设计思考:五个关键问题及已确认解法
以下是可对外审查的设计推理,不是把内部思维过程当成事实。
### 5.1 Spec、Ticket 和 Trellis task 不是同一层概念
| 概念 | 回答的问题 | 推荐角色 |
|---|---|---|
| Spec | “为什么做、做到什么程度才算完成” | 复杂开发的业务聚合根 |
| Ticket | “按什么可验证切片推进,哪些切片已解锁” | 可刷新的实施计划 / 验收单元 |
| Trellis task | “本地这次复杂执行需要什么上下文和生命周期” | 本地执行容器 |
**[已确认]** 严格使用 `1 Spec = 1 Trellis task`。Ticket 只作为该 task 的动态执行计划、frontier 和验收单元,不映射为 Trellis child task。这样只保留一个 task lifecycle,避免 Trellis 任务树和 Base Ticket 依赖图双轨漂移。
### 5.2 两套状态机必须指定单向事实源
**[推荐]** 不做“两边任意修改、互相最后写入覆盖”的双向同步。
| 事实 | 权威来源 | 另一侧如何使用 |
|---|---|---|
| 负责人、优先级、Spec/Ticket 关系、前置依赖 | Feishu Base | Trellis 启动 / 恢复时读取快照 |
| Spec 长文档 | Feishu Wiki | Trellis task 保存链接和执行所需的摘要,不另建权威副本 |
| 当前 session 的 active task、本地 plan / check 上下文 | Trellis | 必要的节点摘要回写 Base |
| 代码、测试、commit / PR 引用 | repo | Base 仅保存 `代码引用` 和 `验证证据` |
| 对外工作状态 | Feishu Base | Trellis lifecycle 作为触发事件,不取代 Base |
### 5.3 需要稳定的关联 ID,不能靠标题回猜
**[推荐]** 用 Feishu Base `record_id` 作为 Spec / Ticket 的稳定关联键。标题只用于展示和启动前查重,不用于收口时反向查找。
Trellis 官方架构文档说 `task.json` 支持“扩展元数据”。**[本机验证]** Trellis 0.6.8 的 task 初始结构实际包含 `meta: {}`,archive 后 `after_archive` 收到的 `TASK_JSON_PATH` 指向已移入 archive 的 `task.json`。因此初步推荐用 `task.json.meta.feishuTracker`保存关联,但实现时仍要在目标项目回读 schema 并跑 archive POC。
候选合约(方案定义,非 Trellis 内置字段):
```json
{
"meta": {
"feishuTracker": {
"schemaVersion": 1,
"specRecordId": "rec_xxx",
"ticketRecordIds": ["rec_aaa", "rec_bbb"],
"selectedRecordIds": ["rec_aaa"],
"specWikiUrl": "https://...",
"trackerContractPath": "docs/agents/issue-tracker.md",
"boundAt": "2026-07-26T00:00:00+08:00",
"lastRefreshAt": "2026-07-26T00:00:00+08:00"
}
}
}
```
不将 Base token、API token、密钥或固定个人 open ID 写入 task 元数据。Base / table 坐标继续由 repo tracker contract 提供;当次人类用户每次通过 `lark-cli auth status --json --verify` 重新验证。
关联基数保持为:
```text
Trellis task
↔ 1 个 Feishu Spec record_id
↔ 0..N 个 Feishu Ticket record_id
↔ Spec Wiki URL
```
Inline 路径不为了保存 mapping 而初始化 Trellis。同会话收口时使用用户已选的 record IDs;若跨会话恢复,收口 skill 重新完整查询“负责人 = 当前用户 且 状态 = 进行中 / 待评审 / 阻塞”的记录,让用户按 record ID 重选,不用标题猜测。
### 5.4 “任务归档”只是 Spec 最终完成的必要条件,不是充分条件
**[已确认]** Ticket 可在 task 进行中通过部分收口逐张完成;`after_archive` 只解决“何时允许尝试 Spec 最终收口”。它不能单独证明每张 Ticket 均已验收。Spec 完成回写仍必须同时满足:
- 对应验收标准已核对。
- 真实验证命令 / 结果已采集;未运行项已明示。
- 需要的 check 已通过,且人类已完成最终 review。
- 要更新的每个 Ticket 都有对应证据,不因父 Spec 任务归档而批量猜测“全部完成”。
### 5.5 Inline 和 Trellis 应共用收口协议
**[推荐]** Inline 和 Trellis 的区别只是“是否需要持久的本地任务容器”,不应导致两套飞书状态规则。
```mermaid
flowchart TD
Queue["当前用户的 Spec / Ticket 队列"] --> Select["用户选择工作项"]
Select --> Route{"是否需要持久的复杂任务上下文?"}
Route -->|"No"| Inline["Inline 实现"]
Route -->|"Yes"| Task["1 Spec ↔ 1 Trellis task\nTickets 作为计划 / 验收单元"]
Inline --> Verify["共用验证与 Base 回写协议"]
Task --> Archive["Trellis 最终验证 + 归档"]
Archive --> Verify
Verify --> Readback["Base 回读 + 收口回执"]
```
## 6. 初步方案
### 6.1 总体架构
**[推荐]** 把新能力分成三层:
| 层 | 职责 | 不应负责的事 |
|---|---|---|
| Skill 编排层 | 身份门禁、列表、用户选择、路由、收口规则、结果汇报 | 不把 API 返回的 `ok:true` 当最终证据 |
| CLI 读写层 | 调用已验证的 `lark-cli`,查询 / patch / record-get | 不负责决定应将哪张 Ticket 置为完成 |
| Trellis lifecycle 集成层 | 提供 task 关联、start / archive 事件和归档上下文 | 不替代 Base 作为业务状态事实源 |
**[本机验证]** `lark-cli 1.0.76` 已提供 V1 所需的基础原语:
- `auth status --json --verify`:验证 bot / user 身份。
- `base +record-list`:结构化 filter、sort、字段投影、`offset` 和单页最大 `limit=200`;skill 必须自行循环到完整结果。
- `base +record-batch-update`:单次最多 200 条的差异化 patch,响应不保证 record ID 存在。
- `base +record-get`:按稳定 record ID 回读,所以 batch update 后仍需逐条或分批验证。
V1 可直接由 skill 编排这些 `lark-cli` 命令;先不为了包装而新建 CLI。只有当分页、frontier 计算、幂等 patch 在两个 skill 中形成重复且已经 POC 验证时,再提取 repo-local helper。
### 6.2 Skill A:工作入队与路由
**[V1 已实现]** 全局显式 skill 名为 `start-work-feishu`,source of truth 位于 `~/.agents/skills/start-work-feishu/`;它不是 Trellis 内置命令。
触发条件:
- 用户表示“开始开发、看我的待办、选一个 Spec / Ticket 实现”。
- 当前无 active Trellis task,或用户明确要恢复已认领工作。
建议流程:
1. 运行已验证的 Feishu 身份检查,冻结当前人类用户 open ID;不把 bot 当用户。
2. 分别完整分页查询两类记录:
- Spec 队列:`产物类型 = PRD/Spec` 且 **Spec 自身** `负责人 = 当前用户`。不因“它的子 Ticket 由当前用户负责”而把该 Spec 追加到 Spec 队列。
- Ticket 队列:`产物类型 = 实现 Ticket` 且 Ticket 自身 `负责人 = 当前用户`。展示时可附带父 Spec 上下文,但不改变 Spec 队列口径。
3. 分组展示:
- **恢复执行**:`进行中` / `阻塞`。
- **现在可开始**:`ready-for-agent` 且 blocker 都已完成的 Ticket,以及符合条件的 Spec。
- **尚未解锁**:存在未完成 blocker 的 Ticket,只展示原因,不默认推荐开工。
4. 每行至少展示:标题、产物类型、Base record ID、状态、优先级、父 Spec、阻塞项、更新时间和建议路由。
5. 用户选择后,用 record ID 重新取得最新记录,防止列表与实际状态之间竞态。
6. 如选 Ticket,沿 `所属父项` 取父 Spec 和 Wiki;如选 Spec,同时取子 Tickets 和依赖图。
7. 根据既有约定路由:
- 范围小、根因 / 方案已知、当前上下文可以完成:Inline。
- 跨模块、需持久计划、多会话、多人 / 多 Agent 或验收链较长:Trellis task。
8. 列表本身只读。用户选择后,skill 一次性展示“工作项 + Inline / Trellis 路由 + 拟写 Base patch”;用户确认“开始”后,同时构成任务路由决定和这一次外部写入授权,不再追加一个纯流程性的“是否创建 Trellis task”问题。
9. 官方 native `no_task` breadcrumb 要求任务创建同意,但本地 Trellis × Matt workflow 明确覆盖为“满足 durable 条件时直接创建,不问 task-consent”。本方案用上一步的“选择并开始”统一两者,不改 Trellis CLI 语义。
10. 当 record ID 关联已成功保存且用户确认开始时,将选中的聚合工作项更新为 `进行中`。选 Spec 时先只写 Spec,其他 Tickets 保持原状态;选 Ticket 时写该 Ticket,并将其父 Spec 写为 `进行中`(如尚未进入),其他 Tickets 不动。这里的语义是“已认领并开始规划 / 执行”,不声称代码已写。
11. 每次写入都带 `最后更新人 = 当前人类用户`,并立即回读核对。
建议列表形式:
| 序号 | 可执行性 | 类型 | 标题 | 状态 | 优先级 | 父 Spec | 阻塞 | 建议路由 |
|---:|---|---|---|---|---|---|---|---|
| 1 | 可恢复 | Spec | … | 进行中 | P1 | — | — | Trellis |
| 2 | 可开始 | Ticket | … | ready-for-agent | P2 | Spec A | 无 | Inline |
| 3 | 被阻塞 | Ticket | … | ready-for-agent | P2 | Spec B | Ticket X | 暂不开工 |
### 6.3 复杂开发的映射规则
**[推荐]**
```text
Feishu Spec record_id
↔ Trellis task
├── prd.md:Spec 链接、必要摘要、验收边界
├── implement.md:按 Ticket frontier 生成 / 刷新的执行计划
├── implement.jsonl / check.jsonl:只收录必要的本地 spec / research
└── task.json.meta.feishuTracker:Spec record_id + Ticket record_ids
```
约束:
- 同一 Spec 同时最多对应一个 active Trellis task。创建前先扫描 active task 的 `meta.feishuTracker.specRecordId`;已存在时恢复原 task,不按标题再建一个。
- Feishu Wiki Spec 仍是长规格事实源;Trellis `prd.md` 是本地执行上下文,应显式记录来源 record ID / URL 和取得时间。
- Ticket 状态和依赖仍以 Base 为准;`implement.md` 是可执行快照,恢复开发时先检查 Base 是否已变化。
- 每次恢复 Trellis task 时,按 `specRecordId` 重取 Spec、子 Tickets、依赖与 `更新时间`,与 `lastRefreshAt` 快照比较。新增 Ticket 可追加为新计划项;验收、范围或依赖发生实质变化时,先向用户展示 diff,不静默改写已 review 的 task artifacts。
- `implement.md` 保存本地 checkpoint,Base Ticket 保存对外状态。二者的重合内容是可重建快照,不形成双向最后写入覆盖。
- Ticket 不映射成 Trellis child task;所有 Tickets 都通过同一 Spec task 的 `implement.md` / checkpoint 管理。
- 不把完整业务文档塞进 JSONL;Trellis 官方建议 JSONL 只列当前任务需要的 spec / research。[官方:架构全景](https://docs.trytrellis.app/zh/advanced/architecture)
### 6.4 Skill B:验证与飞书收口
**[V1 已实现]** 全局显式 skill 名为 `close-work-feishu`,source of truth 位于 `~/.agents/skills/close-work-feishu/`;它不是 Trellis 内置命令。
这个 skill 支持三个 routing,而不是只能在整个 Spec 完成后运行:
| Routing | 何时调用 | 允许写入的终态 |
|---|---|---|
| **部分收口** | Inline 或 Trellis task 还在进行中,用户希望先结算已完成切片 | 只能关闭经人类 review 确认的 Tickets;Spec 继续保持 `进行中` |
| **最终收口** | 全部 Ticket 已结算,Spec 验收已完成;Trellis 路径的 task 还必须已 archive | 先确认漏网 Tickets,最后才允许关闭 Spec |
| **对账重放** | 上次写入部分成功、回读失败或记录已处于目标终态 | 只补齐仍有差异的记录;证据完整时返回“已同步”,不重复追加 |
Inline 不等待 Trellis 事件。Trellis 的部分收口可在 active task 期间运行;最终收口才要求 archive。`after_archive` 仍只负责提醒或标记“待对账”,不直接代表 Base 已写回。
共享步骤:
1. 先确定唯一父 Spec。Trellis 从 active / archived task 的 `meta.feishuTracker.specRecordId` 取得;Inline 从当会话选择或一次用户重选取得。不用标题反查。
2. **按 Spec 回读所有未完成 Tickets**,不只分析当前 mapping 快照中的 Ticket IDs。同时重取验收标准、负责人、状态、前置依赖和更新时间,避免漏掉开发中新增或变更的 Tickets。
3. 汇总 repo diff、真实验证命令与结果、未运行项及原因、review 证据、代码引用和 Trellis checkpoint,并逐张映射 Ticket 验收标准。
4. 对未完成 Tickets 分类:
- **建议可收口**:验收条件和直接证据充分,可交给人类 review。
- **待补证 / 待验证**:实现看似已有,但证据或验收映射不足,不建议完成。
- **明确未完成 / 阻塞**:仍有实现项、未满足 blocker 或需要新决策。
5. 向用户展示逐 Ticket 分析:标题、record ID、验收结论、证据、风险、建议动作和拟写 patch。Agent 只推荐,不自行选择终态。
6. **人类 review 是每张 Ticket 写入 `已完成` 的必要条件**。用户可确认全部建议项,也可只选其中一部分;未被确认的 Ticket 不写终态。
7. 对用户确认的 Tickets 构造最小 patch,写入状态、完成度、Ticket 专属的验证证据、代码引用和 `最后更新人`,清理终态不应保留的阻塞字段。不覆盖无关新写入。
8. 先更新 Tickets 并逐条回读。部分收口在此结束:父 Spec 保持 `进行中`,未完成 Tickets 保持原状态,回执中列出最小下一步。
9. 最终收口在 Ticket 回读后重新查询全部子 Tickets。只有当全部 Tickets 已完成、Spec 级验收充分、Trellis task 已 archive(若适用)且人类完成最终 review,才展示 Spec 终态 patch 并再取得一次确认。
10. 更新 Spec 后回读,最终输出收口回执:已更新记录、未收口记录及原因、失败记录、人类 review 结论和回读证据。
```mermaid
flowchart TD
Invoke["用户执行收口 skill"] --> Spec["定位 Spec record ID"]
Spec --> Fetch["取全部未完成 Tickets"]
Fetch --> Analyze["逐 Ticket 分析验收与证据"]
Analyze --> Review["人类 review 并选择可收口 Tickets"]
Review --> CloseTickets["更新 Tickets + 逐条回读"]
CloseTickets --> Remaining{"仍有未完成 Ticket?"}
Remaining -->|"Yes"| Partial["部分收口完成\nSpec 保持进行中"]
Remaining -->|"No"| FinalGate{"Spec 验收 + 人类最终 review\n+ Trellis archive 如适用?"}
FinalGate -->|"No"| Wait["保持 Spec 进行中 / 待评审"]
FinalGate -->|"Yes"| CloseSpec["用户确认 Spec patch"]
CloseSpec --> Done["更新 Spec + 回读"]
```
推荐的完成 patch 语义,不是未验证的 CLI 命令:
| 字段 | 目标值 / 规则 |
|---|---|
| `工作流阶段` | 已完成实现和验收后进入交付,或按团队最终确定的阶段映射 |
| `状态` | `已完成` |
| `完成度` | 100 |
| `验证证据` | 真实命令 + 结果摘要 + 未运行项 |
| `代码引用` | 任务路径、分支、commit、PR 或关键文件,只写真实存在的引用 |
| `阻塞原因` | 清空 |
| `下一步` | 清空,或按团队终态规则写明后续交付动作 |
| `最后更新人` | 当前已验证 CLI 人类用户 |
### 6.5 Trellis 与 Base 状态映射
**[推荐]**
| Trellis / 本地事件 | Base 候选状态 | 备注 |
|---|---|---|
| 已列表、用户未选择 | 不写 | 只读查询不应该改状态 |
| 用户确认“选择并开始”,mapping 保存成功 | `进行中` | 表示已认领并进入 planning / execution;不猜测完成度 |
| Trellis `planning` / `after_start` | 通常不再重复写 | 由入队 skill 完成开始回写;hook 可做对账,不必二次 patch |
| 外部 blocker 出现 | `阻塞` | `阻塞原因` + `下一步` 必填 |
| Agent 分析 Ticket “建议可收口”,尚未人类 review | 保持原状态,或经确认写 `待评审` | 绝不自动写 `已完成` |
| 部分收口:人类 review 并确认部分 Tickets | 被选 Tickets → `已完成` | 其他 Tickets 不动,Spec 保持 `进行中` |
| `after_finish` | 不写 | 只是 session detach |
| `after_archive` | 不直接写 done | 只生成收口提醒 / 待对账信号 |
| 全部 Tickets 完成 + Spec 验收 + 人类最终 review + archive(如适用) | Spec → `已完成` | 最终收口的聚合门禁;任一条不满足都不关 Spec |
| 同步失败 | 保留原状态 | 本地报告“代码 / Trellis 已完成,Base 待对账”,不伪报闭环 |
该映射要在 POC 后才能固化进 skill;特别是 `工作流阶段` 和 Spec 聚合完成语义,需再确认业务预期。
### 6.6 Hook 怎么用:事件触发,不是唯一保障
**[推荐]** 分三阶段导入:
#### V1:skill 显式闭环
- 由工作入队 skill 负责选择、路由和开始状态回写。
- Inline / Trellis 进行中都可显式执行收口 skill 的“部分收口”routing,只关闭经人类 review 确认的 Tickets。
- Inline 整体验收完成,或 Trellis 最终验证和归档后,显式执行“最终收口”routing,才可能关闭 Spec。
- 先证明字段映射、回读和幂等性,不先扩大到全自动 hook。
#### V1.5:Workflow routing 固化入口
- 在 `.trellis/workflow.md` 的 Skill Routing 中加入“开始飞书工作”与“实现完成后闭环飞书”的意图路由。
- 在 Finish 阶段明确“archive 成功后运行飞书收口 / 对账”。
- 保持 Trellis 解析器依赖的 block 标签、Phase / step 标题层级和真实命令名不变。[官方:定制 Workflow](https://docs.trytrellis.app/zh/advanced/custom-workflow)
#### V2:lifecycle hook + 可重放对账
- `after_start` 可选用于检查绑定工作项是否已是 `进行中`,不与入队 skill 重复 patch。
- `after_archive` 只输出明确提醒,或写一个不含凭证的本地待对账标记;后续仍由用户显式运行收口 skill。
- `after_finish` 不更新 Base 完成态。
- Hook 里不放 Base token、user open ID 或机器绝对路径;`.trellis/config.yaml` 只保存团队共享的相对命令。[官方:`config.yaml` 配置](https://docs.trytrellis.app/zh/advanced/configuration)
- 收口 skill 扫描已 archive 任务的 `meta.feishuTracker`,并回读 Base 判断是否待同步;不需要依赖 hook 的“成功标记”。
- 由于 hook 失败不阻断 archive,同一收口核心必须支持手动重放 / 对账;skill 作为唯一声称“Base 已闭环”的入口。
### 6.7 幂等、竞态和失败处理
**[推荐]** 收口设计必须包含:
1. **稳定键**:只按 record ID 更新。
2. **写前回读**:责任人、状态或父子关系已变更时停止并报告,不强制覆盖。
3. **最小 patch**:只写当前状态转移需要的字段。
4. **幂等重放**:目标已是相同终态且证据一致时,结果为“已同步”,不再创建新记录或重复附加证据。
5. **部分成功可见**:返回逐条成功 / 失败列表,不用一个总体 `ok` 遮蔽部分失败。
6. **回读才是成功**:只有回读字段符合预期才报告“Base 已闭环”。
7. **外部失败不篡改本地事实**:代码 / Trellis 已完成与 Base 同步失败必须分开汇报。
### 6.8 为什么暂不需要新 sub-agent
**[推荐]** Spec / Ticket 选择、外部写入确认和收口回执都依赖当前主会话,并不需要隔离的编码角色。Trellis 支持由主会话通过 skill 读取任务上下文,而本地 Trellis × Matt 覆盖已把 lifecycle、最终验收和用户沟通明确交给主会话。[官方:定制 Sub-agent](https://docs.trytrellis.app/zh/advanced/custom-agents)
可以继续使用 Trellis 原生 implement / check / research 角色处理各自的执行职责,但不应该让它们各自直接决定 Base 终态。
## 7. 建议的端到端时序
### 7.1 Inline 路径
```mermaid
sequenceDiagram
participant U as 用户
participant S as 工作入队 skill
participant F as Feishu Base / Wiki
participant C as Coding Agent
participant X as 工作收口 skill
U->>S: 显示我的可实现工作
S->>F: 验证身份 + 完整查询
F-->>S: Spec / Ticket + 关系 + 状态
S-->>U: 可恢复 / 可开始 / 被阻塞列表
U->>S: 选择工作项
S-->>U: 展示 Inline 路由 + Base 开始 patch
U->>S: 确认选择并开始
S->>F: 重读后写进行中,再回读
S->>C: record IDs + Spec + Tickets + 验收边界
C->>C: Inline 实现与验证
C->>X: 完成证据 + 代码引用
X-->>U: 展示逐 Ticket / Spec patch
U->>X: 确认外部写入
X->>F: 按 record ID 最小 patch
X->>F: 逐条回读
X-->>U: 收口回执
```
### 7.2 Trellis 路径
```mermaid
sequenceDiagram
participant U as 用户
participant S as 工作入队 skill
participant F as Feishu Base / Wiki
participant T as Trellis
participant X as 工作收口 / 对账
U->>S: 选择复杂 Spec / Ticket
S->>F: 取最新 Spec、Tickets、依赖
S-->>U: 展示 1 Spec ↔ 1 task 路由 + Base 开始 patch
U->>S: 确认选择并开始
S->>T: 建立 task 与 Base record IDs 的稳定关联
S->>F: 写进行中 + 最后更新人,再回读
T->>T: planning
T->>T: start → in_progress
T->>T: implement → check → update-spec → 最终验证
U->>T: 按目标项目合约执行 finish-work / archive
T->>T: archive + journal
T-->>X: after_archive 提醒 + archived TASK_JSON_PATH
U->>X: 显式运行收口 skill
X-->>U: 展示逐 Ticket / Spec patch
U->>X: 确认外部写入
X->>F: 按逐 Ticket 证据幂等收口,Spec 最后写
X->>F: 回读
X-->>U: 收口成功,或 Base 待对账
```
图中 `after_archive` 和 `TASK_JSON_PATH` 是 Trellis 官方已有事实;它们只触发提醒,不绕过用户确认直接写飞书。具体收口 skill 和 Feishu CLI payload 是本方案待实现部分。[官方:架构全景](https://docs.trytrellis.app/zh/advanced/architecture) [官方:`config.yaml` 配置](https://docs.trytrellis.app/zh/advanced/configuration)
## 8. 建议的最小 POC
本文推荐先不改完整 Trellis workflow,用一个真实但可回收的 Spec + 两张 Ticket 验证下列最小闭环:
1. 当前 Feishu CLI 人类用户可被准确解析。
2. 能完整列出“Spec 自身负责人 = 当前用户”的 Spec,不因子 Ticket 归属扩张 Spec 列表;同时独立列出当前用户负责的 Tickets,并正确计算依赖 frontier。
3. 用户选定后,Trellis 路径能把 Spec / Ticket record IDs 保存到 `task.json.meta.feishuTracker`,且 archive 后仍可读取。
4. 同一个候选工作能分别跑通 Inline 和 Trellis 两条路径。
5. Trellis 的 `after_finish` 不触发 done;`after_archive` 只触发收口提醒,显式 skill 才尝试写 done。
6. 在 task 未 archive 时执行部分收口,skill 能按 Spec 取得全部未完成 Tickets,给出“建议可收口 / 待补证 / 未完成”分析,并只关闭用户 review 后确认的 Tickets。
7. 部分收口后 Spec 仍为 `进行中`;未被用户确认的 Tickets 不被误关闭。
8. 最终收口只在全部 Tickets 完成、Spec 验收通过、人类最终 review 通过且 Trellis task 已 archive(如适用)时关闭 Spec。
9. 重复执行部分 / 最终收口不会创建重复记录、重复证据或错误状态。
10. 刻意让一次 hook 失败,archive 仍成功,收口 skill 仍能通过 archive task mapping + Base 回读发现待同步工作。
11. 刻意让一次 Base batch update 部分失败,skill 能保留逐条成功 / 失败证据并幂等重放,不误关父 Spec。
12. 所有 Base 更新都显示 `最后更新人 = 当前真实用户`,且已逐条回读。
13. POC 验收后将测试记录标记为 `已取代`,保留审计证据,不删除。
POC 前先仅定义读取和预演模式,展示将修改的 record IDs 和字段;真实写飞书应在用户确认后进行。
## 9. 导入顺序建议
### 阶段 A:只读队列
- 实现身份验证、完整分页、负责人过滤、状态分组和 frontier 计算。
- 不改 Base、不建 Trellis task。
- 验收:列表与 Base UI 人工核对一致。
### 阶段 B:选择与开始同步
- 用户选择后重读 record。
- 实现 Inline / Trellis 路由和稳定 ID 绑定。
- 用户一次确认“选择并开始”后,写 `进行中`并回读;Trellis `after_start` 只做可选对账。
### 阶段 C:显式收口
- Inline 和 Trellis 共用一个收口核心。
- 先做“部分收口”:按 Spec 分析所有未完成 Tickets,人类 review 后选择收口集合。
- 再做“最终收口”:验证全 Ticket 完成、Spec 聚合验收、人类最终 review 和幂等重放。
### 阶段 D:Workflow 与 hook 集成
- 把 skill 意图写入 `.trellis/workflow.md` Skill Routing。
- 再接 `after_start` / `after_archive` 的对账 / 提醒能力,不在 hook 中无确认写飞书。
- 保留手动对账入口,并演练 hook 失败。
## 10. 已确认的设计决策
| # | 已确认决策 | 对实现的直接约束 |
|---:|---|---|
| 1 | 使用两个 skill:入队 skill + 收口 skill | 对账重放是收口 skill 的 routing,不新增第三个 skill |
| 2 | 严格 `1 Spec = 1 Trellis task` | Ticket 不建 Trellis task / child task,只作为同一 task 内的动态计划和验收单元 |
| 3 | 用户确认“选择并开始”且 mapping 保存后,立即写 `进行中` | 不新增“规划中”状态;`after_start` 不重复 patch |
| 4 | 必须人类 review 才能完成 | Agent check、测试通过和 archive 都只是证据,不能单独产生 Ticket / Spec 终态 |
| 5 | 收口 skill 支持部分收口 | 每次按 Spec 重取所有未完成 Tickets,分析可收口集合,用户 review / 选择后只关闭被确认 Tickets;Spec 保持进行中,直到最终聚合门禁通过 |
| 6 | 采用本文推荐的 mapping | 使用 `task.json.meta.feishuTracker`,不写 token、密钥或固定个人 open ID |
| 7 | Hook 按本文推荐边界 | `after_archive` 只提醒 / 待对账,不直接写 Feishu;显式收口 skill 才能声称 Base 闭环 |
| 8 | Spec 队列只列 Spec 自身负责人 = 当前用户 | 不因子 Ticket 归属扩张 Spec 队列;当前用户负责的 Tickets 仍作为独立 Ticket 队列展示 |
## 11. 风险与非目标
### 当前风险
- **状态双写风险**:若 Base 和 Trellis 都被当成业务状态权威源,会出现覆盖与逆向跳转。
- **误用 `after_finish`**:会在其他 session 仍工作时提前完成 Base。
- **hook 假成功**:archive 成功不代表 hook 成功,必须有重放 / 对账。
- **Spec 批量误关闭**:父 task 归档不能无证据地把所有 Ticket 置为已完成。
- **用标题做关联**:改名、重名和模糊查询会导致更新错记录。
- **身份混淆**:bot、`负责人`、`最后更新人` 和 Trellis developer 是不同概念。
- **敏感信息进仓**:不能把 token / API key / 个人 open ID 硬编码进 `.trellis/config.yaml`。
### 非目标
- 本文不设计新的 coding / TDD / review 规则。
- V1 已实现两个显式 skill,但不实现 hook、CLI wrapper、helper script 或 Trellis workflow 定制。
- 本文不修改飞书 Base schema 或真实业务记录。
- 本文不把本地结构 / fixture 验证等同于真实 Base POC。
## 12. 资料索引
### Trellis 官方一手资料
1. [架构全景](https://docs.trytrellis.app/zh/advanced/architecture)
2. [定制 Workflow](https://docs.trytrellis.app/zh/advanced/custom-workflow)
3. [定制 Skill](https://docs.trytrellis.app/zh/advanced/custom-skills)
4. [定制 Sub-agent](https://docs.trytrellis.app/zh/advanced/custom-agents)
5. [配置 `.trellis/config.yaml`](https://docs.trytrellis.app/zh/advanced/configuration)
### 本地已验证资料
- [Matt 工作流 × 飞书 CLI 全流程总结](<./Matt 工作流 × 飞书 CLI 全流程总结.md>)
- [Trellis × Matt 全局 Agent 规则](<../AI-RD-Workflow/40-workflows/trellis-matt/CN/AGENTS.md>)
- [Trellis × Matt 项目 Workflow](<../AI-RD-Workflow/40-workflows/trellis-matt/CN/workflow.md>)
- 本机命令验证:`trellis 0.6.8`、`lark-cli 1.0.76`、本机 Trellis 0.6.8 已安装 task / config 模板。
## 13. V1 实现状态与下一步
### 13.1 已实现
- `~/.agents/skills/start-work-feishu/`:`SKILL.md`、`references/feishu.md`、`agents/openai.yaml`。
- `~/.agents/skills/close-work-feishu/`:`SKILL.md`、`references/feishu.md`、`agents/openai.yaml`。
- 两个 skill 均设置 `policy.allow_implicit_invocation: false`,只允许用户显式调用。
- V1 直接编排项目内 Trellis 脚本与 `lark-cli`,没有新增 helper、hook、workflow 修改或 Base schema 写入。
### 13.2 已完成的本地验证
- 两个目录均通过 `skill-creator/scripts/quick_validate.py`。
- `agents/openai.yaml` 已解析并确认显式调用策略及 `$skill-name` 默认提示。
- 暂存目录与全局安装目录逐字节一致,无 `TODO` / 模板占位残留。
- 契约 fixture 覆盖 11 类场景:负责人过滤、父 Spec 上下文、完整 frontier、非完成终态、待评审分流、重复 task mapping、部分收口、缺失证据、`finish` 非 archive、Spec 最终门禁和幂等回读规则。
- 独立前向测试只使用脱敏 fixture,未调用 `lark-cli`、未写 Base;验证结果见本次实施回执。
### 13.3 尚未运行与后续顺序
当前机器没有发现任何项目级 `docs/agents/issue-tracker.md`,因此不能安全定位真实 Base,真实只读 POC 标记为 `未运行`。后续按以下顺序继续:
1. 用户指定一个已配置飞书 tracker contract 的 Trellis 项目。
2. 运行 `start-work-feishu` 只读队列 POC,与 Base UI 人工核对负责人、分页和 frontier。
3. 单独展示 record IDs 与开始 patch,经确认后验证 mapping、`进行中` 写入和回读。
4. 依次验证部分收口、最终收口和对账重放;每批真实写入仍单独确认。
5. V1 真实 POC 稳定后,再讨论是否抽取 helper,以及是否进入 workflow / hook 提醒集成。