feat:更新
This commit is contained in:
@@ -1,520 +0,0 @@
|
||||
# Matt 工作流 × 飞书 CLI 全流程总结
|
||||
|
||||
> 状态:已通过真实 Feishu Base / Wiki POC 验证
|
||||
> 更新时间:2026-07-26
|
||||
> 覆盖范围:`setup-workflow-skills-feishu`、`to-spec-feishu`、`to-tickets-feishu`、`triage-feishu`
|
||||
|
||||
## 1. 结论
|
||||
|
||||
本次工作把 Matt Pocock 的工程工作流接入了飞书,并保持原 Matt skills 的规划、规格、垂直切片和分诊语义不变:
|
||||
|
||||
- **Feishu Base 是状态、关系和查询的事实来源**:每个 Issue、Spec、Ticket 或其他产物对应一条记录。
|
||||
- **Feishu Wiki / Docs 是长文档事实来源**:保存 Spec、Triage Notes、Agent Brief、Human Brief 等叙述性产物。
|
||||
- **仓库仍保存代码侧事实**:代码、测试、ADR、`CONTEXT.md` 和被拒绝 enhancement 的 `.out-of-scope/` 决定不会复制成第二份事实来源。
|
||||
- **所有 Feishu API 操作使用应用身份**:`--as bot --format json`,不回退到 user 身份或其他文档位置。
|
||||
- **每次 Base 记录创建或更新都记录真实发起用户**:调用者是 bot,“最后更新人”保存当前 CLI 人类用户;“负责人”仍只表示执行责任人。
|
||||
- **所有写入都需要回读验证**:API 返回 `ok:true` 只是第一层证据,Wiki 用 `docs +fetch`,Base 用 `record-get` 或完整分页查询复核。
|
||||
|
||||
## 2. 当前资源与身份
|
||||
|
||||
| 项目 | 当前值 |
|
||||
| ---------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| Base | [Matt 工作流多维表格](https://oppeinlink.feishu.cn/wiki/Cq6Kw9mrGi0KXDkBJJpcW57Lnmd?table=tblFvlnVuWhmvQKC&view=vewwNwcwaf) |
|
||||
| Base token | `HXzGbaFIAaHEpBsMMrfc0z1lnnb` |
|
||||
| 数据表 | `数据表` / `tblFvlnVuWhmvQKC` |
|
||||
| 主字段 | `文本` / `fldzLHLTca` |
|
||||
| 视图 | `表格` / `vewwNwcwaf`,29 个字段全部可见 |
|
||||
| Wiki 根节点 | [开发智能体文档仓库](https://oppeinlink.feishu.cn/wiki/RG7bwmoP0i6DJikbHqWcY959nLd) |
|
||||
| Wiki space | `7493342321238130707` |
|
||||
| 工作流文档 | [Matt 工作流 × 飞书 CLI:文档与进度管理工作流](https://oppeinlink.feishu.cn/wiki/L2qFwzIMAipZqlkbwoXc6Pofnxe) |
|
||||
| API 执行身份 | bot `迷迭香` / `ou_967b892ae067fd2e24d369a289a5b01e` |
|
||||
| 当前归因用户 | `于选辉` / `ou_aed469c8168cd31341fa94bf2d89bddd` |
|
||||
| 已验证 CLI | `lark-cli 1.0.76` |
|
||||
|
||||
## 3. 系统架构
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Human["真实用户 / 维护者"] --> Conversation["对话确认与 Matt 工作流"]
|
||||
Conversation --> Auth["auth status --verify"]
|
||||
Auth -->|"验证 bot"| Bot["应用身份:迷迭香"]
|
||||
Auth -->|"冻结 user openId"| Attribution["业务归因:最后更新人"]
|
||||
|
||||
Bot -->|"--as bot"| Base["Feishu Base\n状态、关系、查询"]
|
||||
Bot -->|"--as bot"| Wiki["Feishu Wiki / Docs\n长文档与叙述"]
|
||||
Attribution -->|"每次 record create / update"| Base
|
||||
|
||||
Repo["代码仓库\n代码、测试、CONTEXT、ADR、out-of-scope"] --> Conversation
|
||||
Base -->|"产物文档"| Wiki
|
||||
Base -->|"代码引用"| Repo
|
||||
|
||||
Base --> Verify["record-get / 完整分页回读"]
|
||||
Wiki --> VerifyDoc["docs +fetch 回读"]
|
||||
Verify --> Evidence["验证证据"]
|
||||
VerifyDoc --> Evidence
|
||||
```
|
||||
|
||||
关键边界:
|
||||
|
||||
1. bot 是 API 调用者,不自动等于“负责人”或“最后更新人”。
|
||||
2. “最后更新人”由工作流显式写入当前已验证用户的 open ID。
|
||||
3. “负责人”是工作执行责任,不因 CLI 操作而被覆盖。
|
||||
4. Wiki 节点必须创建在配置的根节点下;失败时报告完整错误和 `x-tt-logid`,不切换身份或位置重试。
|
||||
|
||||
## 4. 四个 Feishu skill
|
||||
|
||||
| Skill | 何时使用 | 核心输入 | 核心产物 | Base / Wiki 策略 |
|
||||
|---|---|---|---|---|
|
||||
| `setup-workflow-skills-feishu` | 仓库接入或切换到飞书 tracker | Base 表格/视图 URL、Wiki 根节点 URL、Setup 模式 | repo tracker 合约;Bootstrap 另含 Base schema、Wiki setup 文档、POC 记录 | 默认 Reuse 只读复核既有设施;Bootstrap 才初始化并验证写路径 |
|
||||
| `to-spec-feishu` | 把已澄清的对话转成可执行 Spec | 对话、代码库上下文、测试 seam、可选来源 Issue | 完整 Wiki Spec + 一条 Base Spec | Wiki 保存完整规格;Base 保存身份、状态、摘要、验收和父项 |
|
||||
| `to-tickets-feishu` | 把 Spec / 计划拆成 tracer-bullet Tickets | 已确认 Spec、垂直切片、依赖图 | 每个切片一条 Base Ticket | V1 不创建 Ticket Wiki;通过父 Spec 取得文档;两遍写入关系 |
|
||||
| `triage-feishu` | 处理 Issue / PR 的分类、澄清和委派 | Issue/PR、代码验证、维护者决定、报告人反馈 | Base Issue 状态 + 可选 Triage Wiki dossier | Base 保存当前状态;Wiki 追加 Notes / Brief;拒绝决定以 repo 为准 |
|
||||
|
||||
这些 skill 的 `来源技能`仍使用逻辑流程名,例如 `setup-matt-pocock-skills`、`to-spec`、`to-tickets`、`triage`;不会把适配器名称写成新的业务枚举。
|
||||
|
||||
## 5. 端到端工作流
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Setup["setup-workflow-skills-feishu\n建立 repo 合约;按模式复用或初始化飞书资源"] --> Intake{"工作从哪里进入?"}
|
||||
|
||||
Intake -->|"想法 / 已澄清对话"| SpecDraft["to-spec-feishu"]
|
||||
Intake -->|"外部 Issue / PR / 表单"| Triage["triage-feishu"]
|
||||
|
||||
Triage --> NeedsInfo["needs-info\n等待报告人"]
|
||||
NeedsInfo -->|"最后反馈时间 > 最后分诊时间"| Triage
|
||||
Triage --> ReadyAgent["ready-for-agent"]
|
||||
Triage --> ReadyHuman["ready-for-human"]
|
||||
Triage --> Wontfix["wontfix / out-of-scope"]
|
||||
|
||||
ReadyAgent --> Complexity{"是否需要正式 Spec?"}
|
||||
Complexity -->|"跨模块、需要设计决策"| SpecDraft
|
||||
Complexity -->|"范围已足够小且明确"| Implement["implement / tdd"]
|
||||
|
||||
SpecDraft --> SpecArtifacts["Wiki Spec + Base Spec\n状态 ready-for-agent"]
|
||||
SpecArtifacts --> Ticketing["to-tickets-feishu"]
|
||||
Ticketing --> TicketGraph["Base Ticket 依赖图\nfrontier = 无未完成 blocker"]
|
||||
TicketGraph --> Implement
|
||||
|
||||
Implement --> Review["code-review / 验证"]
|
||||
Review --> Done["已完成 + 验证证据"]
|
||||
Implement --> Blocked["阻塞 + 阻塞原因 + 下一步"]
|
||||
Blocked --> Implement
|
||||
|
||||
ReadyHuman --> HumanWork["人类处理:判断、权限、设计或手工验证"]
|
||||
Wontfix --> Memory["Wiki 关闭说明;必要时 repo .out-of-scope/"]
|
||||
```
|
||||
|
||||
本次新增的硬依赖飞书适配止于 setup、Spec、Tickets 和 Triage;`implement`、`tdd`、`code-review` 等下游流程通过生成的 `docs/agents/issue-tracker.md` 公共合约继续消费同一 Base。
|
||||
|
||||
## 6. Setup:一次性建立公共契约
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start["探索仓库"] --> Detect["检查 AGENTS/CLAUDE、docs/agents、domain docs、triage、monorepo"]
|
||||
Detect --> Tracker{"选择 issue tracker"}
|
||||
Tracker -->|"Feishu"| Inputs["只接受两个用户输入\nBase URL + Wiki 根 URL"]
|
||||
Inputs --> ReadSkills["读取 lark-shared / base / wiki / doc 规则"]
|
||||
ReadSkills --> Mode{"选择 Setup 模式\n默认 Reuse"}
|
||||
Mode -->|"Reuse:复用已配置资源"| Identity["验证 bot + user;冻结当前 user openId"]
|
||||
Mode -->|"Bootstrap:新建或显式重验"| Identity
|
||||
Identity --> Resolve["bot 解析 Base、table、view、Wiki root"]
|
||||
Resolve --> Diff["完整 field-list;按精确字段名计算缺失项"]
|
||||
Diff --> ReuseCheck{"选择的是 Reuse?"}
|
||||
ReuseCheck -->|"是,schema 完整"| ReuseDraft["展示 repo 文件与只读验证证据\n明确不会写 Base / Wiki"]
|
||||
ReuseCheck -->|"是,但发现 drift"| ReuseStop["停止;询问切换 Bootstrap\n或单独授权 schema repair"]
|
||||
ReuseCheck -->|"否"| BootstrapDraft["展示 repo 文件、缺失字段、Wiki 标题、POC 标题"]
|
||||
ReuseDraft --> ReuseConfirm{"用户确认 repo 文件?"}
|
||||
ReuseConfirm -->|"否"| ReuseDraft
|
||||
ReuseConfirm -->|"是"| RepoContract["生成 docs/agents/issue-tracker.md\n以及 triage/domain 合约"]
|
||||
BootstrapDraft --> BootstrapConfirm{"用户确认 Bootstrap 写入?"}
|
||||
BootstrapConfirm -->|"否"| BootstrapDraft
|
||||
BootstrapConfirm -->|"是"| Schema["只创建缺失字段;不静默转换冲突字段"]
|
||||
Schema --> WikiSetup["根节点下创建 Wiki setup 文档;append + fetch"]
|
||||
WikiSetup --> POC["创建 POC Base 记录;record-get"]
|
||||
POC --> RepoContract
|
||||
RepoContract --> Gate{"验证门通过?"}
|
||||
Gate -->|"否"| Report["报告具体错误、未运行项和边界"]
|
||||
Gate -->|"是"| Ready["其他 Matt skills 可开始消费"]
|
||||
```
|
||||
|
||||
### Setup 产物
|
||||
|
||||
- `AGENTS.md` 或 `CLAUDE.md` 中唯一的 `## Agent skills` 区块。
|
||||
- `docs/agents/issue-tracker.md`:真实 Base/Wiki 坐标、命令、字段与身份合约。
|
||||
- `docs/agents/triage-labels.md`:仅当 triage 已安装时生成。
|
||||
- `docs/agents/domain.md`:单 context 或多 context 的领域文档规则。
|
||||
- Reuse 模式不创建 Base 字段/记录或 Wiki 文档;只读验证既有资源并生成 repo-local 合约。
|
||||
- Bootstrap 模式额外创建一份 Wiki setup 文档,记录实际命令、字段、状态机、失败与修正、验证证据。
|
||||
- Bootstrap 模式额外创建一条 setup POC Base 记录,链接 Wiki 文档并证明写路径闭环;它不是每个项目的必跑步骤。
|
||||
|
||||
## 7. to-spec:从对话到可执行规格
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Context["对话 + 代码库 + Domain / ADR"] --> Seam["选择尽可能高的测试 seam"]
|
||||
Seam --> SeamConfirm{"用户确认 seam?"}
|
||||
SeamConfirm -->|"调整"| Seam
|
||||
SeamConfirm -->|"确认"| Draft["生成完整 Matt Spec"]
|
||||
Draft --> Search["按真实主字段精确查重"]
|
||||
Search --> Match{"精确匹配数量"}
|
||||
Match -->|"多个"| Disambiguate["停止并消歧"]
|
||||
Match -->|"一个,未明确修订"| Duplicate["停止并报告重复"]
|
||||
Match -->|"零个或明确修订"| CreateWiki["bot 在配置根节点下创建 Spec — 标题"]
|
||||
CreateWiki --> Append["append 完整 XML Spec"]
|
||||
Append --> Fetch{"docs +fetch 完整?"}
|
||||
Fetch -->|"否"| Stop["停止,不创建 Base"]
|
||||
Fetch -->|"是"| BaseSpec["创建或明确更新 Base Spec"]
|
||||
BaseSpec --> Parent["有来源 Issue 时写入所属父项"]
|
||||
Parent --> Readback["record-get 验证所有字段和最后更新人"]
|
||||
```
|
||||
|
||||
### Spec 产物契约
|
||||
|
||||
Wiki 文档标题为 `Spec — <标题>`,正文包含:Problem Statement、Solution、完整 User Stories、Implementation Decisions、Testing Decisions、Out of Scope 和 Further Notes。
|
||||
|
||||
对应 Base 记录至少包含:
|
||||
|
||||
| 字段 | 值 |
|
||||
|---|---|
|
||||
| `产物类型` | `PRD/Spec` |
|
||||
| `来源技能` | `to-spec` |
|
||||
| `工作流阶段` | `规格` |
|
||||
| `状态` | `ready-for-agent` |
|
||||
| `协作模式` | `AFK` |
|
||||
| `产物文档` | Wiki Spec 链接 |
|
||||
| `结论/摘要` | Problem + Solution 摘要 |
|
||||
| `验收标准` | 可执行、可验证条件 |
|
||||
| `所属父项` | 可选的来源 Issue record ID |
|
||||
| `最后更新人` | 当前已验证 CLI 用户 |
|
||||
|
||||
## 8. to-tickets:从 Spec 到垂直切片依赖图
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Spec["已确认 Spec / 计划"] --> Explore["可选:探索代码、prefactor 机会"]
|
||||
Explore --> Slice["拆成单上下文可完成的 tracer-bullet 垂直切片"]
|
||||
Slice --> Edges["为每张票声明真实 blocker"]
|
||||
Edges --> Quiz["用户确认粒度、合并/拆分和依赖边"]
|
||||
Quiz -->|"调整"| Slice
|
||||
Quiz -->|"批准"| ResolveParent["解析真实父 Spec record ID"]
|
||||
ResolveParent --> Search["逐标题查重;歧义时停止"]
|
||||
Search --> Pass1["第一遍:按依赖顺序创建全部 Ticket\n暂不写 blocker"]
|
||||
Pass1 --> IDs["保留每个返回的 record ID"]
|
||||
IDs --> Pass2["第二遍:写所属父项 + 前置依赖"]
|
||||
Pass2 --> Readback["逐条 record-get 验证父项、精确 blocker 集合、最后更新人"]
|
||||
Readback --> Frontier["frontier:所有 blocker 均完成且尚未认领的 Ticket"]
|
||||
```
|
||||
|
||||
每个 Ticket 是一条 Base 记录;V1 不创建独立 Wiki 文档。Ticket 的 `产物文档`留空,实现者沿 `所属父项`找到父 Spec,再取得其 Wiki 文档。
|
||||
|
||||
### 普通垂直切片
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["Ticket A\n完整可验证切片\n无 blocker"] -->|"解锁"| B["Ticket B\n消费 A 的稳定输出"]
|
||||
B -->|"解锁"| C["Ticket C\n继续扩展端到端行为"]
|
||||
```
|
||||
|
||||
### Wide refactor 的 expand–migrate–contract
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Expand["Expand\n新旧形式并存"] --> M1["Migrate batch 1"]
|
||||
Expand --> M2["Migrate batch 2"]
|
||||
Expand --> M3["Migrate batch N"]
|
||||
M1 --> Contract["Contract\n删除旧形式"]
|
||||
M2 --> Contract
|
||||
M3 --> Contract
|
||||
M1 --> Integrate["可选:integrate-and-verify"]
|
||||
M2 --> Integrate
|
||||
M3 --> Integrate
|
||||
```
|
||||
|
||||
## 9. triage:Issue / PR 分诊与可恢复上下文
|
||||
|
||||
### 关注队列
|
||||
|
||||
每次“显示需要关注的事项”都必须完整分页,并按创建时间从旧到新汇总三类:
|
||||
|
||||
1. `状态`为空或`待分诊`。
|
||||
2. `状态=needs-triage`。
|
||||
3. `状态=needs-info`且本地比较得到`最后反馈时间 > 最后分诊时间`。
|
||||
|
||||
不能用单页查询宣称“没有待处理事项”。报告人活动只更新时间,不直接改变状态;后续 triage run 再根据时间门禁重启分诊。
|
||||
|
||||
### Triage 状态机
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 待分诊
|
||||
待分诊 --> NeedsTriage: 初次进入维护者评估
|
||||
state "needs-triage" as NeedsTriage
|
||||
state "needs-info" as NeedsInfo
|
||||
state "ready-for-agent" as ReadyAgent
|
||||
state "ready-for-human" as ReadyHuman
|
||||
|
||||
NeedsTriage --> NeedsInfo: 信息不足
|
||||
NeedsInfo --> NeedsTriage: 报告人有新反馈\n且反馈时间晚于分诊时间
|
||||
NeedsTriage --> ReadyAgent: 事实充分且可委派
|
||||
NeedsTriage --> ReadyHuman: 需要人类判断、权限或手工工作
|
||||
NeedsTriage --> wontfix: 不实施
|
||||
|
||||
ReadyAgent --> 进行中: Agent 认领
|
||||
ReadyHuman --> 进行中: 人类认领
|
||||
进行中 --> 待评审
|
||||
待评审 --> 已完成
|
||||
wontfix --> [*]
|
||||
已完成 --> [*]
|
||||
```
|
||||
|
||||
每个已分诊项必须恰好拥有:
|
||||
|
||||
- 一个`类别`:`bug`或`enhancement`。
|
||||
- 一个 canonical triage `状态`。
|
||||
|
||||
推荐阶段只读、不写飞书;维护者确认后才更新类别、状态、时间、摘要、证据和下一步。
|
||||
|
||||
### Outcome 与叙述产物
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Outcome{"维护者确认的 outcome"}
|
||||
Outcome -->|"needs-info"| Notes["Wiki 追加 Triage Notes\n已确认事实 + 具体问题"]
|
||||
Outcome -->|"ready-for-agent"| Agent["Wiki 追加完整 Agent Brief"]
|
||||
Outcome -->|"ready-for-human"| Human["Wiki 追加 Human Brief\n注明不能委派原因"]
|
||||
Outcome -->|"wontfix"| Close["Wiki 追加关闭原因"]
|
||||
|
||||
Notes --> Fetch["fetch 最新 section"]
|
||||
Agent --> Fetch
|
||||
Human --> Fetch
|
||||
Close --> Fetch
|
||||
Fetch --> BasePatch["更新 Base 状态、产物文档、证据、下一步、时间、最后更新人"]
|
||||
|
||||
Outcome -->|"拒绝 enhancement"| OOS["repo .out-of-scope/<concept>.md\n唯一决定事实来源"]
|
||||
OOS --> CodeRef["Base 代码引用保存 repo 路径"]
|
||||
Outcome -->|"已实现请求或拒绝 bug"| NoOOS["不写 .out-of-scope/"]
|
||||
```
|
||||
|
||||
所有 AI 生成的 triage 文档 section 必须带免责声明。一个 Issue 只复用一份 `Triage — <标题>` dossier,后续 append,不为每个状态新建文档,也不覆盖历史。
|
||||
|
||||
## 10. 主执行状态机
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 草拟中
|
||||
草拟中 --> 待确认
|
||||
待确认 --> ReadyAgent: 可由 Agent 独立执行
|
||||
待确认 --> ReadyHuman: 需要人类处理
|
||||
state "ready-for-agent" as ReadyAgent
|
||||
state "ready-for-human" as ReadyHuman
|
||||
|
||||
ReadyAgent --> 进行中: 设置负责人并认领
|
||||
ReadyHuman --> 进行中: 人类认领
|
||||
进行中 --> 阻塞: 出现 blocker
|
||||
阻塞 --> 进行中: blocker 已解除
|
||||
进行中 --> 待评审
|
||||
待评审 --> 进行中: 评审要求修改
|
||||
待评审 --> 已完成: 验证证据充分
|
||||
|
||||
草拟中 --> 已取代: POC 或被新方案替代
|
||||
待确认 --> 已取代
|
||||
ReadyAgent --> 已取代
|
||||
进行中 --> 已取代
|
||||
|
||||
已完成 --> [*]
|
||||
已取代 --> [*]
|
||||
```
|
||||
|
||||
状态一致性规则:
|
||||
|
||||
- `状态=阻塞`时,`阻塞原因`和`下一步`必须非空。
|
||||
- 设置`已完成`前必须有具体`验证证据`;无法验证时写“未运行”及原因。
|
||||
- POC、废弃版本和超越记录进入`已取代`,不删除审计证据。
|
||||
- `完成度`、`下一步`和`阻塞原因`必须与`状态`一致。
|
||||
|
||||
## 11. 产物与关系模型
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
External["外部 Issue / PR / 表单"] -->|"来源链接、外部编号、报告人"| Issue["Base:需求/Issue"]
|
||||
Issue -->|"产物文档"| TriageDoc["Wiki:Triage dossier"]
|
||||
|
||||
Spec["Base:PRD/Spec"] -->|"所属父项"| Issue
|
||||
Spec -->|"产物文档"| SpecDoc["Wiki:Spec — 标题"]
|
||||
|
||||
TicketA["Base:实现 Ticket A"] -->|"所属父项"| Spec
|
||||
TicketB["Base:实现 Ticket B"] -->|"所属父项"| Spec
|
||||
TicketB -->|"前置依赖"| TicketA
|
||||
|
||||
TicketA -.->|"沿父项取得文档"| SpecDoc
|
||||
TicketB -.->|"沿父项取得文档"| SpecDoc
|
||||
|
||||
Issue -->|"代码引用"| RepoDecision["Repo:代码 / ADR / .out-of-scope/"]
|
||||
TicketA -->|"代码引用、验证证据"| Code["分支 / commit / PR / 测试"]
|
||||
TicketB -->|"代码引用、验证证据"| Code
|
||||
```
|
||||
|
||||
### 哪个系统保存什么
|
||||
|
||||
| 信息 | 事实来源 | 原因 |
|
||||
|---|---|---|
|
||||
| 当前状态、类别、负责人、进度、时间 | Base | 可筛选、排序、聚合和自动化 |
|
||||
| 父子关系、阻塞关系 | Base link 字段 | 可计算 frontier,不依赖文字解析 |
|
||||
| Spec、Triage Notes、Agent/Human Brief | Wiki / Docs | 长文档可读、可追加、可审计 |
|
||||
| 实现代码、测试、ADR、领域上下文 | repo | 与版本控制一致 |
|
||||
| 被拒绝 enhancement 的持久决定 | repo `.out-of-scope/` | 避免 Wiki 与 repo 产生两份决定事实 |
|
||||
| 命令、测试结果、回读事实 | Base `验证证据`,必要时 Wiki 详述 | 完成状态必须可核验 |
|
||||
|
||||
## 12. 身份与“最后更新人”
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant H as 真实用户
|
||||
participant C as Codex / 工作流
|
||||
participant A as lark-cli auth
|
||||
participant B as Feishu bot
|
||||
participant T as Base record
|
||||
|
||||
H->>C: 确认外部写入
|
||||
C->>A: auth status --json --verify
|
||||
A-->>C: bot verified + user verified + user.openId
|
||||
C->>C: 冻结 CURRENT_USER_OPEN_ID
|
||||
C->>B: --as bot 创建或更新记录
|
||||
B->>T: payload 包含最后更新人 = user.openId
|
||||
T-->>C: ok:true + record ID
|
||||
C->>T: record-get 回读
|
||||
T-->>C: 最后更新人显示真实用户
|
||||
```
|
||||
|
||||
这是一条业务审计契约,而不是飞书 UI 的系统“最后操作者”字段:
|
||||
|
||||
- 写入执行者:bot。
|
||||
- CLI 工作流真实发起者:`最后更新人`。
|
||||
- 当前工作责任人:`负责人`。
|
||||
- 每一次 Base create/update 都刷新`最后更新人`,包括仅修改状态、时间、关系、文档链接、证据或终态的 patch。
|
||||
- schema、view 和纯读操作没有行级归因目标,不写该字段。
|
||||
|
||||
## 13. Base 完整字段字典(29 个)
|
||||
|
||||
以下内容来自 2026-07-26 的实时 `field-list` 回读。
|
||||
|
||||
| # | 字段 | Field ID | 类型 / 取值 | 含义与使用规则 |
|
||||
|---:|---|---|---|---|
|
||||
| 1 | 文本 | `fldzLHLTca` | text,主字段 | 记录的业务标题;Spec/Ticket 查重使用真实主字段精确匹配。 |
|
||||
| 2 | 产物类型 | `fldlwQ46Ks` | single select:需求/Issue、PRD/Spec、实现 Ticket、Wayfinder Map、决策 Ticket、原型、研究、Handoff、ADR、领域词汇、Bug 诊断、代码评审、架构候选、教学资产 | 标识这条记录代表哪一种 Matt 工作流核心产物。 |
|
||||
| 3 | 来源技能 | `fldUMyVtoS` | multi-select:setup-matt-pocock-skills、grill-with-docs、grill-me、triage、diagnosing-bugs、wayfinder、to-spec、to-tickets、implement、tdd、code-review、improve-codebase-architecture、domain-modeling、prototype、research、handoff、teach | 记录创建或推进该产物的逻辑 Matt skills;使用逻辑流程名,不使用 Feishu 适配器后缀。 |
|
||||
| 4 | 工作流阶段 | `fldjAkNPqD` | single select:探索/澄清、决策、规格、拆票/规划、实现、验证/评审、交付、维护/学习、分诊 | 产物当前处于端到端流程的哪个阶段;与状态是两个维度。 |
|
||||
| 5 | 状态 | `fldHjFrlwJ` | single select:草拟中、待确认、待分诊、needs-triage、needs-info、ready-for-agent、ready-for-human、进行中、阻塞、待评审、已完成、wontfix、out-of-scope、已取代 | 全流程统一状态机;英文值保留 Matt triage canonical role 名称。 |
|
||||
| 6 | 类别 | `fldQWuceDX` | single select:bug、enhancement | Triage category role;每个被分诊项必须且只能有一个。 |
|
||||
| 7 | 决策票类型 | `fldFpkeDkj` | single select:research、prototype、grilling、task | Wayfinder 子决策票的处理方式;非决策票通常留空。 |
|
||||
| 8 | 协作模式 | `fldVwgWNRU` | single select:HITL、AFK | HITL 表示人类需要实时参与;AFK 表示 Agent 可独立推进。 |
|
||||
| 9 | 优先级 | `fldJv2ts2l` | single select:P0、P1、P2、P3 | 表示业务/执行优先级;与依赖 frontier 分开管理。 |
|
||||
| 10 | 负责人 | `fldGlPa1B1` | user,单值 | 当前直接执行责任人;必须使用真实飞书用户,不用纯文本姓名或 bot 代替。 |
|
||||
| 11 | 最后更新人 | `fld6nvDu18` | user,单值 | 最近一次通过 lark-cli 创建或更新该记录的真实人类用户;不代表飞书 UI 的 API 操作者。 |
|
||||
| 12 | 完成度 | `fldqNJjr0g` | number/progress,0–100% | 执行进度;需与当前状态保持一致。 |
|
||||
| 13 | 产物文档 | `fldorpkrbf` | text/plain | 该记录的 canonical Wiki/长文档链接;Spec 和 Triage dossier 使用,V1 Ticket 留空。 |
|
||||
| 14 | 验收标准 | `fldwbSY2pq` | text | 可验证完成条件;实现 Ticket 必填,Spec 保存主要测试/验收条件。 |
|
||||
| 15 | 验证证据 | `fldIQ0NQPO` | text | 实际命令、测试结果、复现、评审或 read-back 事实;终态的重要门禁。 |
|
||||
| 16 | 结论/摘要 | `fldmdDUJHh` | text | 决策结论、规格摘要、诊断根因、研究摘要或交付结果;长分析放 Wiki。 |
|
||||
| 17 | 阻塞原因 | `fldUsFDsTS` | text | 仅`阻塞`或`needs-info`时填写;说明当前为何不能继续。 |
|
||||
| 18 | 下一步 | `fldMY6XATm` | text | 解除阻塞或进入下一阶段所需的最小、直接动作。 |
|
||||
| 19 | 代码引用 | `fldNylIQ5y` | text | 分支、commit、PR、文件路径、review fixed point 或 `.out-of-scope/` 路径。 |
|
||||
| 20 | 截止时间 | `fldZP6Cm30` | datetime,`yyyy-MM-dd HH:mm` | 人工承诺的截止时间;不是自动推算时间。 |
|
||||
| 21 | 创建时间 | `fldnPF52hP` | created_at,只读 | 飞书自动记录的行创建时间;关注队列按此从旧到新排序。 |
|
||||
| 22 | 更新时间 | `fldd3rTk0I` | updated_at,只读 | 飞书自动记录的行更新时间;与业务归因字段不同。 |
|
||||
| 23 | 所属父项 | `flduS0iiPy` | self-link,双向 | Spec 指向来源 Issue、Ticket 指向父 Spec、决策 Ticket 指向 Wayfinder Map;写入真实 record ID。 |
|
||||
| 24 | 前置依赖 | `fldYkwZVu1` | self-link,双向 | 指向阻塞当前项的记录;所有依赖完成后当前项才进入 frontier。 |
|
||||
| 25 | 来源链接 | `fldp4F1S6m` | text/url | 原始 Issue、PR、表单或外部系统 URL。 |
|
||||
| 26 | 外部编号 | `fldpv8O5OW` | text | 原始外部系统编号;不能当作 Base record ID 使用。 |
|
||||
| 27 | 报告人 | `fld37AxlZf` | text | 报告人显示名或外部标识;兼容报告人不是飞书用户的场景。 |
|
||||
| 28 | 最后反馈时间 | `fldTwNj5Uz` | datetime,`yyyy-MM-dd HH:mm` | 报告人或外部来源最近一次新增反馈的时间。 |
|
||||
| 29 | 最后分诊时间 | `fldNy9eAgM` | datetime,`yyyy-MM-dd HH:mm` | 维护者最近一次确认并写回分诊结果的时间;与反馈时间比较决定 needs-info 是否重入队列。 |
|
||||
|
||||
### Link 字段边界
|
||||
|
||||
`所属父项`和`前置依赖`是自动化写入的正向事实来源。`lark-cli 1.0.76`可能返回同表双向关系的反向 field ID,但反向字段不一定能独立列出;在 CLI 明确回读证明前,不假设反向字段可以直接寻址。
|
||||
|
||||
## 14. 关键 CLI 操作模式
|
||||
|
||||
```bash
|
||||
# 身份门禁
|
||||
lark-cli auth status --json --verify
|
||||
|
||||
# Schema 与记录
|
||||
lark-cli base +field-list --base-token <BASE_TOKEN> --table-id <TABLE_ID> --limit 200 --as bot --format json
|
||||
lark-cli base +record-search --base-token <BASE_TOKEN> --table-id <TABLE_ID> --keyword "<TITLE>" --search-field <PRIMARY_FIELD> --as bot --format json
|
||||
lark-cli base +record-upsert --base-token <BASE_TOKEN> --table-id <TABLE_ID> --json '<FIELD_MAP>' --as bot --format json
|
||||
lark-cli base +record-upsert --base-token <BASE_TOKEN> --table-id <TABLE_ID> --record-id <RECORD_ID> --json '<PATCH>' --as bot --format json
|
||||
lark-cli base +record-get --base-token <BASE_TOKEN> --table-id <TABLE_ID> --record-id <RECORD_ID> --as bot --format json
|
||||
|
||||
# Wiki / Docs
|
||||
lark-cli wiki +node-create --space-id <SPACE_ID> --parent-node-token <ROOT_NODE_TOKEN> --obj-type docx --title "<TITLE>" --as bot --format json
|
||||
lark-cli docs +update --doc <OBJ_TOKEN> --command append --content @artifact.xml --doc-format xml --as bot --format json
|
||||
lark-cli docs +fetch --doc <OBJ_TOKEN> --detail with-ids --as bot --format json
|
||||
```
|
||||
|
||||
共同约束:
|
||||
|
||||
- `record-upsert`不会按业务标题自动去重;创建前必须查重。
|
||||
- link CellValue 必须使用真实 record ID,不能填标题或 Ticket 编号。
|
||||
- 文档先成功 fetch,再把 Wiki 链接和相应状态写入 Base。
|
||||
- 所有记录 create/update payload 都包含`最后更新人`。
|
||||
- 失败后不改用 user 身份,也不改到 Drive 或其他 Wiki 位置。
|
||||
|
||||
## 15. 已完成的真实 POC
|
||||
|
||||
### 应用身份全流程 POC
|
||||
|
||||
- bot 成功在指定 Wiki 根节点下创建独立 Spec 与 Triage 文档。
|
||||
- Wiki 创建结果返回正确的`parent_node_token`、`space_id`和自动用户权限。
|
||||
- Base 成功创建 Spec、两张 Ticket 和一条 Issue。
|
||||
- Ticket 父项和 blocker 边可回读。
|
||||
- Issue 完成`needs-info → reporter feedback → ready-for-agent`时间门禁。
|
||||
- 四条 POC Base 记录验收后均标记为`已取代`,Wiki 文档保留审计证据。
|
||||
|
||||
### 最后更新人 POC
|
||||
|
||||
| 产物 | Base record ID | 最终验证 |
|
||||
|---|---|---|
|
||||
| Spec | `recvqrDi2D3ky9` | bot 创建;`最后更新人=于选辉`;状态`已取代` |
|
||||
| Ticket A | `recvqrDoAyemKF` | 父项指向 Spec;归因正确;状态`已取代` |
|
||||
| Ticket B | `recvqrDoAyBBZB` | 父项指向 Spec;前置依赖仅指向 Ticket A;归因正确;状态`已取代` |
|
||||
| Issue | `recvqrDxnqoNUJ` | 完整 triage 状态流、时间门禁、Wiki Agent Brief、归因均通过;状态`已取代` |
|
||||
|
||||
相关文档:
|
||||
|
||||
- [Spec — 最后更新人全流程验证](https://oppeinlink.feishu.cn/wiki/Cu10w5D5CiWetKk6dVfcT52YnNJ)
|
||||
- [Triage — 状态归因闭环](https://oppeinlink.feishu.cn/wiki/IvpowYL0si7JbVk0TzocQ5yvnPf)
|
||||
- [Spec — 应用身份全流程验证](https://oppeinlink.feishu.cn/wiki/MacgwbOOpibGaEkH901cZ56AnCe)
|
||||
- [Triage — 应用身份反馈闭环](https://oppeinlink.feishu.cn/wiki/R9s0whJvGimchUkhnjlcM1wcnkd)
|
||||
|
||||
## 16. 当前验证状态与边界
|
||||
|
||||
- Base schema 实时回读:29 个字段,`产物文档`唯一存在。
|
||||
- Wiki 根节点完整分页:5 个直属子文档,`has_more=false`。
|
||||
- 双身份验证:bot 和 user 均为 verified。
|
||||
- 四个新 skill 均有`agents/openai.yaml`;受影响 skill 已通过`quick_validate.py`。
|
||||
- 所有相关本地 skill、Wiki 文档和当前 vault 中,已移除被替换字段名的旧引用。
|
||||
- Ticket V1 有意不创建 Wiki 文档;其长上下文来自父 Spec。
|
||||
- `负责人`若无法解析为真实飞书用户就留空并报告,不能填 bot 或伪造数据。
|
||||
- 未验证的命令、状态或产物不能写成“已完成”;需明确标记“未运行”及原因。
|
||||
|
||||
## 17. 最小心智模型
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Issue["Issue\n要解决什么"] --> Spec["Spec\n为什么与验收边界"]
|
||||
Spec --> Tickets["Tickets\n可独立交付的垂直切片"]
|
||||
Tickets --> Work["实现 / 测试 / 评审"]
|
||||
Work --> Evidence["验证证据"]
|
||||
Evidence --> Done["已完成"]
|
||||
|
||||
Base["Base"] -.->|"管理状态、关系、责任、时间"| Issue
|
||||
Base -.-> Spec
|
||||
Base -.-> Tickets
|
||||
Wiki["Wiki"] -.->|"保存 Spec 与 Triage 叙述"| Spec
|
||||
Repo["Repo"] -.->|"保存代码、测试、ADR、决定"| Work
|
||||
```
|
||||
|
||||
一句话总结:**Base 回答“现在是什么状态、由谁负责、依赖谁”,Wiki 回答“为什么这样做、具体要求是什么”,repo 回答“实现和验证事实是什么”;四个 Feishu skills 负责在三者之间建立可回读、可审计的连接。**
|
||||
@@ -1,759 +0,0 @@
|
||||
# Matt 工作流 × 飞书 Skills × Trellis Coding 闭环总结
|
||||
|
||||
> 状态:六个 Feishu workflow skills 已落地;Coding 入队、Trellis 映射、Ticket 部分收口和 Spec 最终收口已通过真实 Base POC。
|
||||
> 更新时间:2026-07-27
|
||||
> 实际验证项目:`/Users/yuxuanhui/Documents/ai-workflow/project/经销商政策`
|
||||
> 范围:工作进入、需求澄清、Spec、Tickets、Triage、Inline/Trellis Coding 路由、实现证据、部分收口、归档和最终对账。具体编码规范仍由目标项目自己的 Trellis specs 和 coding skills 决定。
|
||||
|
||||
## 1. 最终结论
|
||||
|
||||
这次工作补齐了 Matt 工作流在飞书上的实现侧闭环。现在不只是把需求和计划放进 Base/Wiki,还可以从 Base 选择当前用户负责的工作,路由到 Inline 或 Trellis,实现后按 Ticket 逐步验收,最后在严格门禁下关闭父 Spec。
|
||||
|
||||
当前完整模型是:
|
||||
|
||||
- **Feishu Base** 管业务状态、责任人、父子关系、依赖、进度和可查询队列。
|
||||
- **Feishu Wiki / Docs** 管 Spec、Triage Notes、Agent Brief、Human Brief 等长文档。
|
||||
- **Trellis** 管复杂开发的本地任务生命周期、规划产物、执行快照、checkpoint、归档和 journal。
|
||||
- **repo** 管代码、测试、commit、ADR、领域知识和可回放的实现证据。
|
||||
- **用户** 决定开始哪项工作,并对每张 Ticket 和最终 Spec 分别执行人类 review。
|
||||
- **Agent** 负责查询、分析、路由、组织证据和提出精确 patch,但不能绕过人类 review 决定终态。
|
||||
- **lark-cli bot** 执行 API;当前已验证人类用户写入 `最后更新人`;`负责人`始终表示工作责任,不被 bot 或操作归因覆盖。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
U["用户<br/>选择、review、确认外部写入"] --> Skills["六个 Feishu workflow skills<br/>流程编排与门禁"]
|
||||
Skills --> Auth["lark-cli 身份门禁<br/>bot + user verified"]
|
||||
|
||||
Auth -->|"--as bot"| Base["Feishu Base<br/>状态、关系、队列、责任"]
|
||||
Auth -->|"--as bot"| Wiki["Feishu Wiki / Docs<br/>Spec 与长叙述"]
|
||||
Skills --> Trellis["Trellis<br/>复杂任务生命周期与本地上下文"]
|
||||
Skills --> Repo["Repository<br/>代码、测试、commit、ADR"]
|
||||
|
||||
Wiki -->|"产物文档"| Base
|
||||
Base -->|"record IDs + 验收边界"| Trellis
|
||||
Base -->|"Tickets / frontier"| Trellis
|
||||
Trellis -->|"checkpoint / archive"| Skills
|
||||
Repo -->|"验证证据 / 代码引用"| Skills
|
||||
Skills -->|"最小 patch + 回读"| Base
|
||||
```
|
||||
|
||||
## 2. 六个 Feishu workflow skills
|
||||
|
||||
六个 skills 都是全局 skill,source of truth 位于 `~/.agents/skills/<skill-name>/`。它们都配置了 `policy.allow_implicit_invocation: false`,因此涉及真实飞书读写时要求显式调用,不靠模糊意图静默修改外部系统。
|
||||
|
||||
| Skill | 负责的阶段 | 主要输入 | 主要产物 | 明确不负责 |
|
||||
|---|---|---|---|---|
|
||||
| `setup-workflow-skills-feishu` | 仓库接入 | Base URL、Wiki 根 URL、Reuse/Bootstrap 选择 | repo tracker 合约;Bootstrap 时创建 schema、setup Wiki 文档和 POC 记录 | 不在 Reuse 模式修 schema;不猜资源地址 |
|
||||
| `to-spec-feishu` | 对话 → 可执行规格 | 已澄清对话、代码库、领域词汇、测试 seam | 一份 Wiki Spec + 一条 Base `PRD/Spec` | 不采访式重新澄清;不在 Wiki 未回读前创建 Base Spec |
|
||||
| `to-tickets-feishu` | Spec → 垂直切片 | 已批准 Spec、Ticket 粒度、依赖边 | 每个切片一条 Base `实现 Ticket` | V1 不为 Ticket 创建 Wiki;不关闭或修改父 Spec |
|
||||
| `triage-feishu` | Issue/PR 分诊 | 外部请求、代码验证、维护者决定、报告人反馈 | Base Issue 状态 + 可选 Wiki Triage dossier | 不在推荐阶段写状态;不重复创建 dossier |
|
||||
| `start-work-feishu` | Coding 入队 | 当前用户、Spec/Ticket 队列、用户选择、路由确认 | Inline 会话绑定,或 `1 Spec = 1 task` 的 Trellis mapping;Base `进行中`回写 | 不实现代码;不初始化 Trellis;不启动 sibling Tickets |
|
||||
| `close-work-feishu` | Coding 收口 | Spec/Tickets、repo/Trellis 证据、人类 review、确认 patch | Ticket 部分收口、Spec 最终收口、失败后的幂等对账 | 不根据测试或 archive 自动完成;不替用户选择完成项 |
|
||||
|
||||
### 2.1 Skill 之间的调用关系
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Setup["setup-workflow-skills-feishu<br/>建立项目级 tracker 合约"] --> Intake{"工作从哪里进入?"}
|
||||
|
||||
Intake -->|"已澄清想法 / 对话"| Spec["to-spec-feishu<br/>Wiki Spec + Base Spec"]
|
||||
Intake -->|"Issue / PR / 表单"| Triage["triage-feishu<br/>分类、验证、澄清、Brief"]
|
||||
|
||||
Triage -->|"needs-info"| Feedback["等待报告人反馈"]
|
||||
Feedback -->|"最后反馈时间 > 最后分诊时间"| Triage
|
||||
Triage -->|"ready-for-agent 且需要正式规格"| Spec
|
||||
Triage -->|"ready-for-agent 且已足够明确"| Start
|
||||
Triage -->|"ready-for-human"| Human["人类处理"]
|
||||
Triage -->|"wontfix / out-of-scope"| Stop["保留关闭原因与审计记录"]
|
||||
|
||||
Spec --> Tickets["to-tickets-feishu<br/>Base Ticket 依赖图"]
|
||||
Spec --> Start["start-work-feishu<br/>选择并开始"]
|
||||
Tickets --> Start
|
||||
|
||||
Start --> Coding["Inline 或 Trellis Coding"]
|
||||
Coding --> Close["close-work-feishu<br/>部分 / 最终 / 对账"]
|
||||
Close -->|"仍有未完成 Ticket"| Coding
|
||||
Close -->|"全部门禁满足"| Done["Base Spec 已完成<br/>工作流闭环"]
|
||||
```
|
||||
|
||||
## 3. 端到端工作流总图
|
||||
|
||||
下面这张图把需求侧、规划侧、实现侧和收口侧放在同一条链路中。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["仓库首次接入"] --> B["Setup:验证 Base/Wiki、生成 docs/agents 合约"]
|
||||
B --> C{"请求入口"}
|
||||
|
||||
C -->|"外部 Issue / PR / 表单"| D["Triage:验证事实与分类"]
|
||||
D --> D1{"维护者 outcome"}
|
||||
D1 -->|"needs-info"| D2["Wiki Triage Notes<br/>等待反馈"]
|
||||
D2 --> D
|
||||
D1 -->|"ready-for-human"| D3["Human Brief / 人类处理"]
|
||||
D1 -->|"wontfix"| D4["关闭说明<br/>必要时 repo .out-of-scope"]
|
||||
D1 -->|"ready-for-agent"| E{"是否需要正式 Spec?"}
|
||||
|
||||
C -->|"已澄清对话"| F["to-spec:确认测试 seam"]
|
||||
E -->|"是"| F
|
||||
E -->|"否,范围足够小"| J
|
||||
|
||||
F --> G["Wiki Spec 写入并 fetch 回读"]
|
||||
G --> H["Base Spec:ready-for-agent"]
|
||||
H --> I{"是否需要拆 Ticket?"}
|
||||
I -->|"是"| I1["to-tickets:垂直切片 + blocker 图"]
|
||||
I -->|"否,简单 Spec"| J["start-work:工作队列"]
|
||||
I1 --> J
|
||||
|
||||
J --> K["用户选择 record ID"]
|
||||
K --> L["写前重读:负责人、状态、父项、依赖、更新时间"]
|
||||
L --> M{"Inline 还是 Trellis?"}
|
||||
|
||||
M -->|"Inline"| N["冻结当前会话 record IDs"]
|
||||
M -->|"Trellis"| O["查找/创建唯一 task<br/>持久化 mapping 与 artifacts"]
|
||||
N --> P["用户确认选择、路由和开始 patch"]
|
||||
O --> P
|
||||
P --> Q["Base 写进行中 + 实现 + 最后更新人"]
|
||||
Q --> R["record-get 回读"]
|
||||
R -->|"Trellis 新任务"| S["task.py start → in_progress"]
|
||||
R -->|"Inline"| T["Coding 与验证"]
|
||||
S --> T
|
||||
|
||||
T --> U["收集 diff、测试、浏览器验收、未运行项、代码引用"]
|
||||
U --> V["close-work:逐 Ticket 验收映射"]
|
||||
V --> W["人类 review 并选择可关闭 Ticket IDs"]
|
||||
W --> X["Ticket 最小 patch + 逐条回读"]
|
||||
X --> Y{"所有子 Tickets 已完成?"}
|
||||
Y -->|"否"| T
|
||||
|
||||
Y -->|"是"| Z{"最终 Spec 门禁"}
|
||||
Z -->|"Inline:Spec 证据 + 人类最终 review"| Z1["展示 Spec-only patch"]
|
||||
Z -->|"Trellis:再加 archive + status=completed"| Z1
|
||||
Z1 --> Z2["用户第二次确认 Spec patch"]
|
||||
Z2 --> Z3["更新 Spec + record-get 回读"]
|
||||
Z3 --> End["最终闭环完成"]
|
||||
```
|
||||
|
||||
## 4. 四类事实源与产物关系
|
||||
|
||||
### 4.1 产物关系总图
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
External["外部 Issue / PR / 表单"] -->|"来源链接 / 外部编号 / 报告人"| Issue["Base:需求/Issue"]
|
||||
Issue -->|"产物文档"| TriageDoc["Wiki:Triage — 标题"]
|
||||
|
||||
Spec["Base:PRD/Spec"] -->|"所属父项"| Issue
|
||||
Spec -->|"产物文档"| SpecDoc["Wiki:Spec — 标题"]
|
||||
|
||||
Ticket1["Base:实现 Ticket A"] -->|"所属父项"| Spec
|
||||
Ticket2["Base:实现 Ticket B"] -->|"所属父项"| Spec
|
||||
Ticket2 -->|"前置依赖"| Ticket1
|
||||
|
||||
Spec -->|"specRecordId,一对一"| Task["Trellis task"]
|
||||
Ticket1 -.->|"ticketRecordIds / snapshot"| Task
|
||||
Ticket2 -.->|"ticketRecordIds / snapshot"| Task
|
||||
|
||||
Task --> PRD["prd.md<br/>Spec 来源与验收边界"]
|
||||
Task --> Design["design.md<br/>复杂任务技术设计"]
|
||||
Task --> Impl["implement.md<br/>Ticket frontier + checkpoint"]
|
||||
Task --> JSONL["implement.jsonl / check.jsonl<br/>必要 spec / research 清单"]
|
||||
Task --> Archive["archive task.json<br/>status=completed"]
|
||||
|
||||
Repo["repo:代码 / 测试 / ADR / commits"] -->|"验证证据 / 代码引用"| Ticket1
|
||||
Repo -->|"验证证据 / 代码引用"| Ticket2
|
||||
Archive -->|"最终生命周期门禁"| Spec
|
||||
Ticket1 -->|"全部严格已完成"| Spec
|
||||
Ticket2 -->|"全部严格已完成"| Spec
|
||||
```
|
||||
|
||||
### 4.2 哪个系统保存什么
|
||||
|
||||
| 信息 | 事实来源 | 说明 |
|
||||
|---|---|---|
|
||||
| 当前业务状态、负责人、完成度、优先级、时间 | Base | 面向队列、筛选、自动化和团队可见性 |
|
||||
| 父子层级和 blocker 边 | Base `所属父项`、`前置依赖` | 使用真实 record ID;用于计算 frontier |
|
||||
| Spec 与 Triage 长叙述 | Wiki / Docs | 可读、可追加、可审计 |
|
||||
| 复杂任务的本地生命周期 | Trellis | planning、in_progress、archive、journal |
|
||||
| 当前复杂任务的执行快照 | Trellis `prd.md`、`implement.md` | 可从 Base/Wiki 刷新,不反向覆盖 Base 业务事实 |
|
||||
| 代码、测试、commit、ADR、领域知识 | repo | 版本控制事实来源 |
|
||||
| 完成证明 | Base `验证证据` + `代码引用` | 内容来自 repo、真实命令、浏览器验收和 Trellis checkpoint |
|
||||
| 被拒绝 enhancement 的持久决定 | repo `.out-of-scope/` | Wiki 只记录 outcome/link,不复制第二份 canonical decision |
|
||||
|
||||
## 5. Setup、Spec、Tickets 与 Triage 的逻辑
|
||||
|
||||
### 5.1 Setup:建立可执行 tracker 合约
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["读取仓库现状"] --> B["用户提供 Base URL + Wiki 根 URL"]
|
||||
B --> C{"Setup 模式"}
|
||||
C -->|"Reuse,推荐"| D["只读验证身份、资源和完整 schema"]
|
||||
C -->|"Bootstrap"| E["展示缺失字段、Wiki setup 标题、POC 标题"]
|
||||
D --> F{"29 字段兼容?"}
|
||||
F -->|"否"| G["停止;询问切换 Bootstrap 或单独 repair 授权"]
|
||||
F -->|"是"| H["展示 repo-local 合约草案"]
|
||||
E --> I["用户确认外部写入"]
|
||||
I --> J["只创建缺失字段"]
|
||||
J --> K["创建 Wiki setup 文档并 fetch"]
|
||||
K --> L["创建 POC Base 记录并 record-get"]
|
||||
L --> H
|
||||
H --> M["生成 AGENTS/CLAUDE Agent skills 区块"]
|
||||
M --> N["生成 docs/agents/issue-tracker.md"]
|
||||
N --> O["生成 domain / triage 合约"]
|
||||
```
|
||||
|
||||
Setup 的关键产物是项目级 `docs/agents/issue-tracker.md`。后续所有 Feishu skills 必须先读它,从中取得真实 Base、table、view、主字段、Wiki root、字段取值、身份和完成门禁,不能从别的项目或相似标题推断资源。
|
||||
|
||||
### 5.2 to-spec:一份长规格 + 一条可查询记录
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as 用户
|
||||
participant S as to-spec-feishu
|
||||
participant W as Wiki / Docs
|
||||
participant B as Base
|
||||
|
||||
S->>S: 读取对话、代码库、领域词汇和 ADR
|
||||
S-->>U: 提议最高可用测试 seam
|
||||
U->>S: 确认 seam
|
||||
S->>B: 按真实主字段精确查重
|
||||
S->>W: 创建 Spec — 标题
|
||||
S->>W: append 完整 Spec XML
|
||||
S->>W: docs +fetch
|
||||
alt Wiki 内容完整
|
||||
S->>B: 创建 PRD/Spec 记录
|
||||
S->>B: record-get 回读全部字段
|
||||
else Wiki 写入或 fetch 不完整
|
||||
S-->>U: 停止,不创建 Base Spec
|
||||
end
|
||||
```
|
||||
|
||||
Wiki Spec 包含 Problem Statement、Solution、User Stories、Implementation Decisions、Testing Decisions、Out of Scope 和 Further Notes。Base Spec 保存 `ready-for-agent`、Wiki 链接、摘要、验收标准和可选来源 Issue。
|
||||
|
||||
### 5.3 to-tickets:两遍发布依赖图
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Spec["已批准 Spec"] --> Slice["拆成单上下文可验证的 tracer-bullet"]
|
||||
Slice --> Edge["声明真实 blocker"]
|
||||
Edge --> Quiz["用户确认粒度、拆分、合并和依赖"]
|
||||
Quiz -->|"调整"| Slice
|
||||
Quiz -->|"批准"| Parent["解析父 Spec record ID"]
|
||||
Parent --> Search["逐标题查重"]
|
||||
Search --> Pass1["Pass 1:按依赖顺序创建 Ticket<br/>暂不写 blocker"]
|
||||
Pass1 --> IDs["冻结返回的 record IDs"]
|
||||
IDs --> Pass2["Pass 2:写所属父项 + 前置依赖"]
|
||||
Pass2 --> Verify["逐条回读父项、blocker 集、验收和最后更新人"]
|
||||
Verify --> Frontier["frontier = 状态可开始<br/>且每个 blocker 恰好为已完成"]
|
||||
```
|
||||
|
||||
Ticket V1 不创建 Wiki 文档,`产物文档`留空。实现者通过 `所属父项`找到父 Spec,再从父 Spec 的 `产物文档`取得完整规格。
|
||||
|
||||
### 5.4 triage:请求进入工程流程的 on-ramp
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 待分诊
|
||||
待分诊 --> NeedsTriage: 维护者开始评估
|
||||
state "needs-triage" as NeedsTriage
|
||||
state "needs-info" as NeedsInfo
|
||||
state "ready-for-agent" as ReadyAgent
|
||||
state "ready-for-human" as ReadyHuman
|
||||
|
||||
NeedsTriage --> NeedsInfo: 信息不足,写 Triage Notes
|
||||
NeedsInfo --> NeedsTriage: 最后反馈时间晚于最后分诊时间
|
||||
NeedsTriage --> ReadyAgent: 事实与验收足够,可委派
|
||||
NeedsTriage --> ReadyHuman: 需要判断、权限或手工工作
|
||||
NeedsTriage --> wontfix: 不实施
|
||||
|
||||
ReadyAgent --> 进行中: 被 start-work 认领
|
||||
ReadyHuman --> 进行中: 人类认领
|
||||
wontfix --> [*]
|
||||
```
|
||||
|
||||
Triage 的推荐与验证阶段只读。维护者确认 outcome 后,才写唯一 `类别`、唯一 canonical `状态`、`最后分诊时间`、摘要、证据、下一步和 `最后更新人`。需要长叙述时,一个 Issue 只创建并持续 append 一份 `Triage — <标题>` Wiki dossier。
|
||||
|
||||
## 6. `start-work-feishu`:Coding 入队与路由
|
||||
|
||||
### 6.1 队列口径
|
||||
|
||||
Skill 会冻结当前已验证用户的 open ID,然后分别完整分页查询:
|
||||
|
||||
- Spec:`产物类型=PRD/Spec`,且 **Spec 自身** `负责人=当前用户`。
|
||||
- Ticket:`产物类型=实现 Ticket`,且 **Ticket 自身** `负责人=当前用户`。
|
||||
|
||||
子 Ticket 归当前用户不会让父 Spec 自动进入 Spec 队列。父 Spec 只作为 Ticket 的上下文展示。
|
||||
|
||||
| 分组 | 条件 | 是否可选择 |
|
||||
|---|---|---|
|
||||
| 可恢复 | `进行中`或`阻塞` | 可以,但阻塞项必须展示原因,不暗示已解除 |
|
||||
| 可开始 | `ready-for-agent`;Ticket 无 blocker 或所有 blocker 都恰好为`已完成` | 可以 |
|
||||
| 待收口 | `待评审` | 不重新开始,转 `close-work-feishu` |
|
||||
| 被阻塞 | `ready-for-agent`,但任一 blocker 不是`已完成` | 不可开始 |
|
||||
| 排除 | 草拟、triage、人类专属和终态记录 | 不进入 coding queue |
|
||||
|
||||
`wontfix`、`out-of-scope`、`已取代`虽然是终态,但不能自动证明依赖要求已交付,因此不算满足 blocker。
|
||||
|
||||
### 6.2 Start skill 内部逻辑
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["显式调用 start-work-feishu"] --> B["读取项目 tracker 合约与 Trellis workflow"]
|
||||
B --> C["验证 bot + user,冻结当前 user open ID"]
|
||||
C --> D["field-list 验证 29 字段和枚举"]
|
||||
D --> E["完整分页查询 Spec 队列"]
|
||||
E --> F["完整分页查询 Ticket 队列"]
|
||||
F --> G["按 record ID 读取父项与 blocker"]
|
||||
G --> H["计算可恢复 / 可开始 / 待收口 / 被阻塞"]
|
||||
H --> I["用户选择 number 或 record ID"]
|
||||
I --> J["重读选中项、父 Spec、全部子 Tickets、blockers"]
|
||||
J --> K{"负责人、状态、关系或更新时间漂移?"}
|
||||
K -->|"是"| H
|
||||
K -->|"否"| L{"建议路由"}
|
||||
|
||||
L -->|"小、明确、单上下文"| M["Inline:冻结本会话 IDs 与快照"]
|
||||
L -->|"跨模块、多会话、长验收链"| N["Trellis:扫描现有 mapping"]
|
||||
N --> O{"匹配 task 数量"}
|
||||
O -->|"多个"| Stop["停止,报告冲突"]
|
||||
O -->|"一个"| Resume["恢复已有 task"]
|
||||
O -->|"零个"| Create["task.py create --no-start"]
|
||||
Resume --> Persist["刷新 prd / implement / mapping"]
|
||||
Create --> Persist
|
||||
Persist --> ReadMap["回读完整 meta.feishuTracker"]
|
||||
|
||||
M --> Confirm["一次确认:工作项 + 路由 + Base patch"]
|
||||
ReadMap --> Confirm
|
||||
Confirm --> Patch["按 record ID 写进行中 / 实现 / 最后更新人"]
|
||||
Patch --> ReadBase["逐条 record-get 回读"]
|
||||
ReadBase --> Route{"路由"}
|
||||
Route -->|"Inline"| Coding["交给当前会话实现"]
|
||||
Route -->|"新建或 planning task"| Start["task.py start"]
|
||||
Start --> VerifyTask["回读 task.json status=in_progress"]
|
||||
```
|
||||
|
||||
### 6.3 Inline 与 Trellis 的判断
|
||||
|
||||
| 路由 | 适用情况 | 本地持久化 |
|
||||
|---|---|---|
|
||||
| Inline | 范围窄、方案已知、一个健康上下文可完成、最低验证可在当前会话完成 | 只在当前对话冻结 record IDs,不创建 mapping 文件 |
|
||||
| Trellis | 跨模块、多阶段、多个稳定决策、durable research、多会话或验收链较长 | 创建或恢复唯一 task,持久化 Spec mapping、规划产物和 Ticket snapshot |
|
||||
|
||||
这里的 Inline 是“完全不创建 Trellis task”。它和 Trellis 内部 Codex `dispatch_mode=inline`不是同一概念;后者仍然已经处在 Trellis task 内。
|
||||
|
||||
### 6.4 `1 Spec = 1 Trellis task` mapping
|
||||
|
||||
```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": "ISO-8601",
|
||||
"lastRefreshAt": "ISO-8601"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `specRecordId` 是一对一绑定的稳定键。
|
||||
- `ticketRecordIds` 是刷新时全部子 Tickets 的排序去重快照,不是 Base 的替代事实源。
|
||||
- `selectedRecordIds` 是这次用户直接选择的 Spec 或 Ticket。
|
||||
- `boundAt` 首次绑定后不变;`lastRefreshAt` 随成功刷新更新。
|
||||
- mapping 不保存 Base token、凭证或固定个人 open ID。
|
||||
- 只更新 `meta.feishuTracker`,保留 `task.json`其他字段和未知未来键。
|
||||
|
||||
### 6.5 开始 patch
|
||||
|
||||
```json
|
||||
{
|
||||
"状态": "进行中",
|
||||
"工作流阶段": "实现",
|
||||
"最后更新人": [{"id": "<CURRENT_USER_OPEN_ID>"}]
|
||||
}
|
||||
```
|
||||
|
||||
- 选择 Spec:只写 Spec。
|
||||
- 选择 Ticket:写选中的 Ticket 和它的父 Spec。
|
||||
- 不修改`负责人`、`完成度`、sibling Tickets、证据、blocker 或下一步。
|
||||
- Trellis 新任务只有在 mapping 持久化成功、Base 写入成功且回读一致后才执行 `task.py start`。
|
||||
|
||||
## 7. Trellis Coding 生命周期
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> planning: task.py create --no-start
|
||||
planning --> in_progress: task.py start
|
||||
in_progress --> in_progress: implement / check / update-spec / commit
|
||||
in_progress --> Detached: task.py finish
|
||||
state "session detached\n任务未完成" as Detached
|
||||
Detached --> in_progress: 其他 session 可继续
|
||||
in_progress --> completed: task.py archive
|
||||
completed --> Archived: 移入 archive tree
|
||||
state "archive/task.json\nstatus=completed" as Archived
|
||||
```
|
||||
|
||||
关键边界:
|
||||
|
||||
- `task.py finish`只清除当前 session 的任务指针,不能作为 Base 完成信号。
|
||||
- 复杂任务通常经历 `implement → check → update-spec → 工作 commit → finish-work/archive → journal`。
|
||||
- `after_archive`最多作为提醒或待对账信号;显式 `close-work-feishu`才有资格在回读后声称 Base 已闭环。
|
||||
- Ticket 部分收口不要求 archive;父 Spec 最终收口才要求归档 task 且`status=completed`。
|
||||
|
||||
## 8. `close-work-feishu`:部分收口、最终收口与对账
|
||||
|
||||
### 8.1 三个内部 routing
|
||||
|
||||
| Routing | 进入条件 | 结果 |
|
||||
|---|---|---|
|
||||
| 部分收口 | 有一个或多个 Ticket 已有直接证据,并完成对应人类 review | 只关闭用户选中的 Ticket;Spec 保持`进行中` |
|
||||
| 最终收口 | 全部 Ticket 已完成,Spec 验收有证据,人类完成最终 review;Trellis 路径还必须 archive | 用户再次确认 Spec-only patch 后关闭 Spec |
|
||||
| 对账重放 | 上次写入部分成功、回读失败或记录已在目标终态 | 只补差异;证据完整时返回`already synchronized`,不重复追加 |
|
||||
|
||||
### 8.2 Close skill 完整逻辑
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["显式调用 close-work-feishu"] --> B["用 active/archived mapping 或 Inline 会话定位 Spec ID"]
|
||||
B --> C["验证身份、schema、Spec 类型"]
|
||||
C --> D["按父 Spec 完整分页查询全部子 Tickets"]
|
||||
D --> E["比较 live Ticket 集与 Trellis snapshot"]
|
||||
E --> F["汇总验收标准、repo diff、测试、浏览器验收、未运行项、代码引用、checkpoint"]
|
||||
F --> G["逐 Ticket 映射验收证据"]
|
||||
G --> H{"分类"}
|
||||
H --> H1["建议可收口"]
|
||||
H --> H2["待补证 / 待验证"]
|
||||
H --> H3["明确未完成 / 阻塞"]
|
||||
|
||||
H1 --> I["展示精确 Ticket patch"]
|
||||
H2 --> Wait["保持原状态,说明最小下一步"]
|
||||
H3 --> Wait
|
||||
I --> J["用户声明已完成人类 review<br/>并选择允许关闭的 record IDs"]
|
||||
J --> K["写前逐条重读,检查 owner、状态、父项、依赖、验收、证据、更新时间"]
|
||||
K --> L{"是否漂移?"}
|
||||
L -->|"是"| I
|
||||
L -->|"否"| M["批量最小 patch,最多 200 条且串行"]
|
||||
M --> N["逐条 record-get 回读"]
|
||||
N --> O{"失败 / ignored / mismatch?"}
|
||||
O -->|"是"| Reconcile["输出成功、失败、待对账清单<br/>禁止关闭 Spec"]
|
||||
O -->|"否"| P["重新完整查询所有子 Tickets"]
|
||||
P --> Q{"是否全部严格为已完成?"}
|
||||
Q -->|"否"| Partial["部分收口完成<br/>Spec 保持进行中"]
|
||||
Q -->|"是"| R{"Spec 级最终门禁"}
|
||||
R -->|"未满足"| Hold["Spec 不变,报告缺失门禁"]
|
||||
R -->|"满足"| S["展示独立 Spec-only patch"]
|
||||
S --> T["用户第二次确认"]
|
||||
T --> U["立即重读 Spec;漂移则确认失效"]
|
||||
U --> V["写 Spec + record-get 回读"]
|
||||
V --> Done["最终收口回执"]
|
||||
```
|
||||
|
||||
### 8.3 Ticket 完成 patch
|
||||
|
||||
```json
|
||||
{
|
||||
"状态": "已完成",
|
||||
"工作流阶段": "交付",
|
||||
"完成度": 1,
|
||||
"验证证据": "<保留旧内容并追加一次 Ticket 专属 closure section>",
|
||||
"代码引用": "<保留并去重的真实引用>",
|
||||
"阻塞原因": null,
|
||||
"下一步": null,
|
||||
"最后更新人": [{"id": "<CURRENT_USER_OPEN_ID>"}]
|
||||
}
|
||||
```
|
||||
|
||||
每个 closure section 至少记录:人类 review、验收到证据的映射、真实验证命令和结果、明确未运行项及原因。不能用 Agent review、测试通过、Trellis `finish`或 archive 单独替代人类 review。
|
||||
|
||||
### 8.4 Spec 最终门禁
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["全部子 Tickets<br/>状态恰好为已完成"] --> Gate{"Spec 最终门禁"}
|
||||
B["Spec 每条验收标准<br/>都有直接证据"] --> Gate
|
||||
C["用户完成 Spec<br/>最终代码/功能 review"] --> Gate
|
||||
D["Trellis 路径:task 位于 archive<br/>且 status=completed"] --> Gate
|
||||
E["不存在 Ticket write/read-back 失败"] --> Gate
|
||||
Gate -->|"全部满足"| Patch["展示 Spec-only patch"]
|
||||
Patch --> Confirm["用户单独确认"]
|
||||
Confirm --> Done["写入 + 回读后才算闭环"]
|
||||
```
|
||||
|
||||
`wontfix`、`out-of-scope`、`已取代`不自动算作“全部 Ticket 已完成”。无 Ticket 的简单 Spec 可以跳过 Ticket 门禁,但仍需 Spec 验收证据、人类最终 review,以及适用的 Trellis archive 门禁。
|
||||
|
||||
## 9. 身份、确认与写后回读协议
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as 用户
|
||||
participant S as Feishu skill
|
||||
participant A as lark-cli auth
|
||||
participant B as Feishu Base
|
||||
|
||||
U->>S: 显式调用 skill
|
||||
S->>A: auth status --json --verify
|
||||
A-->>S: bot verified + user verified + user.openId
|
||||
S->>S: 冻结 CURRENT_USER_OPEN_ID
|
||||
S->>B: --as bot 读取 schema / records
|
||||
B-->>S: 当前快照
|
||||
S-->>U: 展示稳定 record IDs 与精确 patch
|
||||
U->>S: 明确确认外部写入
|
||||
S->>B: 写前按 record ID 重读
|
||||
B-->>S: 无漂移
|
||||
S->>B: --as bot 最小 patch<br/>最后更新人=user.openId
|
||||
B-->>S: ok:true
|
||||
S->>B: record-get / 完整分页回读
|
||||
B-->>S: 字段与关系符合预期
|
||||
S-->>U: 完成回执
|
||||
```
|
||||
|
||||
统一规则:
|
||||
|
||||
1. 每条 Base read/write 都使用 `--as bot --format json`,失败后不降级为 user。
|
||||
2. `负责人`是 assignee;`最后更新人`是最近一次通过 CLI 推进记录的真实人类;bot 只是 API caller。
|
||||
3. 标题是展示文本,record ID 才是更新键。
|
||||
4. 写前展示目标记录和精确 patch;写后必须回读。
|
||||
5. `ok:true`不证明 record 存在或字段已生效;`ignored_fields`和 read-back mismatch 都算失败。
|
||||
6. schema、视图和只读操作没有行级归因目标,不写`最后更新人`。
|
||||
|
||||
## 10. Base 主状态机与 Trellis 映射
|
||||
|
||||
### 10.1 Base 主状态机
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 草拟中
|
||||
草拟中 --> 待确认
|
||||
待确认 --> ReadyAgent: 可由 Agent 执行
|
||||
待确认 --> ReadyHuman: 需要人类执行
|
||||
state "ready-for-agent" as ReadyAgent
|
||||
state "ready-for-human" as ReadyHuman
|
||||
|
||||
ReadyAgent --> 进行中: start-work 确认并回写
|
||||
ReadyHuman --> 进行中: 人类认领
|
||||
进行中 --> 阻塞: 发生 blocker
|
||||
阻塞 --> 进行中: blocker 解除
|
||||
进行中 --> 待评审: 进入 review
|
||||
待评审 --> 进行中: review 要求修改
|
||||
待评审 --> 已完成: 人类 review + 直接证据
|
||||
|
||||
草拟中 --> 已取代
|
||||
待确认 --> 已取代
|
||||
ReadyAgent --> 已取代
|
||||
进行中 --> 已取代
|
||||
ReadyAgent --> OutOfScope: 范围外
|
||||
state "out-of-scope" as OutOfScope
|
||||
|
||||
已完成 --> [*]
|
||||
已取代 --> [*]
|
||||
OutOfScope --> [*]
|
||||
```
|
||||
|
||||
### 10.2 Trellis 事件到 Base 的业务含义
|
||||
|
||||
| Trellis / 本地事件 | Base 动作 | 原因 |
|
||||
|---|---|---|
|
||||
| 只读列队、用户未选择 | 不写 | 浏览队列不是认领 |
|
||||
| mapping 保存成功,用户确认“选择并开始” | Spec 或 Ticket/父 Spec → `进行中`、`实现` | 表示进入规划/执行,不猜完成度 |
|
||||
| `planning` / `after_start` | 通常不重复写 | Start skill 已完成开始回写 |
|
||||
| 发生外部 blocker | `阻塞`,并填写`阻塞原因`和`下一步` | 状态与解释必须一致 |
|
||||
| Agent 建议可收口但无人类 review | 保持原状态 | Agent 只能推荐 |
|
||||
| 部分收口 | 仅用户选中的 Tickets → `已完成` | 父 Spec 保持`进行中` |
|
||||
| `task.py finish` / `after_finish` | 不写完成态 | 只代表 session detach |
|
||||
| `archive` / `after_archive` | 不自动写完成态 | 只满足 Spec 生命周期门禁之一 |
|
||||
| 全 Ticket 完成 + Spec 验收 + 人类最终 review + archive | Spec → `已完成`、`交付`、`完成度=1` | 最终聚合收口 |
|
||||
| Base 同步失败 | 保留真实现状并输出待对账 | 代码/Trellis 完成与外部同步分开报告 |
|
||||
|
||||
## 11. Base 完整字段字典(29 个)
|
||||
|
||||
以下字段来自“经销商政策”项目配置的真实 Base `field-list`回读。`文本`是当前表的主字段。
|
||||
|
||||
| # | 字段 | Field ID | 类型 / 当前取值 | 含义与规则 |
|
||||
|---:|---|---|---|---|
|
||||
| 1 | 文本 | `fldzLHLTca` | text,主字段 | 记录的业务标题。标题可用于创建前精确查重,但更新必须使用 record ID。 |
|
||||
| 2 | 产物类型 | `fldlwQ46Ks` | single select:需求/Issue、PRD/Spec、实现 Ticket、Wayfinder Map、决策 Ticket、原型、研究、Handoff、ADR、领域词汇、Bug 诊断、代码评审、架构候选、教学资产 | 说明该记录代表哪类工作流产物。 |
|
||||
| 3 | 来源技能 | `fldUMyVtoS` | multi-select:setup-matt-pocock-skills、setup-workflow-skills-feishu、grill-with-docs、grill-me、triage、diagnosing-bugs、wayfinder、to-spec、to-tickets、implement、tdd、code-review、improve-codebase-architecture、domain-modeling、prototype、research、handoff、teach | 记录创建或推进产物的逻辑流程。业务记录通常写逻辑 skill 名;当前表也保留 setup 的 Feishu 适配器选项。 |
|
||||
| 4 | 工作流阶段 | `fldjAkNPqD` | single select:探索/澄清、决策、规格、拆票/规划、实现、验证/评审、交付、维护/学习、分诊 | 表示产物处于端到端流程哪一阶段;与`状态`是不同维度。 |
|
||||
| 5 | 状态 | `fldHjFrlwJ` | single select:草拟中、待确认、待分诊、needs-triage、needs-info、ready-for-agent、ready-for-human、进行中、阻塞、待评审、已完成、wontfix、out-of-scope、已取代 | 统一业务状态机。英文值保留 Matt triage canonical role。 |
|
||||
| 6 | 类别 | `fldQWuceDX` | single select:bug、enhancement | Triage 分类;每个已分诊项必须恰好一个。 |
|
||||
| 7 | 决策票类型 | `fldFpkeDkj` | single select:research、prototype、grilling、task | Wayfinder 子决策票的解决方式;非决策票通常留空。 |
|
||||
| 8 | 协作模式 | `fldVwgWNRU` | single select:HITL、AFK | HITL 需要人类实时参与;AFK 表示 Agent 可以独立推进到下一个门禁。 |
|
||||
| 9 | 优先级 | `fldJv2ts2l` | single select:P0、P1、P2、P3 | 业务/执行优先级;不替代 blocker frontier。 |
|
||||
| 10 | 负责人 | `fldGlPa1B1` | user,单值 | 当前直接执行责任人。必须是真实飞书用户;Start/Close skills 不覆盖它。 |
|
||||
| 11 | 最后更新人 | `fld6nvDu18` | user,单值 | 最近一次通过 lark-cli 创建或更新记录的真实人类用户;不是 bot,也不是飞书系统更新时间。 |
|
||||
| 12 | 完成度 | `fldqNJjr0g` | number/progress,0–1 | 业务进度。Base 显示为百分比;最终完成写 JSON number `1`。 |
|
||||
| 13 | 产物文档 | `fldorpkrbf` | text/plain | canonical Wiki 或长文档链接。Spec/Triage 使用;V1 Ticket 留空并沿父 Spec 取文档。 |
|
||||
| 14 | 验收标准 | `fldwbSY2pq` | text | 可验证的完成条件。实现 Ticket 必填;Spec 保存聚合验收边界。 |
|
||||
| 15 | 验证证据 | `fldIQ0NQPO` | text | 真实命令、测试结果、浏览器验收、review、read-back 事实和未运行原因。没有具体证据不能完成。 |
|
||||
| 16 | 结论/摘要 | `fldmdDUJHh` | text | Problem/Solution 摘要、决策结论、诊断根因、研究摘要或交付结果;长分析放 Wiki。 |
|
||||
| 17 | 阻塞原因 | `fldUsFDsTS` | text | 仅`阻塞`或`needs-info`等无法继续的状态使用;说明为什么不能推进。 |
|
||||
| 18 | 下一步 | `fldMY6XATm` | text | 解除阻塞或进入下一阶段的最小动作;完成态清空。 |
|
||||
| 19 | 代码引用 | `fldNylIQ5y` | text | 分支、commit、PR、文件:行号、Trellis checkpoint、review fixed point 或`.out-of-scope/`路径。只写真实存在的引用。 |
|
||||
| 20 | 截止时间 | `fldZP6Cm30` | datetime,`yyyy-MM-dd HH:mm` | 人工承诺的截止时间,不由 Agent 自动推算。 |
|
||||
| 21 | 创建时间 | `fldnPF52hP` | created_at,只读 | Base 自动记录的创建时间;Triage 关注队列按它从旧到新排序。 |
|
||||
| 22 | 更新时间 | `fldd3rTk0I` | updated_at,只读 | Base 自动记录的行更新时间;用于竞态检测,不等于`最后更新人`。 |
|
||||
| 23 | 所属父项 | `flduS0iiPy` | self-link,双向 | Spec 指向来源 Issue;Ticket 指向父 Spec;决策 Ticket 指向 Wayfinder Map。写真实 record ID。 |
|
||||
| 24 | 前置依赖 | `fldYkwZVu1` | self-link,双向 | 指向阻塞当前项的记录。只有所有 blocker 都恰好为`已完成`时 Ticket 才进入 frontier。 |
|
||||
| 25 | 来源链接 | `fldp4F1S6m` | text/url | 原始 Issue、PR、表单或外部系统 URL。 |
|
||||
| 26 | 外部编号 | `fldpv8O5OW` | text | 外部系统编号。它不是 Base record ID,不能用作更新键或 link CellValue。 |
|
||||
| 27 | 报告人 | `fld37AxlZf` | text | 报告人的显示名或外部标识;兼容报告人不是飞书用户。 |
|
||||
| 28 | 最后反馈时间 | `fldTwNj5Uz` | datetime,`yyyy-MM-dd HH:mm` | 报告人或外部来源最近一次新增反馈时间。只更新时间,不自动改状态。 |
|
||||
| 29 | 最后分诊时间 | `fldNy9eAgM` | datetime,`yyyy-MM-dd HH:mm` | 维护者最近一次确认并写回分诊结果的时间。`最后反馈时间 > 最后分诊时间`时,needs-info 重新进入关注队列。 |
|
||||
|
||||
### 11.1 Link 字段边界
|
||||
|
||||
`所属父项`和`前置依赖`的正向字段是自动化 source of truth。`lark-cli 1.0.76`可能返回同表双向关系的 reverse field ID,但 reverse 字段不一定独立出现在`field-list`,因此当前实现不依赖反向字段寻址。
|
||||
|
||||
## 12. 真实 POC:经销商政策项目
|
||||
|
||||
### 12.1 POC 对象
|
||||
|
||||
| 产物 | Record ID / 路径 | 最终状态 |
|
||||
|---|---|---|
|
||||
| Spec:历史报告多条件检索 | `recvquNpDDOafu` | `已完成 / 交付 / 1` |
|
||||
| Ticket A:按事业部和分析类型筛选历史报告 | `recvquNtBMcQ2V` | `已完成 / 交付 / 1` |
|
||||
| Ticket B:按关键词搜索并完善筛选反馈 | `recvquNxjmWwth` | `已完成 / 交付 / 1` |
|
||||
| Trellis task | `.trellis/tasks/archive/2026-07/07-27-feishu-recvqunpddoafu` | archive 中,`task.json.status=completed` |
|
||||
| 工作 commit | `e7270cf` | `feat: 支持历史报告多条件检索` |
|
||||
| 规范 commit | `1f00f51` | `docs: 沉淀报告检索状态同步契约` |
|
||||
| 归档 commit | `30b9c8f` | `chore(task): archive 07-27-feishu-recvqunpddoafu` |
|
||||
| journal commit | `3e91199` | `chore: record journal` |
|
||||
|
||||
### 12.2 真实执行时序
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as 于选辉
|
||||
participant S as start-work-feishu
|
||||
participant B as Feishu Base
|
||||
participant T as Trellis
|
||||
participant C as Coding / Check
|
||||
participant X as close-work-feishu
|
||||
|
||||
U->>S: 选择历史报告多条件检索工作
|
||||
S->>B: 查询 Spec、Tickets、父项和 blocker
|
||||
S->>T: 创建并保存 1 Spec = 1 task mapping
|
||||
S->>B: 写 Spec/Ticket 进行中并回读
|
||||
S->>T: task.py start
|
||||
|
||||
T->>C: 实现 Ticket A
|
||||
C-->>U: 代码、测试和构建证据
|
||||
U->>X: 已完成 Ticket A 人类 review
|
||||
X->>B: 关闭 recvquNtBMcQ2V 并回读
|
||||
B-->>X: Ticket A 已完成,Ticket B blocker 解锁
|
||||
|
||||
T->>C: 实现 Ticket B
|
||||
C-->>U: API、前端、构建、真实浏览器与竞态证据
|
||||
U->>X: 已完成 Ticket B 人类 review
|
||||
X->>B: 关闭 recvquNxjmWwth 并回读
|
||||
B-->>X: 两张 Ticket 全部已完成
|
||||
|
||||
C->>T: update-spec + commits
|
||||
U->>T: 授权 finish-work
|
||||
T->>T: archive task + journal
|
||||
U->>X: 已完成 Spec 最终 review
|
||||
X->>B: 重新查询全部 Tickets 与 Spec
|
||||
X-->>U: 展示 Spec-only 精确 patch
|
||||
U->>X: 第二次确认最终 patch
|
||||
X->>B: 更新 Spec 已完成并 record-get
|
||||
B-->>X: 已完成 / 交付 / 1,负责人和验收保持不变
|
||||
```
|
||||
|
||||
### 12.3 实现与验证结果
|
||||
|
||||
本次 Spec 实现了:事业部、分析类型、标题/文件名关键词组合检索;条件使用 AND 语义;关键词去除首尾空白并对拉丁字符大小写不敏感;无筛选兼容旧行为;筛选后详情与列表保持一致;区分空仓库和筛选无结果;支持一键清空;旧请求不能覆盖新筛选结果。
|
||||
|
||||
真实验证证据:
|
||||
|
||||
- `pytest -q tests/test_api.py -k reports`:`9 passed, 11 deselected`。
|
||||
- 可执行后端回归:`37 passed, 1 deselected`。
|
||||
- 前端 `npm test`:`4 passed`。
|
||||
- 前端 `npm run build`:通过,仅保留既有 large-chunk advisory。
|
||||
- Trellis task validation:通过。
|
||||
- `git diff --check`:通过。
|
||||
- 真实浏览器验收:文件名关键词、大小写不敏感三条件组合、当前条件/结果数反馈、筛选无结果、详情清空与恢复、一键清空全部通过。
|
||||
- 受控请求竞态:较早的延迟响应未覆盖较新的筛选结果。
|
||||
- 浏览器 console 仅出现与本功能无关的 `favicon.ico` 404。
|
||||
- 完整 pytest 未运行成功的原因被明确保留:既有缺失模块/import collection errors,以及本次 diff 外的`policy_data` 404;没有把未运行项伪报为通过。
|
||||
|
||||
### 12.4 POC 证明了什么
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["当前用户负责人过滤"] --> Proof["真实 POC 通过"]
|
||||
B["Ticket blocker frontier"] --> Proof
|
||||
C["稳定 record ID 与 Trellis mapping"] --> Proof
|
||||
D["1 Spec = 1 task"] --> Proof
|
||||
E["Ticket 逐张人类 review"] --> Proof
|
||||
F["部分收口不关闭 Spec"] --> Proof
|
||||
G["archive 不是自动完成授权"] --> Proof
|
||||
H["Spec 第二次确认"] --> Proof
|
||||
I["写前重读 + 写后回读"] --> Proof
|
||||
J["最后更新人归因"] --> Proof
|
||||
K["未运行项显式记录"] --> Proof
|
||||
```
|
||||
|
||||
本次 demo POC 仅对“planning artifacts 必须经人类 review 后才能 `task.py start`”放宽了一次;Ticket review、Spec 最终 review、外部写入确认和回读门禁均未放宽。最终 Spec 的 Base 回读时间为 `2026-07-27 10:04:12`,`负责人`和`最后更新人`均为于选辉,验收标准和关联字段保持不变。未执行 push。
|
||||
|
||||
## 13. 失败处理与幂等对账
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["任一步失败"] --> B{"失败位置"}
|
||||
B -->|"身份 / schema / 查询"| C["不做任何本地或外部写入"]
|
||||
B -->|"选择后发生漂移"| D["旧确认失效,重新展示队列或 patch"]
|
||||
B -->|"task / artifact / mapping"| E["不写 Base,保留明确失败原因"]
|
||||
B -->|"Base 开始写失败"| F["task 保持 planning<br/>报告 mapping 已保存但未同步"]
|
||||
B -->|"Base 成功,Trellis start 失败"| G["Base 已认领<br/>Trellis 待启动,不自动回滚"]
|
||||
B -->|"Ticket batch 部分失败"| H["保留逐条成功/失败<br/>禁止关闭 Spec"]
|
||||
B -->|"write ok 但回读 mismatch"| I["标记 mismatched,不宣称完成"]
|
||||
B -->|"记录已完整同步"| J["already synchronized<br/>不重复追加证据"]
|
||||
H --> K["下次对账只补仍有差异的记录"]
|
||||
I --> K
|
||||
```
|
||||
|
||||
核心原则:外部系统的部分成功不能被一个总体`ok:true`遮蔽;也不能因为 Base 同步失败就篡改已经完成的代码/Trellis事实。回执必须把“代码完成”“Trellis lifecycle 完成”“Base 同步完成”分开报告。
|
||||
|
||||
## 14. 当前边界与后续演进
|
||||
|
||||
V1 当前边界:
|
||||
|
||||
- 两个 Coding 闭环 skills 已实现并通过真实 POC。
|
||||
- 直接编排项目内`.trellis/scripts/task.py`和`lark-cli`,没有新增 helper CLI。
|
||||
- 没有修改 Trellis workflow、hooks 或 Base schema。
|
||||
- 不自动 commit、push 或创建 PR;Git 写操作继续遵守用户授权边界。
|
||||
- 不把 coding sub-agent 设为 Base 状态决策者;外部选择、review、确认和回读都留在主会话。
|
||||
|
||||
建议的后续顺序:
|
||||
|
||||
1. 在第二个真实项目重放一次 Inline 路径,验证跨会话时按 record ID 重选的体验。
|
||||
2. 演练一次故意的 Base batch 部分失败,验证对账 routing 的逐条补偿。
|
||||
3. 演练一次 mapping 冲突和记录竞态,验证确认失效路径。
|
||||
4. 稳定后再考虑抽取共享分页/frontier/helper;在两个 skills 尚未形成稳定重复前不提前封装。
|
||||
5. 如果接入 lifecycle hook,`after_archive`只提醒或生成不含凭证的 pending 标记,不直接写 Base 完成态。
|
||||
|
||||
## 15. 一句话心智模型
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Issue["Issue<br/>要解决什么"] --> Spec["Spec<br/>为什么做、验收边界"]
|
||||
Spec --> Tickets["Tickets<br/>可独立交付的垂直切片与依赖"]
|
||||
Tickets --> Start["Start<br/>选择、路由、认领"]
|
||||
Start --> Coding["Coding<br/>Inline 或 1 Spec = 1 Trellis task"]
|
||||
Coding --> Evidence["Evidence<br/>代码、测试、浏览器、review"]
|
||||
Evidence --> Close["Close<br/>Ticket 部分收口 → Spec 最终收口"]
|
||||
Close --> Done["Done<br/>写后回读的 Base 闭环"]
|
||||
```
|
||||
|
||||
**Base 回答“现在是什么状态、由谁负责、依赖谁”;Wiki 回答“为什么做、具体要求是什么”;Trellis 回答“复杂工作如何规划、执行和归档”;repo 回答“到底实现了什么、验证过什么”;六个 Feishu skills 负责把这些事实源连接成一条可确认、可回读、可重放的工作流。**
|
||||
|
||||
## 16. 相关资料
|
||||
|
||||
- [Matt 工作流 × 飞书 CLI 全流程总结](<./Matt 工作流 × 飞书 CLI 全流程总结.md>)
|
||||
- [Trellis × 飞书实现闭环初步方案](<./Trellis × 飞书实现闭环初步方案.md>)
|
||||
- 经销商政策项目 tracker 合约:`/Users/yuxuanhui/Documents/ai-workflow/project/经销商政策/docs/agents/issue-tracker.md`
|
||||
- 真实 POC 归档任务:`/Users/yuxuanhui/Documents/ai-workflow/project/经销商政策/.trellis/tasks/archive/2026-07/07-27-feishu-recvqunpddoafu`
|
||||
- Trellis 官方文档:[架构](https://docs.trytrellis.app/zh/advanced/architecture)、[自定义 Workflow](https://docs.trytrellis.app/zh/advanced/custom-workflow)、[自定义 Skills](https://docs.trytrellis.app/zh/advanced/custom-skills)、[自定义 Agents](https://docs.trytrellis.app/zh/advanced/custom-agents)、[配置](https://docs.trytrellis.app/zh/advanced/configuration)
|
||||
@@ -1,331 +0,0 @@
|
||||
# MonoProxy 订阅信息获取工作流
|
||||
|
||||
本文记录如何从 macOS 版 MonoProxy 的本地配置中获取自有账户的节点信息,并生成不包含节点密码的 Clash YAML 列表。
|
||||
|
||||
## 适用范围
|
||||
|
||||
- 应用路径:`/Applications/MonoProxyMac.app`
|
||||
- 配置路径:`~/Library/Application Support/MonoProxy/config.json`
|
||||
- 已验证日期:2026-07-24
|
||||
- 输出字段:`name`、`server`、`port`、`type`、`cipher`、`udp`
|
||||
- 明确排除:节点 `password`、登录令牌、刷新令牌和账户信息
|
||||
|
||||
仅应处理自己拥有或获授权访问的账户与配置。不要上传或公开分享原始 `config.json`,其中还包含账户令牌和加密后的节点密码。
|
||||
|
||||
## 结论
|
||||
|
||||
MonoProxy 将节点数组保存在 `config.json` 的 `mn_service_<service-id>_servers` 字段中。该字段是 Base64 字符串,解码后的数据布局为:
|
||||
|
||||
```text
|
||||
salt(16 字节)
|
||||
+ IV(16 字节)
|
||||
+ HMAC-SHA256(32 字节)
|
||||
+ AES-256-CBC ciphertext(剩余字节)
|
||||
```
|
||||
|
||||
密钥派生参数:
|
||||
|
||||
```text
|
||||
算法:PBKDF2-HMAC-SHA256
|
||||
迭代次数:100000
|
||||
密钥长度:32 字节
|
||||
配置封装口令:MonoProxyMac.MNLocalManager.Services.v1
|
||||
```
|
||||
|
||||
这里的“配置封装口令”是应用二进制中用于保护本地配置结构的固定值,不是 Shadowsocks 节点的 `password`。
|
||||
|
||||
解密流程必须先验证 HMAC,再执行 AES 解密。HMAC 不匹配时应立即停止,不能忽略校验继续处理。
|
||||
|
||||
## 步骤一:让 MonoProxy 刷新本地配置
|
||||
|
||||
1. 启动 MonoProxy 并登录自己的账户。
|
||||
2. 等待节点列表完成刷新;是否开启系统代理不影响离线读取,但刷新过程需要网络。
|
||||
3. 检查配置文件是否刚刚更新:
|
||||
|
||||
```bash
|
||||
stat -f '%N | modified=%Sm | size=%z' \
|
||||
-t '%Y-%m-%d %H:%M:%S %z' \
|
||||
"$HOME/Library/Application Support/MonoProxy/config.json"
|
||||
```
|
||||
|
||||
如果文件不存在,先确认应用是否已登录并成功获取服务信息。
|
||||
|
||||
## 步骤二:确认节点字段
|
||||
|
||||
只查看字段名称,不输出令牌或节点密码:
|
||||
|
||||
```bash
|
||||
jq -r 'keys[] | select(test("^mn_service_.*_servers$"))' \
|
||||
"$HOME/Library/Application Support/MonoProxy/config.json"
|
||||
```
|
||||
|
||||
正常情况下会得到类似:
|
||||
|
||||
```text
|
||||
mn_service_2462_servers
|
||||
```
|
||||
|
||||
服务 ID 可能随账户或后端迁移而变化,因此提取脚本不应硬编码数字部分。
|
||||
|
||||
## 步骤三:使用离线脚本生成无密码 YAML
|
||||
|
||||
下面的脚本仅使用 Node.js 内置的 `fs` 和 `crypto` 模块,不需要安装第三方依赖,也不会联网。脚本会:
|
||||
|
||||
1. 自动查找 `mn_service_<id>_servers` 字段;
|
||||
2. Base64 解码数据;
|
||||
3. 使用 PBKDF2-SHA256 派生密钥;
|
||||
4. 验证 HMAC-SHA256;
|
||||
5. 使用 AES-256-CBC 解密节点 JSON;
|
||||
6. 输出不含 `password` 的 Clash YAML。
|
||||
|
||||
保存为 `extract-monoproxy.js`:
|
||||
|
||||
```javascript
|
||||
const fs = require("fs");
|
||||
const crypto = require("crypto");
|
||||
|
||||
const configPath =
|
||||
process.argv[2] ||
|
||||
`${process.env.HOME}/Library/Application Support/MonoProxy/config.json`;
|
||||
|
||||
const configEnvelopePassword =
|
||||
"MonoProxyMac.MNLocalManager.Services.v1";
|
||||
|
||||
/**
|
||||
* 使用 YAML 单引号格式转义字符串,避免节点名称中的特殊字符破坏 YAML。
|
||||
* @param {unknown} value 需要编码的值。
|
||||
* @returns {string} 可安全写入 YAML 的单引号字符串。
|
||||
*/
|
||||
function yamlString(value) {
|
||||
return `'${String(value).replaceAll("'", "''")}'`;
|
||||
}
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
||||
const serverKey = Object.keys(config).find((key) =>
|
||||
/^mn_service_.*_servers$/.test(key),
|
||||
);
|
||||
|
||||
if (!serverKey) {
|
||||
throw new Error("未找到 mn_service_<id>_servers 字段");
|
||||
}
|
||||
|
||||
const envelope = Buffer.from(config[serverKey], "base64");
|
||||
if (envelope.length <= 64) {
|
||||
throw new Error("节点密文长度异常");
|
||||
}
|
||||
|
||||
const salt = envelope.subarray(0, 16);
|
||||
const iv = envelope.subarray(16, 32);
|
||||
const storedHmac = envelope.subarray(32, 64);
|
||||
const ciphertext = envelope.subarray(64);
|
||||
|
||||
const key = crypto.pbkdf2Sync(
|
||||
configEnvelopePassword,
|
||||
salt,
|
||||
100000,
|
||||
32,
|
||||
"sha256",
|
||||
);
|
||||
|
||||
const calculatedHmac = crypto
|
||||
.createHmac("sha256", key)
|
||||
.update(Buffer.concat([salt, iv, ciphertext]))
|
||||
.digest();
|
||||
|
||||
if (
|
||||
storedHmac.length !== calculatedHmac.length ||
|
||||
!crypto.timingSafeEqual(storedHmac, calculatedHmac)
|
||||
) {
|
||||
throw new Error(
|
||||
"HMAC 校验失败:配置可能损坏,或 MonoProxy 已更改加密格式",
|
||||
);
|
||||
}
|
||||
|
||||
const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
|
||||
const plaintext = Buffer.concat([
|
||||
decipher.update(ciphertext),
|
||||
decipher.final(),
|
||||
]).toString("utf8");
|
||||
|
||||
const nodes = JSON.parse(plaintext);
|
||||
if (!Array.isArray(nodes)) {
|
||||
throw new Error("解密结果不是节点数组");
|
||||
}
|
||||
|
||||
console.log("proxies:");
|
||||
for (const node of nodes) {
|
||||
if (!node.alias || !node.hostname || !node.port || !node.encryption) {
|
||||
throw new Error("节点缺少 alias/hostname/port/encryption 字段");
|
||||
}
|
||||
|
||||
console.log(` - name: ${yamlString(node.alias)}`);
|
||||
console.log(` server: ${yamlString(node.hostname)}`);
|
||||
console.log(` port: ${Number(node.port)}`);
|
||||
console.log(" type: ss");
|
||||
console.log(` cipher: ${yamlString(node.encryption)}`);
|
||||
console.log(" udp: true");
|
||||
}
|
||||
```
|
||||
|
||||
执行:
|
||||
|
||||
```bash
|
||||
node extract-monoproxy.js \
|
||||
"$HOME/Library/Application Support/MonoProxy/config.json" \
|
||||
> monoproxy-subscription-without-password.yaml
|
||||
```
|
||||
|
||||
检查输出中没有密码字段:
|
||||
|
||||
```bash
|
||||
rg -n 'password|access_token|refresh_token' \
|
||||
monoproxy-subscription-without-password.yaml
|
||||
```
|
||||
|
||||
正常结果应无任何输出。再检查 YAML 的节点数量:
|
||||
|
||||
```bash
|
||||
rg -c '^ - name:' monoproxy-subscription-without-password.yaml
|
||||
```
|
||||
|
||||
当前快照应输出 `15`。
|
||||
|
||||
## 字段映射
|
||||
|
||||
| MonoProxy 节点字段 | Clash YAML 字段 | 说明 |
|
||||
|---|---|---|
|
||||
| `alias` | `name` | 节点显示名称 |
|
||||
| `hostname` | `server` | 节点域名或地址 |
|
||||
| `port` | `port` | 节点端口 |
|
||||
| 服务类型 Shadowsocks | `type: ss` | `type` 不在每个节点对象中单独存储 |
|
||||
| `encryption` | `cipher` | 当前均为 `chacha20-ietf-poly1305` |
|
||||
| 未单独存储 | `udp: true` | 按现有 Clash Shadowsocks 配置补充 |
|
||||
| `password` | 不输出 | 本工作流明确排除 |
|
||||
|
||||
## 当前完整 YAML 快照(不含 password)
|
||||
|
||||
数据来自 2026-07-24 15:03:55 更新的本地 `config.json`。HMAC 校验、AES 解密及 JSON 解析均已通过。
|
||||
|
||||
```yaml
|
||||
proxies:
|
||||
- name: 'Relay-HK1'
|
||||
server: 'scott.mydarkcloud.info'
|
||||
port: 1904
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-HK2'
|
||||
server: 'andrew.mydarkcloud.info'
|
||||
port: 2004
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-HK3'
|
||||
server: 'ethan.mydarkcloud.info'
|
||||
port: 3204
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-HK4'
|
||||
server: 'lucas.mydarkcloud.info'
|
||||
port: 999
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-SG1'
|
||||
server: 'tyler.mydarkcloud.info'
|
||||
port: 2604
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-SG2'
|
||||
server: 'tyler.mydarkcloud.info'
|
||||
port: 2704
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-JP1'
|
||||
server: 'patrick.mydarkcloud.info'
|
||||
port: 1504
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-JP2'
|
||||
server: 'ava.mydarkcloud.info'
|
||||
port: 995
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-TW1'
|
||||
server: 'kevin.mydarkcloud.info'
|
||||
port: 2104
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-TW2'
|
||||
server: 'kevin.mydarkcloud.info'
|
||||
port: 2204
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-US1'
|
||||
server: 'nathan.mydarkcloud.info'
|
||||
port: 1204
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'Relay-US2'
|
||||
server: 'nathan.mydarkcloud.info'
|
||||
port: 1304
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'JP3'
|
||||
server: 'noah.mydarkcloud.info'
|
||||
port: 999
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'TW1'
|
||||
server: 'tw1.mydarkcloud.info'
|
||||
port: 999
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
- name: 'TR1'
|
||||
server: 'tr1.mydarkcloud.info'
|
||||
port: 999
|
||||
type: ss
|
||||
cipher: 'chacha20-ietf-poly1305'
|
||||
udp: true
|
||||
```
|
||||
|
||||
## 验证与故障处理
|
||||
|
||||
### HMAC 校验失败
|
||||
|
||||
不要跳过校验。常见原因:
|
||||
|
||||
- `config.json` 正在被应用写入,读取到了不完整内容;
|
||||
- MonoProxy 更新后更改了封装口令、迭代次数或加密格式;
|
||||
- 读取了其他应用或旧版本生成的配置文件。
|
||||
|
||||
先等待应用完成刷新并重新执行。如果仍失败,需要重新检查当前二进制中的:
|
||||
|
||||
- `MNLocalManager -_encryptedJSONObjectForKey:`
|
||||
- `Ctor +d:p:e:`
|
||||
- `CCKeyDerivationPBKDF` 参数
|
||||
- `AES256CBCDecryptData:key:iv:error:`
|
||||
- `HMACSHA256WithData:key:`
|
||||
|
||||
### 输出节点为空或字段缺失
|
||||
|
||||
- 确认账户仍有有效服务;
|
||||
- 确认找到的是当前 `mn_service_<id>_servers` 字段;
|
||||
- 不要把旧版 `~/Library/Preferences/com.MonoCloud.MonoProxyMac.plist` 当作最新数据源;
|
||||
- 优先以刚刷新过的 `~/Library/Application Support/MonoProxy/config.json` 为准。
|
||||
|
||||
### YAML 无法直接连接
|
||||
|
||||
本文输出刻意删除了 `password`,因此它是用于审阅、比对和更新 `server/port` 的安全快照,并不是可直接连接的完整凭据文件。需要实际连接时,应在本地私密环境中补回自己已有的密码,且不要提交到 Git 或同步到公开笔记库。
|
||||
|
||||
@@ -1,763 +0,0 @@
|
||||
# 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 提醒集成。
|
||||
@@ -1,689 +0,0 @@
|
||||
# 基于飞书的产物管理工作流
|
||||
|
||||
这套流程把需求澄清、规格、拆票、代码实现和收口串到飞书 Base/Wiki 与 Trellis 上。
|
||||
|
||||
本文以当前安装的 skill 名称为准:
|
||||
|
||||
- `setup-feishu` 指 `$setup-workflow-skills-feishu`;
|
||||
- `start-feishu-work` 指 `$start-work-feishu`;
|
||||
- `close-feishu-work` 指 `$close-work-feishu`;
|
||||
- `to-sepc-feishu` 的正确名称是 `$to-spec-feishu`。
|
||||
|
||||
当前版本有三个明确边界:
|
||||
|
||||
1. Issue 不进入这套 Base;需求在进入 Base 前,通过对话、研究、原型或其他人工确认完成澄清。
|
||||
2. 整个流程不再使用 `triage-feishu`,也不创建 Triage dossier、Agent Brief 或 Human Brief。
|
||||
3. Base 只保留一个状态轴和 6 个状态,不再维护 `工作流阶段`。
|
||||
|
||||
## 事实源怎么分工
|
||||
|
||||
| 载体 | 负责保存 | 不负责保存 |
|
||||
|---|---|---|
|
||||
| 飞书 Base | Spec/Ticket 身份、项目、状态、负责人、父子关系、依赖、验收和验证摘要 | 大段需求正文、完整设计文档 |
|
||||
| 飞书 Wiki / Docx | Engineering Spec、Map、研究、决策、长篇说明 | 可计算的工作队列和关系状态 |
|
||||
| 代码仓库 | 代码、测试、ADR、领域文档和实现证据 | Base 当前状态 |
|
||||
| Trellis | 多会话执行上下文、计划、源快照、归档证据 | 第二份 Spec 或 Ticket 主数据 |
|
||||
|
||||
几个始终有效的规则:
|
||||
|
||||
- Base 管状态和关系,Wiki 管长文,代码仓库管实现和验证。
|
||||
- Trellis 只保存执行上下文,不能静默改写 Wiki Spec 或 Base Ticket。
|
||||
- Feishu CLI 的 Base、Wiki、Docs 操作统一使用 `--as bot --format json`。
|
||||
- API 由 bot 执行,但 `最后更新人` 必须写当前已验证用户。
|
||||
- 每次写入都要回查,不能只看 `ok: true`。
|
||||
|
||||
# 一、初始化
|
||||
|
||||
## 1.1 初始化飞书 CLI
|
||||
|
||||
### 安装
|
||||
|
||||
官方推荐安装方式:
|
||||
|
||||
```bash
|
||||
npx @larksuite/cli@latest install
|
||||
```
|
||||
|
||||
安装后先确认实际版本:
|
||||
|
||||
```bash
|
||||
command -v lark-cli
|
||||
lark-cli --version
|
||||
```
|
||||
|
||||
本文验证时使用的是 `lark-cli 1.0.76`。换机器或升级版本后,先查看当前版本和子命令 `--help`,不要直接照搬旧参数。
|
||||
|
||||
### 初始化应用身份
|
||||
|
||||
```bash
|
||||
lark-cli config init --new
|
||||
```
|
||||
|
||||
需要进入交互流程时可以使用:
|
||||
|
||||
```bash
|
||||
lark-cli config init
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- `app_secret` 不能写入文档、Trellis 产物或命令历史;
|
||||
- 非交互环境优先使用 `--app-secret-stdin`;
|
||||
- 如果当前环境已经绑定应用,先确认是否应使用 `lark-cli config bind`,不要未经确认创建平行应用。
|
||||
|
||||
### 登录用户身份
|
||||
|
||||
推荐登录:
|
||||
|
||||
```bash
|
||||
lark-cli auth login --recommend
|
||||
```
|
||||
|
||||
按业务域登录:
|
||||
|
||||
```bash
|
||||
lark-cli auth login --domain base,docs,wiki
|
||||
```
|
||||
|
||||
不能阻塞等待授权时,使用设备码:
|
||||
|
||||
```bash
|
||||
lark-cli auth login --domain base,docs,wiki --no-wait --json
|
||||
lark-cli auth login --device-code <DEVICE_CODE>
|
||||
```
|
||||
|
||||
### 验证双身份
|
||||
|
||||
```bash
|
||||
lark-cli auth status --json --verify
|
||||
```
|
||||
|
||||
必须同时满足:
|
||||
|
||||
- `identities.bot.verified=true`;
|
||||
- `identities.user.verified=true`;
|
||||
- `identities.user.openId` 非空。
|
||||
|
||||
飞书操作由 bot 执行。用户 open ID 只用于查询当前用户的工作和填写 `最后更新人`,不能固化成全局配置。
|
||||
|
||||
最小检查:
|
||||
|
||||
```bash
|
||||
lark-cli --version
|
||||
lark-cli auth status --json --verify
|
||||
lark-cli base --help
|
||||
lark-cli wiki --help
|
||||
lark-cli docs --help
|
||||
```
|
||||
|
||||
官方入口:[Lark CLI README](https://github.com/larksuite/cli/blob/main/README.md)。
|
||||
|
||||
## 1.2 项目初始化:`setup-workflow-skills-feishu`
|
||||
|
||||
CLI 初始化解决“能不能访问飞书”,Setup 解决“这个仓库应该访问哪张 Base、哪个 Wiki 项目目录”。
|
||||
|
||||
```text
|
||||
$setup-workflow-skills-feishu
|
||||
```
|
||||
|
||||
### 提前准备的飞书内容
|
||||
|
||||
需要明确提供:
|
||||
|
||||
1. Base 表格或视图 URL;
|
||||
2. Wiki 工作区根节点 URL;
|
||||
3. 项目目录名称,或已有项目节点 URL。
|
||||
|
||||
还应提前确认:
|
||||
|
||||
- 一张用于管理 Spec、Ticket 和进度的 Base 表;
|
||||
- 一个明确的 Base 视图;
|
||||
- bot 可访问的 Wiki 知识空间;
|
||||
- 一个已确认的项目名,项目名不必等于仓库名;
|
||||
- bot 对 Base、Wiki、Docs 的应用权限和资源 ACL;
|
||||
- 用户 OAuth 已完成,bot 和 user 都能通过验证。
|
||||
|
||||
推荐的 Wiki 层级:
|
||||
|
||||
```text
|
||||
<WORKSPACE_ROOT>
|
||||
├── 知识文档
|
||||
└── 项目目录
|
||||
└── <PROJECT_NAME>
|
||||
```
|
||||
|
||||
当前只使用以下路由,均指向项目节点:
|
||||
|
||||
| 路由 | 用途 |
|
||||
|---|---|
|
||||
| `setup` | 项目配置说明 |
|
||||
| `spec` | Engineering Spec |
|
||||
| `wayfinder` | Map 与决策文档 |
|
||||
|
||||
不再创建 `triage` 路由,也不把 `知识文档` 当作 skill 写入失败后的兜底位置。
|
||||
|
||||
### Setup 的两个独立选择
|
||||
|
||||
| 维度 | 推荐模式 | 可写模式 | 作用 |
|
||||
|---|---|---|---|
|
||||
| Tracker | Reuse tracker | Bootstrap tracker | 只读校验或补齐 Base 标准字段 |
|
||||
| Project Binding | Reuse existing binding | Provision missing binding | 校验或创建 Wiki 项目目录,并补充项目选项 |
|
||||
|
||||
- **Reuse tracker**:只读检查 Base 坐标、字段和选项;不创建字段、不创建配置文档。
|
||||
- **Bootstrap tracker**:经过确认后,只新增缺失字段并创建一份项目配置说明。
|
||||
- **Reuse existing binding**:只读检查 Wiki 目录和 `所属项目` 选项。
|
||||
- **Provision missing binding**:经过独立确认后,只创建缺失节点或追加缺失项目选项。
|
||||
|
||||
两个授权范围互不包含。字段修复不等于允许创建 Wiki 节点,项目目录授权也不等于允许改表结构。
|
||||
|
||||
### Setup 的产出
|
||||
|
||||
Setup 会留下:
|
||||
|
||||
- `CLAUDE.md` 或 `AGENTS.md` 中的 `## Agent skills` 区块;
|
||||
- `docs/agents/issue-tracker.md`;
|
||||
- `docs/agents/domain.md`;
|
||||
- Bootstrap 模式下的缺失字段和项目配置说明文档;
|
||||
- Provision 模式下的项目 Wiki 节点或项目选项。
|
||||
|
||||
不再生成 `docs/agents/triage-labels.md`。后续 Feishu skill 读取的是 `docs/agents/issue-tracker.md`,其中应记录契约版本、Base/Wiki 坐标、真实主字段、项目绑定、24 个字段、路由和可执行命令。
|
||||
|
||||
## 1.3 当前 Base 字段:24 个
|
||||
|
||||
旧契约有 30 个字段。根据当前流程,删除了 6 个:
|
||||
|
||||
- `工作流阶段`;
|
||||
- `类别`;
|
||||
- `外部编号`;
|
||||
- `报告人`;
|
||||
- `最后反馈时间`;
|
||||
- `最后分诊时间`。
|
||||
|
||||
原因是 Issue 不进入 Base,triage 已移除,而且状态本身已经足够表达下一步动作。当前契约共 24 个字段:
|
||||
|
||||
| # | 字段 | 类型 / 典型值 | 含义与功能 |
|
||||
|---:|---|---|---|
|
||||
| 1 | 实际主字段 | 主字段文本 | 记录标题。创建前用于查重,更新必须使用 record ID。 |
|
||||
| 2 | 产物文档 | 文本 / URL | Wiki Spec、Map 或其他长文产物的规范链接。 |
|
||||
| 3 | 产物类型 | 单选 | `PRD/Spec`、`实现 Ticket`、`Wayfinder Map`、`决策 Ticket`、`原型`、`研究`、`Handoff`、`ADR`、`领域词汇`、`Bug 诊断`、`代码评审`、`架构候选`、`教学资产`。不再有 `需求/Issue`。 |
|
||||
| 4 | 所属项目 | 单选,`multiple=false` | 项目边界。父项和依赖必须属于同一项目。 |
|
||||
| 5 | 来源技能 | 多选 | 记录由哪个 skill 创建或维护,如 `to-spec`、`to-tickets`、`start-work`、`close-work`、`wayfinder`。不再包含 `triage`。 |
|
||||
| 6 | 来源链接 | 文本 / URL | 当前对话、PR、表单、研究或外部系统的来源链接。 |
|
||||
| 7 | 状态 | 单选 | 只允许 6 个状态:`ready-for-agent`、`进行中`、`阻塞`、`待评审`、`已完成`、`wontfix`。 |
|
||||
| 8 | 决策票类型 | 单选 | `research`、`prototype`、`grilling`、`task`。 |
|
||||
| 9 | 协作模式 | 单选 | `HITL` 或 `AFK`。表示执行过程中人工参与的强度,不替代状态。 |
|
||||
| 10 | 优先级 | 单选 | `P0`—`P3`,用于排序和资源安排。 |
|
||||
| 11 | 负责人 | 单用户 | 当前执行人。Start 不擅自覆盖。 |
|
||||
| 12 | 最后更新人 | 单用户 | 最近一次通过 CLI 改动记录的真实操作者。 |
|
||||
| 13 | 完成度 | 数字 / 百分比 | 进度量化,收口时写为 `1`。 |
|
||||
| 14 | 验收标准 | 长文本 | 可观察、可验证的完成条件。 |
|
||||
| 15 | 验证证据 | 长文本 | 实际命令、测试结果、回查事实和未运行项。 |
|
||||
| 16 | 结论/摘要 | 长文本 | Base 中的简洁摘要;`wontfix` 的具体原因也写在这里。 |
|
||||
| 17 | 阻塞原因 | 长文本 | `状态=阻塞` 时解释为什么不能继续。 |
|
||||
| 18 | 下一步 | 长文本 | 解除阻塞或继续推进的明确动作。 |
|
||||
| 19 | 代码引用 | 长文本 | 文件路径、分支、commit、PR、评审链接或 Trellis 证据。 |
|
||||
| 20 | 截止时间 | 日期时间 | 业务期望完成时间。 |
|
||||
| 21 | 创建时间 | 系统字段,只读 | 排序和审计。 |
|
||||
| 22 | 更新时间 | 系统字段,只读 | 并发变更检测和源快照比较。 |
|
||||
| 23 | 所属父项 | 同表关联 | Ticket → Spec,决策 Ticket → Map。 |
|
||||
| 24 | 前置依赖 | 同表关联 | blocker 的真实 record ID,用于计算可执行 frontier。 |
|
||||
|
||||
### 6 个状态的含义
|
||||
|
||||
```text
|
||||
ready-for-agent → 进行中 → 待评审 → 已完成
|
||||
↘ 阻塞 ↗
|
||||
|
||||
任一未完成状态 ─────────────→ wontfix
|
||||
```
|
||||
|
||||
| 状态 | 含义 | 是否进入 Start 队列 |
|
||||
|---|---|---:|
|
||||
| `ready-for-agent` | 已澄清、可以交给 Agent 开始 | 是,前置依赖满足时可选 |
|
||||
| `进行中` | 已认领,正在实现或恢复工作 | 是 |
|
||||
| `阻塞` | 被依赖、决策或外部条件卡住 | 是,作为可恢复项展示 |
|
||||
| `待评审` | 实现完成,等待人工评审和 Close | 否,转给 Close |
|
||||
| `已完成` | 验收和人工确认完成 | 否 |
|
||||
| `wontfix` | 不再交付;原因写入 `结论/摘要` | 否 |
|
||||
|
||||
`wontfix` 是唯一非交付终态。它不能满足其他 Ticket 的前置依赖;只有 `已完成` 才表示依赖交付。
|
||||
|
||||
---
|
||||
|
||||
# 二、需求澄清阶段
|
||||
|
||||
当前流程不再把需求先写成 Issue 再分诊。需求澄清发生在对话、研究、原型、grilling 或人工决策中;只有形成明确方案后,才写入 Spec/Ticket Base。
|
||||
|
||||
## 2.1 `to-spec-feishu`
|
||||
|
||||
```text
|
||||
$to-spec-feishu
|
||||
```
|
||||
|
||||
`to-spec-feishu` 使用已经形成的上下文,不重新访谈用户:
|
||||
|
||||
1. 读取当前对话、领域术语、代码库和 ADR;
|
||||
2. 找到尽可能高层、数量尽可能少的测试 seam;
|
||||
3. 让用户确认 seam 和 Spec 方向;
|
||||
4. 生成 Problem Statement、Solution、User Stories、Implementation Decisions、Testing Decisions、Out of Scope 和 Further Notes;
|
||||
5. 将完整 Spec 发布到 Wiki;
|
||||
6. 创建关联的 `PRD/Spec` Base 记录。
|
||||
|
||||
发布顺序是先 Wiki、后 Base。Wiki fetch 回查正文完整后,才创建 Base 记录。
|
||||
|
||||
Base Spec 的初始值:
|
||||
|
||||
```text
|
||||
产物类型 = PRD/Spec
|
||||
状态 = ready-for-agent
|
||||
协作模式 = AFK
|
||||
产物文档 = Wiki Spec 链接
|
||||
```
|
||||
|
||||
如果决定不再交付已经创建的 Spec,可以把它设为 `wontfix`,并在 `结论/摘要` 写明原因;这不是 triage,而是产物生命周期中的人工决策。
|
||||
|
||||
## 2.2 `to-tickets-feishu`
|
||||
|
||||
```text
|
||||
$to-tickets-feishu
|
||||
```
|
||||
|
||||
`to-tickets-feishu` 把已批准的 Spec 拆成 tracer-bullet 垂直切片:
|
||||
|
||||
- 每张 Ticket 穿过完成行为所需的各层;
|
||||
- 单独完成后可演示或验证;
|
||||
- 能在一个新上下文窗口内完成;
|
||||
- 只声明真实的阻塞关系;
|
||||
- 宽范围机械重构使用 `expand → migrate batches → contract`。
|
||||
|
||||
发布前必须让用户确认粒度、拆分和依赖。发布分两步:
|
||||
|
||||
1. 按依赖顺序创建全部 Ticket,保存真实 record ID;
|
||||
2. 用 record ID 回写 `所属父项` 和 `前置依赖`,逐条回查。
|
||||
|
||||
每条 Ticket 的初始值:
|
||||
|
||||
```text
|
||||
产物类型 = 实现 Ticket
|
||||
状态 = ready-for-agent
|
||||
协作模式 = AFK
|
||||
所属父项 = 父 Spec record ID
|
||||
前置依赖 = blocker record IDs
|
||||
产物文档 = 留空
|
||||
```
|
||||
|
||||
V1 不给每张 Ticket 单独建 Wiki 文档;Ticket 的切片事实保存在 Base,长文仍归属于父 Spec。
|
||||
|
||||
## 2.3 需求澄清的全部操作可能
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["当前对话、研究、原型或其他需求来源"] --> B{"是否已经有明确的目标、约束和验收?"}
|
||||
B -- "否" --> C["HITL:继续澄清、grilling 或补充研究"]
|
||||
C --> B
|
||||
B -- "是" --> D{"是否决定继续交付?"}
|
||||
D -- "否" --> E["不创建 Issue;若已有 Spec/Ticket,则设为 wontfix 并记录原因"]
|
||||
D -- "是" --> F["to-spec-feishu:发布 Wiki Engineering Spec"]
|
||||
F --> G["Base Spec:PRD/Spec + ready-for-agent"]
|
||||
G --> H{"是否需要多个独立垂直切片?"}
|
||||
H -- "否" --> I["直接进入 start-work-feishu"]
|
||||
H -- "是" --> J["to-tickets-feishu:起草 Ticket 和依赖图"]
|
||||
J --> K{"用户是否批准粒度和依赖?"}
|
||||
K -- "否" --> J
|
||||
K -- "是" --> L["创建 Ticket、回写父子关系和前置依赖"]
|
||||
L --> M["Spec + Tickets 进入开发队列"]
|
||||
```
|
||||
|
||||
本阶段的正式产出只有:
|
||||
|
||||
- Wiki Engineering Spec;
|
||||
- 一个 `PRD/Spec` Base 记录;
|
||||
- 可选的多个 `实现 Ticket` Base 记录;
|
||||
- 父子关系、依赖关系和可执行 frontier。
|
||||
|
||||
不再产出:
|
||||
|
||||
- `需求/Issue` Base 记录;
|
||||
- Triage dossier;
|
||||
- `needs-triage`、`needs-info`、`ready-for-human` 等状态;
|
||||
- `类别`、`最后分诊时间` 等 triage 字段。
|
||||
|
||||
---
|
||||
|
||||
# 三、代码开发阶段
|
||||
|
||||
代码开发阶段由 `$start-work-feishu` 开始,由 `$close-work-feishu` 收口。Start 负责“选中并认领”,Close 负责“证据核验并关闭”。
|
||||
|
||||
## 3.1 `start-work-feishu`
|
||||
|
||||
```text
|
||||
$start-work-feishu
|
||||
```
|
||||
|
||||
### 功能
|
||||
|
||||
Start 会:
|
||||
|
||||
- 验证项目契约、双身份、Base 坐标和 24 个字段;
|
||||
- 查询当前用户负责的 Spec 和 Ticket;
|
||||
- 解析父项、依赖、负责人和更新时间;
|
||||
- 把记录分为可开始、可恢复、被阻塞和待评审;
|
||||
- 让用户选择具体 record ID;
|
||||
- 推荐 Inline 或 Trellis;
|
||||
- 经确认后把目标记录改为 `状态=进行中`,并回写 `最后更新人`。
|
||||
|
||||
它不会自动改负责人、完成度、兄弟 Ticket,也不会因为看到了 `ready-for-human` 而转派工作,因为当前状态机已经删除这个状态。
|
||||
|
||||
### 工作队列
|
||||
|
||||
| 条件 | 分类 | 是否可选 |
|
||||
|---|---|---:|
|
||||
| `进行中` | 可恢复 | 是 |
|
||||
| `阻塞` | 可恢复,但展示阻塞原因 | 是 |
|
||||
| `ready-for-agent`,无依赖或依赖全为 `已完成` | 可开始 | 是 |
|
||||
| `ready-for-agent`,存在未完成依赖 | 被阻塞 | 否 |
|
||||
| `待评审` | 待收口 | 否,转 Close |
|
||||
| `wontfix`、`已完成` 或其他不匹配记录 | 不进入开发队列 | 否 |
|
||||
|
||||
只有 `已完成` 能满足依赖。`wontfix` 不是依赖完成证明。
|
||||
|
||||
选择 Spec 时只更新 Spec。选择 Ticket 时,同时更新 Ticket 和唯一父 Spec:
|
||||
|
||||
```text
|
||||
状态 = 进行中
|
||||
最后更新人 = 当前已验证用户
|
||||
```
|
||||
|
||||
负责人、所属项目、完成度和未选中的兄弟 Ticket 保持不变。
|
||||
|
||||
### Inline 与 Trellis
|
||||
|
||||
适合 Inline:
|
||||
|
||||
- 范围窄,路径已知;
|
||||
- 一个上下文可以完成;
|
||||
- 验证命令能在当前会话运行。
|
||||
|
||||
适合 Trellis:
|
||||
|
||||
- 跨模块或多会话;
|
||||
- 有多个稳定决策和交付物;
|
||||
- 需要保存长验收链;
|
||||
- 仓库已经有 `.trellis/`。
|
||||
|
||||
仓库没有 `.trellis/` 时,Start 不会自行初始化;需要用户单独授权后再初始化,或选择 Inline。
|
||||
|
||||
## 3.2 Start 如何承接 Trellis
|
||||
|
||||
### 一对一绑定
|
||||
|
||||
```text
|
||||
1 个飞书 Spec = 1 个 Trellis task
|
||||
```
|
||||
|
||||
Ticket 是该 task 内的计划和验收单元,不为每张 Ticket 创建独立 Trellis 子任务。直接选择 Ticket 时,也绑定到父 Spec 的同一个 task。
|
||||
|
||||
映射保存在:
|
||||
|
||||
```text
|
||||
task.json.meta.feishuTracker
|
||||
```
|
||||
|
||||
至少保存 `specRecordId`、`ticketRecordIds`、`selectedRecordIds`、`specWikiUrl`、`trackerContractPath`、`boundAt` 和 `lastRefreshAt`。映射里不保存凭证、Base token 或固定用户 ID。
|
||||
|
||||
### 创建和启动顺序
|
||||
|
||||
```bash
|
||||
python3 ./.trellis/scripts/task.py create "<SPEC_TITLE>" \
|
||||
--slug "feishu-<NORMALIZED_SPEC_RECORD_ID>" \
|
||||
--description "Implement Feishu Spec <SPEC_RECORD_ID>" \
|
||||
--no-start
|
||||
```
|
||||
|
||||
正确顺序:
|
||||
|
||||
1. 在 `prd.md` 维护飞书 Spec 来源区块;
|
||||
2. 在 `implement.md` 维护 Ticket 快照;
|
||||
3. 写入并回查 `task.json.meta.feishuTracker`;
|
||||
4. 比较 Trellis 快照与飞书批准源;
|
||||
5. 用户确认选择、路由、稳定 ID 和 Base patch;
|
||||
6. 更新 Base 并回查;
|
||||
7. Base 认领成功后启动 Trellis:
|
||||
|
||||
```bash
|
||||
python3 ./.trellis/scripts/task.py start <TASK_DIR>
|
||||
```
|
||||
|
||||
这样可以把失败范围控制在一个边界内:本地映射失败不碰 Base,Base 回查失败不启动 Trellis。
|
||||
|
||||
### 快照判定
|
||||
|
||||
| 判定 | 含义 | 动作 |
|
||||
|---|---|---|
|
||||
| `snapshot-only` | 只是已批准 Spec/Ticket 的忠实镜像 | 做机械一致性检查 |
|
||||
| `delta-reviewed` | 新增实现顺序、兼容、迁移、安全或回滚决策 | 只评审新增技术差量 |
|
||||
| `source-revision-required` | 改变产品行为、范围、验收或依赖语义 | 回到 Wiki/Base 修订正式源 |
|
||||
|
||||
Trellis 能补充执行计划,不能静默变更正式业务产物。
|
||||
|
||||
### Trellis 生命周期
|
||||
|
||||
| 命令 | 语义 |
|
||||
|---|---|
|
||||
| `task.py create --no-start` | 创建 `planning` 任务,不设为活动任务 |
|
||||
| `task.py start <TASK_DIR>` | 将任务设为活动并改为 `in_progress` |
|
||||
| `task.py finish` | 只清除当前会话活动指针,不代表完成 |
|
||||
| `task.py archive <TASK_DIR> --no-commit` | 写入 `completed` 并移动到月度归档目录 |
|
||||
|
||||
Trellis 路线最终关闭 Spec 时,要求归档树下存在 `task.json` 且 `status=completed`。按本机约定,归档使用 `--no-commit`。
|
||||
|
||||
## 3.3 `close-work-feishu`
|
||||
|
||||
```text
|
||||
$close-work-feishu
|
||||
```
|
||||
|
||||
### 功能
|
||||
|
||||
Close 会:
|
||||
|
||||
- 从 Trellis 映射、归档 task 或 Inline 冻结 ID 解析 Spec;
|
||||
- 每次重新查询全部子 Ticket;
|
||||
- 从代码、测试、命令结果、Trellis 产物和 Base 记录收集直接证据;
|
||||
- 将 Ticket 分为建议可收口、待补证/待验证、明确未完成/阻塞;
|
||||
- 只关闭用户明确选择的 Ticket;
|
||||
- Ticket 回查通过后,再判断 Spec 是否满足最终门禁;
|
||||
- 需要时对部分成功的写入进行幂等重放。
|
||||
|
||||
Close 不补代码、不自动归档 Trellis,也不因为测试通过或 Agent 说“完成”就改变 Base 状态。
|
||||
|
||||
### Ticket 证据分类
|
||||
|
||||
| 分类 | 条件 | 默认动作 |
|
||||
|---|---|---|
|
||||
| 建议可收口 | 每条验收都有直接证据,且没有未解决阻塞 | 交给人审 |
|
||||
| 待补证/待验证 | 可能已实现,但至少一条验收缺少直接证据 | 不关闭 |
|
||||
| 明确未完成/阻塞 | 行为、依赖、决策、实现或验证仍未完成 | 不关闭 |
|
||||
|
||||
### Ticket 收口
|
||||
|
||||
用户必须明确两件事:
|
||||
|
||||
1. 代码和功能的人审已经完成;
|
||||
2. 哪些 Ticket record ID 允许关闭。
|
||||
|
||||
选中的 Ticket 更新为:
|
||||
|
||||
```text
|
||||
状态 = 已完成
|
||||
完成度 = 1
|
||||
阻塞原因 = 空
|
||||
下一步 = 空
|
||||
验证证据 = 保留原文并追加本次 closure 证据
|
||||
代码引用 = 保留原文并追加去重后的真实引用
|
||||
最后更新人 = 当前已验证用户
|
||||
```
|
||||
|
||||
每条记录都按 ID 回查。未选择的 Ticket 保持原状。只要还有 Ticket 不是 `已完成`,Spec 就不能完成。
|
||||
|
||||
### Spec 最终收口
|
||||
|
||||
必须同时满足:
|
||||
|
||||
- 所有子 Ticket 恰好为 `已完成`;或没有 Ticket,但 Spec 自身验收已有直接证据;
|
||||
- Spec 每条验收都有直接证据;
|
||||
- 没有 Ticket 写入失败或回查不一致;
|
||||
- 用户明确确认最终人审完成;
|
||||
- Trellis 任务已归档且 `task.json.status=completed`;Inline 无此门禁。
|
||||
|
||||
Ticket 关闭确认不能自动授权 Spec 关闭。Spec 必须再展示一次独立 patch 并取得确认。
|
||||
|
||||
## 3.4 Start → Inline / Trellis → Close
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["start-work-feishu:验证身份、24 字段、Base 和队列"] --> B["用户选择 Spec 或 Ticket"]
|
||||
B --> C["刷新 record ID、父项、依赖、负责人和更新时间"]
|
||||
C --> D{"选择执行路由"}
|
||||
|
||||
D -- "Inline" --> E["冻结 ID 和最新快照"]
|
||||
E --> F["确认选择、路由和 Base patch"]
|
||||
F --> G["Base:状态改为进行中并回查"]
|
||||
G --> H["当前会话实现、测试和整理证据"]
|
||||
|
||||
D -- "Trellis" --> I{"已有唯一 Spec task?"}
|
||||
I -- "有" --> J["复用 task"]
|
||||
I -- "没有" --> K["create --no-start:planning"]
|
||||
I -- "冲突" --> L["停止并处理映射冲突"]
|
||||
J --> M["刷新 Spec 来源、Ticket 快照和映射"]
|
||||
K --> M
|
||||
M --> N{"快照判定"}
|
||||
N -- "snapshot-only" --> O["机械一致性检查"]
|
||||
N -- "delta-reviewed" --> P["评审新增技术决策"]
|
||||
N -- "source-revision-required" --> Q["回到 Wiki/Base 修订正式源"]
|
||||
Q --> M
|
||||
O --> R["确认选择、路由、判定和 Base patch"]
|
||||
P --> R
|
||||
R --> S["Base:状态改为进行中并回查"]
|
||||
S --> T["task.py start:planning → in_progress"]
|
||||
T --> U["多会话实现、测试、评审和证据"]
|
||||
U --> V["task.py archive --no-commit:completed"]
|
||||
|
||||
H --> W["close-work-feishu:查询全部 Ticket 并收集证据"]
|
||||
V --> W
|
||||
W --> X["输出证据表和收口建议"]
|
||||
X --> Y{"人工评审并选择 Ticket"}
|
||||
Y -- "证据不足或未选择" --> Z["保留未完成记录并给出下一步"]
|
||||
Y -- "确认关闭" --> AA["更新所选 Ticket 并逐条回查"]
|
||||
AA --> AB{"全部 Ticket 完成且 Spec 验收满足?"}
|
||||
AB -- "否" --> AC["部分收口:Spec 保持进行中"]
|
||||
AB -- "是" --> AD{"Trellis 已归档?"}
|
||||
AD -- "未归档" --> AE["阻塞 Spec 收口;归档后重跑 Close"]
|
||||
AD -- "Inline 或已归档" --> AF["第二次人审:确认 Spec 最终关闭"]
|
||||
AF --> AG["更新 Spec 为已完成并回查"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 四、全流程总结
|
||||
|
||||
## 4.1 从初始化到收口
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["CLI 初始化"] --> B["Setup:解析 Base、Wiki 和项目"]
|
||||
B --> C["24 个字段 + 项目绑定 + spec/wayfinder 路由"]
|
||||
C --> D["HITL:对话、研究、原型和决策完成需求澄清"]
|
||||
D --> E["to-spec-feishu:Wiki Spec + Base PRD/Spec"]
|
||||
E --> F{"是否需要拆票?"}
|
||||
F -- "否" --> G["start-work-feishu:直接开始 Spec"]
|
||||
F -- "是" --> H["to-tickets-feishu:Base Tickets + 依赖图"]
|
||||
H --> I["start-work-feishu:选择 Spec 或 Ticket"]
|
||||
G --> J{"Inline / Trellis"}
|
||||
I --> J
|
||||
J --> K["代码、测试、评审和验证证据"]
|
||||
K --> L["close-work-feishu:关闭 Ticket"]
|
||||
L --> M{"Trellis 路线?"}
|
||||
M -- "是" --> N["确认 task 已归档"]
|
||||
M -- "否" --> O["跳过归档门禁"]
|
||||
N --> P["第二次人审:关闭 Spec"]
|
||||
O --> P
|
||||
P --> Q["Base、Wiki、代码和 Trellis 形成闭环"]
|
||||
```
|
||||
|
||||
## 4.2 每个环节的产出
|
||||
|
||||
| 环节 | 主要输入 | 主要产出 | 事实源 |
|
||||
|---|---|---|---|
|
||||
| CLI 初始化 | 飞书应用、用户授权 | bot/user 双身份可验证 | Lark CLI 配置 |
|
||||
| 项目 Setup | Base URL、Wiki 根 URL、项目名 | 24 字段契约、项目绑定、路由、`docs/agents/*` | Base + Wiki + Repo |
|
||||
| 需求澄清 | 对话、研究、原型、人工决策 | 已批准的产品目标、约束和验收 | Conversation/Wiki |
|
||||
| To Spec | 已澄清上下文、领域术语、测试 seam | Wiki Engineering Spec、Base `PRD/Spec` | Wiki + Base |
|
||||
| To Tickets | 已批准 Spec | Base Ticket、父子关系、依赖图、frontier | Base |
|
||||
| Start | 当前用户队列、record ID、依赖 | `进行中` 状态、Inline 上下文或 Trellis 映射 | Base + Conversation/Trellis |
|
||||
| 实现 | Spec、Ticket、代码库、Trellis 计划 | 代码、测试、命令结果、验证证据 | Repo + Trellis |
|
||||
| Close Ticket | 实时 Ticket、直接证据、人审选择 | Ticket `已完成` 或保留原状态 | Base |
|
||||
| Trellis Archive | 已完成的多会话任务 | `status=completed` 和归档路径 | Trellis |
|
||||
| Close Spec | 全部 Ticket、Spec 验收、最终人审 | Spec `已完成` | Base |
|
||||
|
||||
## 4.3 HITL 与 AFK 的边界
|
||||
|
||||
### HITL:必须有人拍板
|
||||
|
||||
| 环节 | 人工门禁 |
|
||||
|---|---|
|
||||
| Setup | 选择 Reuse/Bootstrap、Reuse/Provision,并确认具体外部写入 |
|
||||
| 需求澄清 | 确认目标、范围、约束、验收和是否继续交付 |
|
||||
| To Spec | 确认测试 seam 和正式 Spec |
|
||||
| To Tickets | 确认 Ticket 粒度、拆分和阻塞边 |
|
||||
| Start | 选择 record ID,确认 Inline/Trellis 和 Base patch |
|
||||
| Trellis 差量 | 评审新增技术决策;影响产品行为时回到正式源 |
|
||||
| Close Ticket | 确认代码/功能人审完成,并选择允许关闭的 Ticket |
|
||||
| Close Spec | 在所有门禁满足后进行最终关闭确认 |
|
||||
|
||||
### AFK:确认后可以交给 Agent
|
||||
|
||||
- 校验 CLI 身份、Base 坐标、字段和项目绑定;
|
||||
- 分页查询、关系解析、frontier 计算和状态分类;
|
||||
- 根据已确认上下文起草 Spec 和 Ticket;
|
||||
- 创建批准后的 Wiki/Base 产物并回查;
|
||||
- 建立、刷新和校验 Trellis 映射;
|
||||
- 在 Inline 或 Trellis 中实现代码、运行测试并整理证据;
|
||||
- 为 Close 生成验收映射、证据表和候选 patch。
|
||||
|
||||
`协作模式=AFK` 只代表执行阶段适合交给 Agent,不代表全程无人参与。当前没有 `ready-for-human` 状态;人工参与由 HITL 门禁、`待评审` 和显式确认表达。
|
||||
|
||||
## 4.4 运行时边界
|
||||
|
||||
1. 不用标题更新记录,始终使用稳定 record ID。
|
||||
2. 不猜 Base、table、view、Wiki 节点或项目名,全部来自项目契约和真实解析。
|
||||
3. 不把未知 JSON 响应当成空结果。
|
||||
4. 不因 `ok: true` 宣称成功,所有写入都要回查。
|
||||
5. 不把 bot ID 写进 `最后更新人`。
|
||||
6. 不覆盖 `负责人` 来表达归因。
|
||||
7. 不跨项目建立父子或依赖关系。
|
||||
8. 不把 Wiki Spec 全文复制成另一份 Trellis 业务 Spec。
|
||||
9. 不把 `task.py finish` 当作 Trellis 完成。
|
||||
10. 不因测试通过、Agent 评审通过或 Trellis 归档自动关闭飞书记录。
|
||||
11. Ticket 收口和 Spec 最终收口分别获得人工确认。
|
||||
12. 没有直接验证证据时,记录“未运行”及原因,不能声称完成。
|
||||
|
||||
## 4.5 各系统各管一段
|
||||
|
||||
```text
|
||||
对话 / 研究 / 原型
|
||||
│ 需求决定、验收和风险
|
||||
▼
|
||||
飞书 Wiki:Engineering Spec、Map、研究和决策长文
|
||||
│ 长文链接
|
||||
▼
|
||||
飞书 Base:Spec/Ticket 状态、负责人、父子关系、依赖和证据摘要
|
||||
│ 执行上下文映射
|
||||
▼
|
||||
Trellis:计划、多会话上下文、快照和归档
|
||||
│ 代码与验证
|
||||
▼
|
||||
代码仓库:实现、测试、ADR 和真实引用
|
||||
```
|
||||
|
||||
最终闭环是:需求在进入 Base 前已经明确,Wiki 保存可读的正式产物,Base 保存可查询的工作状态,Trellis 保存执行上下文,代码仓库保存实现事实;人工只在关键决策、认领和收口处拍板。
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user