feat(ack): refine intake and validation workflow

This commit is contained in:
2026-08-04 10:52:37 +08:00
parent b9c82b5520
commit 5018a1801d
32 changed files with 1602 additions and 302 deletions
+107 -100
View File
@@ -1,53 +1,71 @@
# 飞书 Base Bug 整理与审核
飞书 Base 是 Bug 在**审核通过前的唯一协作区**。用户先在飞书记录 Bug 描述,
Coordinator 读取记录和项目现状,补全或修改修复逻辑、验收标准,再写回同一条飞书
记录。用户可以继续在飞书反馈,Coordinator 按反馈反复修订。只有用户明确表示审核
通过后,Coordinator 才把最终版本写入 `docs/ack/tasks.yaml`,随后启动 ACK 三角色闭环。
飞书 Base 是 Bug 在审核通过前的唯一协作区。用户只需填写 `标题`,可选填写
`详细描述`,并把截图、录屏或日志放在 `附件`。Coordinator 结合来源事实、附件和项目
现状整理 `问题说明``期望效果``验收标准`,但不在收件箱写修复逻辑。
审核前不创建或刷新 `tasks.yaml` 中的 ACK 任务,不得启动 worker,不得派发
Developer/Test,也不得修改应用代码。飞书字段已填满、记录进入某个 view、用户暂时没有
回复,都不等于审核通过。
审核通过前不创建或刷新 `tasks.yaml` 中的 ACK 任务,不得启动 worker、派发 Developer/Test
修改应用代码。字段已填满、记录进入某个 view、用户暂时没有回复,都不等于审核通过。
## 项目配置
## 项目配置与 Base 结构
项目在 `docs/ack/tasks.yaml``project.bugIntake` 声明 `provider: feishu-base`
`workflow: reviewed-writeback-v1`、显式 `profile``baseToken``tableId`用于候选 Bug
`viewId` 和字段映射;不要保存 App Secret、access token 或任何 profile 凭据。
`docs/ack/tasks.yaml``project.bugIntake` 必须声明 `provider: feishu-base`
`workflow: clarified-writeback-v1`、显式 `profile``baseToken``tableId``viewId` 和字段映射:
原有八字段配置在未声明 `workflow` 时按 `read-only-v1` 兼容读取,不得写回或进入本节
流程。启用审核前协作必须显式选择 `reviewed-writeback-v1`,并在 `title``actual`
`expected``stepsToReproduce``acceptance``priority``attachments``updatedAt`
之外配置可写文本字段 `fixLogic`。其中 `fixLogic``acceptance` 由 Coordinator 维护;
用户提供的标题、实际表现、预期结果和附件属于来源事实,Coordinator 不得覆盖。
```yaml
fields:
title: 标题
details: 详细描述
problemStatement: 问题说明
expectedOutcome: 期望效果
acceptance: 验收标准
intakeStatus: 处理状态
ackTaskId: ACK任务ID
attachments: 附件
updatedAt: 更新时间
```
## 一次性安装与 profile 设置
人维护 `标题``详细描述``附件`ACK 维护 `问题说明``期望效果``验收标准`;系统字段
`处理状态``ACK任务ID``更新时间`。状态按
`待整理 → 需补充/待审核 → 已确认 → 已导入` 流转。优先级在批准后做任务规划时确定,
不属于收件箱审核内容。原 `read-only-v1``reviewed-writeback-v1` 继续兼容旧项目。
在账号级可信工具目录安装官方 CLI;ACK 读取器只会搜索账号的 `~/.local/bin`、mise/cargo
shim 目录和固定系统目录,绝不会采用项目 `PATH` 中的同名文件。它同时识别官方 npm
包生成的 `lark-cli -> @larksuite/cli/scripts/run.js` wrapper,并校验 package 名与 bin
映射,然后直接执行该官方包下载的 native binary
结构变更必须先执行只读计划,再携带计划指纹应用;适配器只新增目标字段、迁移来源信息并
调整当前 view 的可见字段,不删除旧列:
```bash
python3 <ack-skill-dir>/scripts/feishu_bug_intake.py schema-plan docs/ack/tasks.yaml
python3 <ack-skill-dir>/scripts/feishu_bug_intake.py schema-apply docs/ack/tasks.yaml \
--expected-schema-fingerprint <schemaFingerprint>
```
迁移时,旧 `期望结果` 会以 `用户原始期望:…` 合并进 `详细描述`,旧字段继续保留但从
当前 view 隐藏;空状态初始化为 `待整理`。不要保存 App Secret、access token 或 profile
凭据。
## Profile 和安全边界
在账号级可信目录安装官方 CLI
```bash
npm install --global --prefix "$HOME/.local" @larksuite/cli@latest
```
随后在受控终端中用 stdin 提供 App Secret,选择 Feishu brand,避免 secret 进入 shell
history、进程参数或项目文件:
```bash
printf '%s' "$FEISHU_APP_SECRET" | lark-cli profile add \
--name project-feishu --app-id "$FEISHU_APP_ID" \
--app-secret-stdin --brand feishu
```
项目配置只填写 `profile: project-feishu`。不要执行 `profile use`,也不要依赖 active
profile;读取、附件下载和写回都必须显式传 `--profile project-feishu`。profile 至少需要
`base:record:read``base:record:write` `docs:document.media:download`
不要把 `lark-cli auth check` 当作 app/bot scope 的证明,因为它检查的是当前用户的
stored user token。
使用官方 `lark-cli`,项目只保存 profile 名。不要依赖 active profile;所有读取、附件下载、
写回和结构迁移都显式传配置 profile。profile 需要 Base 读写和附件下载权限。
所需 scope 至少包括 `base:record:read``base:record:write`
`docs:document.media:download`不要把 `lark-cli auth check` 当作 app/bot scope 的证明,
它只检查当前用户的 stored user token。
## 读取与整理计划
适配器只搜索账号和系统的可信工具目录,子进程只收到实际账号 HOME、可信 PATH 和基础
locale;调用者环境中的凭据和运行时注入变量不会传入。不得绕过适配器直接操作 Base。
每条记录最多 10 个附件、单批最多 100 个,单个附件最多 20 MiB、合计最多 200 MiB
整批下载最多 5 分钟。
## 读取与整理
```bash
python3 <ack-skill-dir>/scripts/feishu_bug_intake.py check docs/ack/tasks.yaml
@@ -58,84 +76,73 @@ python3 <ack-skill-dir>/scripts/feishu_bug_intake.py plan docs/ack/tasks.yaml \
--output-dir "$tmpdir"
```
`fetch` 只调用官方 `base +record-list` 和附件下载命令,输出标准化 JSON,并为每条记录
计算覆盖来源事实、附件元数据和审核字段的 `draftRevision``plan` 只生成
`create` / `refresh` / `unchanged` / `drift` 候选动作,不修改飞书或任务板。**审核通过
不得执行这些候选动作**;它们只用于查重和预览最终导入结果
`fetch` 输出标准化 JSON,并为每条记录计算覆盖来源事实、附件身份、整理字段和状态的
`draftRevision`。标题和更新时间是必需来源事实;详细描述和附件可为空。问题说明、期望
效果、验收标准缺失时返回 `enrichmentRequired``plan` 只给出查重和漂移预览,审核
不得据此创建任务
标题、实际表现、预期结果和更新时间属于来源事实,任一缺失时读取失败。复现步骤、
修复逻辑、验收标准和优先级属于 Coordinator 可整理字段;缺失时记录与 action 返回
`enrichmentRequired`。没有附件且所有 Bug 内容字段都为空的误建行会跳过,并在批次
`warnings` 中返回 `blank_record_skipped`
Coordinator 对每条 Bug
子进程只收到实际账号 HOME、可信 PATH 和基础 locale;调用者环境中的
`LARKSUITE_CLI_*``FEISHU_*``NODE_OPTIONS` 等变量不会传入。每条记录最多 10 个
附件、单批最多 100 个,单个附件最多 20 MiB、合计最多 200 MiB,整批下载最多 5 分钟;
始终使用新的临时目录作为 `--output-dir`
1. 读取标题、详细描述、附件及相关产品/代码上下文;证据不足时明确假设,不伪装成用户原文。
2.`problemStatement`:说清现象、影响范围和边界,不包含修复方案。
3.`expectedOutcome`:说明正确情况下用户能观察到的行为,不包含实现方式。
4.`acceptance`:形成可独立复测的、可观察的标准,不扩张用户未表达的产品范围
5. 将草案保存为不超过 64 KiB 的 JSON,且只含上述三个键:
## 审核前协作循环
```json
{
"problemStatement": "非空字符串",
"expectedOutcome": "非空字符串",
"acceptance": ["非空验收项"]
}
```
对每条候选 BugCoordinator 按以下顺序工作
使用当前 `sourceRef``draftRevision` 写回
1. 读取用户填写的来源事实、附件和项目代码/测试,确认问题边界;证据不足时把不确定点
明确写成假设,不伪装成用户原文。
2. 整理复现步骤和优先级,并生成:
- `fixLogic`:说明根因判断、计划修改的位置与行为、需要保持的不变量,以及回归风险;
它是待审核的实现方向,不宣称代码已经修改。
- `acceptance`:写成可观测、可独立复测的标准,至少覆盖用户可见结果、真实状态或 API
结果,以及原失败不再出现;不扩张用户没有表达的产品范围。
3. 把本轮草案保存为不超过 64 KiB 的临时 JSON:只包含非空字符串 `fixLogic` 和非空
字符串数组 `acceptance`。通过安全适配器写回当前飞书记录:
```bash
python3 <ack-skill-dir>/scripts/feishu_bug_intake.py write-draft \
docs/ack/tasks.yaml --record-id <record-id> \
--expected-source-ref <sourceRef> \
--expected-draft-revision <draftRevision> --input <draft.json>
```
```bash
python3 <ack-skill-dir>/scripts/feishu_bug_intake.py write-draft \
docs/ack/tasks.yaml --record-id <record-id> \
--expected-source-ref <sourceRef> \
--expected-draft-revision <draftRevision> --input <draft.json>
```
`write-draft` 会在写前确认 record 属于配置 view,且 `sourceRef`、`draftRevision` 与调用者
看到的版本一致;它只允许覆盖配置映射的 `fixLogic` 和 `acceptance`,拒绝 symlink、超限
或多余字段输入,并复用读取器的可信 CLI、显式 profile、最小环境和成功 envelope 校验。
不得绕过适配器直接调用 PATH 中的 CLI,也不得改标题、实际表现、预期结果、附件或其它
用户字段。
4. `write-draft` 会回读同一记录、确认落盘值一致并返回当前 `draftRevision`。把这个 revision
连同记录交给用户审核;不能只展示没有 revision 的自由文本。
5. 用户提出意见时,重新读取最新记录和反馈,修订后再次写回、回读、等待审核;不要在
本地或聊天中维护一份与飞书分叉的“最终草案”。
任一写回、回读或字段校验失败时停止本轮并报告,不能转入任务板或三角色处理。
适配器在写前检查记录仍位于配置 view 且 revision 未漂移,只覆盖问题说明、期望效果、
验收标准和处理状态(设为 `待审核`),随后回读并返回新 revision。把新 revision 连同整理
结果交给用户审核。用户反馈后重新读取、修订和写回;不要在聊天或本地维护分叉版本。
## 审核门禁与导入
只有用户针对当前飞书记录的明确 `draftRevision` 表示审核通过”“可以执行”或等价授权,
才解除门禁。授权必须发生在最后一次草案写回和回读之后;之后若用户字段、附件、
`fixLogic` 或 `acceptance` 再次变化,revision 会变化,原授权失效,必须重新审核
只有用户针对当前 revision 明确表示审核通过,并由用户本人在飞书把处理状态改为
`已确认`,才可继续导入。Coordinator 使用的适配器不提供把草案自行标成已确认的命令;
状态和任务 ID 不参与内容 revision,因此用户确认状态不会改变已批准内容的 revision
审核通过后,Coordinator 才执行以下动作
重新读取并核对状态和 revision 后执行
1. 通过适配器重新读取并生成规范任务草案;命令会要求当前 `sourceRef` 和
`draftRevision` 精确等于用户批准值:
```bash
python3 <ack-skill-dir>/scripts/feishu_bug_intake.py import-approved \
docs/ack/tasks.yaml --record-id <record-id> \
--expected-source-ref <approved-sourceRef> \
--expected-draft-revision <approvedDraftRevision>
```
```bash
python3 <ack-skill-dir>/scripts/feishu_bug_intake.py import-approved \
docs/ack/tasks.yaml --record-id <record-id> \
--expected-source-ref <approved-sourceRef> \
--expected-draft-revision <approved-draftRevision>
```
任一来源事实、附件或整理字段变化都会使旧批准失效。导出的 `taskDraft` 把问题说明映射为
`description`、期望效果映射为 `expected`、验收标准映射为 `acceptanceCriteria`;不包含
修复逻辑、复现步骤或优先级。Coordinator 在后续任务规划中补充优先级,但不得改写已审核
字段;校验器会重算 `approvedPayloadHash`
不一致时停止并重新审核。输出的 `taskDraft` 包含批准后的规范字段以及
`source.workflow`、`source.approvedRevision`、`source.approvedPayloadHash`。
2. 按 `source.ref` 查重,把 `taskDraft` 原样合并到新的 ACK task,只补任务 ID、状态、
dispatch 等 ACK 运行字段;不得手工改写 `fixLogic`、`acceptanceCriteria` 或其它审核字段。
可在 `evidence.intakeEnrichment` 标明 Coordinator 推断依据,但它不替代规范字段。
3. 运行 `validate_tasks.py`。校验器会重算 `approvedPayloadHash`;只有写入和校验都成功,
任务才可作为已确认的 `open` 任务
进入 ACK 闭环。
4. 按 Coordinator → Developer → Test 的标准流程派发、实现和独立复测。
`taskDraft` 写入 `tasks.yaml`、补齐任务 ID 和规划字段并通过任务板校验后,再把最终
任务 ID 与同一批准 revision 写回飞书:
相同来源只更新尚未派发的 `open` 任务;`dispatched`、`fixed_by_dev`、`retesting`、
`failed_retest`、`verified`、`blocked` 和 `leftover` 任务只告警来源漂移,由用户决定是否
新建任务。项目启用 reviewed workflow 后,历史 `verified` / `leftover` 只读来源继续保留;
其它仍可执行的 legacy 飞书任务必须先按当前流程重新整理和审核,不能通过省略或降级
`source.workflow` 绕过门禁。飞书记录消失、不可访问或同步失败时,已有 ACK 任务一律保留。
```bash
python3 <ack-skill-dir>/scripts/feishu_bug_intake.py mark-imported \
docs/ack/tasks.yaml --record-id <record-id> --task-id <ack-task-id> \
--expected-source-ref <approved-sourceRef> \
--expected-draft-revision <approvedDraftRevision>
```
适配器只在任务板恰有一条 ID 匹配、来源引用、记录 ID、批准 revision 和 payload hash
全部一致的任务时,写入 `ACK任务ID` 并把状态推进到 `已导入`;回读不一致则失败。重复执行
同一绑定是幂等的,不能把一条记录改挂到另一个任务。
`source.ref` 查重:仅未派发的 `open` 任务可刷新;其它状态只报告来源漂移,不覆盖。
来源消失、不可访问或同步失败时,不删除已有 ACK 任务。