Files
cc-web/.planning/2026-08-23-gitea-workflow/plan-review.md

13 KiB
Raw Blame History

Gitea Workflow 实施计划审查

审查日期:2026-08-24
审查范围:task_plan.md、findings.md、Gitea Workflow TO DO list.csv 及用户目标“完整实现 Gitea Webhook → Codex App 持久会话 → 官方 gitea-mcp → Gitea 回执的可靠工作流,并提供管理页面、队列、恢复、测试和文档”。本审查只产生本文件,不修改业务代码或其它计划文件。

结论

当前计划在“阶段主题”层面与 CSV 基本一致,但还不能作为可直接执行和可验收的实施基线。建议先补齐 Phase 1 的协议、状态机、数据模型和安全设计,再进入实现;否则最容易出现“功能链路能跑一次,但重启、重复 Webhook、回执失败或并发时不可靠”的假完成。

建议结论:有条件通过,暂不进入核心编码。以下 P0 项未关闭前,不应把 CSV 中的核心实现项标记为 DONE。

计划与 CSV 一致性

计划范围 对应 CSV 一致性 审查意见
Phase 1 需求、协议、设计(task_plan.md:13-18) 1、2 基本一致 CSV 第 1 项为 IN_PROGRESS,与计划“进行中”一致;但“已完成边界汇总”和“设计文档尚在编写”的完成定义没有拆开。
Phase 2 状态、Webhook、工作区(task_plan.md:20-25) 3、4 基本一致 计划把队列/恢复和工作区放在同一阶段,CSV 分成两项;缺少明确前置依赖、交付物和负责人。
Phase 3 Codex App、MCP、回执(task_plan.md:27-32) 5 基本一致 CSV 将线程注入、监听、补触发、REST 兜底合成一项,无法分别验收可靠性。
Phase 4 管理界面、测试(task_plan.md:34-39) 6、7 基本一致 计划中的重启恢复、并发、自触发回归没有在 CSV 中单列,容易被“测试已补充”掩盖。
Phase 5 整合、验证、交付(task_plan.md:41-45) 8、9、10 一致 但“解决冲突”“协议形状检查”“文档/审计”均没有明确输出文件、命令和通过阈值。

总体上,CSV 的 10 项与计划的 15 个子项不是一一映射关系。建议在计划和 CSV 中增加稳定的任务 ID(例如 P1-01、P2-02),并为每项写明 交付物 / 依赖 / 验收命令或证据 / 负责人;否则状态同步只能凭文字判断。

P0 阻断项

P0-1:Phase 1 没有可执行的退出条件

计划只写“核验协议”“完成 PRD、状态机、数据模型和安全设计”(task_plan.md:16-17),没有指定文档路径、协议版本、决策结果或评审证据。findings.md 目前只有研究结论,没有状态转移表、字段定义、接口契约或威胁模型。

进入 Phase 2 前至少应产出并评审:

  • Webhook 请求/响应和签名头的版本化协议矩阵;官方 gitea-mcp 版本、启动参数、stdio 生命周期和工具能力清单。
  • 任务/会话/回执状态机(状态、事件、合法转移、重试上限、超时、取消、死信、人工恢复)。
  • 持久化数据模型、唯一键、索引、迁移/版本策略和崩溃恢复规则。
  • 线程、任务、Webhook delivery、评论和回执之间的关联契约。
  • 安全威胁模型与密钥生命周期设计。

P0-2:持久化方案无法证明并发安全和崩溃一致性

findings.md:17 仅指出现有 JSON 持久化或“新增独立存储模块”,但没有做出选择。队列、去重、状态转移、会话映射和回执确认若继续散落写 JSON,会遇到并发覆盖、半写文件、重复消费和重启丢失;这与目标中的“持久化、可靠、可恢复”直接冲突。

计划必须明确单一事实源及原子性边界:至少要定义 inbox(Webhook 去重)、任务状态、会话映射、outbox(评论/补发意图)如何在一次事务或等价原子操作中落盘;并定义锁、文件替换、fsync、备份/恢复和 schema 迁移。若采用 JSON,需证明单写者/进程锁和崩溃恢复;若不能证明,应在计划中选择具备事务语义的存储。

P0-3:状态机、幂等和回执可靠性没有闭环

findings.md:34-39 给出了“先验签/去重/过滤”“最多一次隐藏补触发”“REST 兜底”的原则,但没有定义可判定的幂等键、评论标记、确认窗口、重复运行保护或失败终态。尤其“任务完成但没有回帖”时,如何区分 MCP 调用已成功但查询延迟、调用超时、网络重试导致重复评论,当前不可执行。

需要补充:

  • delivery、任务、turn、评论发送各自的唯一 ID 及跨表关联。
  • 评论内容中的稳定 run/attempt 标记或等价查询条件,保证 MCP、补触发和 REST 兜底不会重复发同一回执。
  • Gitea 查询的最终一致性轮询窗口、退避、最大次数和“未知”状态;未知不能直接当失败重跑。
  • 重试分类(网络/5xx、4xx 权限、超时、进程崩溃)、退避与死信/人工重放策略。
  • 重启时每个状态的恢复动作,特别是 running、waiting_user、receipt_pending 和 cancel_requested。

P0-4:三方协议的真实形状和版本未锁定

findings.md:19-25 只记录官方仓库和大致参数,task_plan.md:29-30 也没有 app-server 方法、事件类型或 MCP 注入字段。没有固定版本和 mock 契约,无法验收“线程级注入”和“turn 状态监听”是否真的走原生协议。

应在 Phase 1 固化并纳入 mock/回归断言:

  • Gitea Webhook 事件类型、评论字段路径、签名算法/头、delivery ID、超时和 HTTP 返回语义。
  • Codex App initialize/initialized、能力探测、thread/start、线程恢复、turn 事件和取消/中止的确切参数形状。
  • thread/start.config.mcp_servers.* 的线程级 env 注入、stdio 子进程启动/退出、超时和错误事件;不得退回动态工具或进程级来源上下文。
  • 官方 gitea-mcp 版本/校验和、GITEA_HOST 与 token 注入方式、工具列表和权限边界。

P0-5:全写权限下的安全边界不足

计划确认“开放官方 gitea-mcp 全部写权限”(task_plan.md:63),但安全设计只写 HMAC 和 Token 分离(task_plan.md:62)。这不足以支撑公网 Webhook 和自动接入。至少要覆盖重放、密钥轮换、日志脱敏、仓库/主机 allowlist、请求体大小和限流、路径穿越、命令注入、工作区权限、MCP 子进程隔离,以及管理页面的认证/授权/CSRF。

同时要明确 Bot 自评论过滤不能只依赖用户名:应定义稳定的 bot identity、来源 delivery/run 标记和异常情况下的 fail-closed 行为,避免自触发风暴(findings.md:34-36)。

P0-6:跨模块写冲突和整合策略未规划

Phase 5 写“整合子任务改动并解决冲突”(task_plan.md:43),但没有任务分区、文件所有权、接口冻结点或整合顺序。预期热点很可能包括 server.js、配置/持久化模块、Codex App turn 路径、MCP 配置、路由和前端状态;多个实现项若直接改同一入口,会产生不可审计的隐式冲突。

进入实现前应把工作拆成不重叠边界(例如 domain/state、webhook/queue、workspace、app-server adapter、API/UI、tests/docs),先冻结共享接口,再按依赖顺序合并;禁止以“最后人工解决冲突”作为验收条件。

P1 重要遗漏与可执行性问题

1. 队列与恢复

Phase 2 只列“状态、队列、去重和恢复”(task_plan.md:22),缺少全局并发上限为 2 的调度算法、公平性、每仓库串行锁的租约/心跳、进程崩溃后的 stale runner 判定、优雅停机、取消排队与中止 turn 的区别、超时、死信和人工重放。应为每一类恢复场景写出输入、状态变化和预期结果,并加入 kill/restart 测试。

2. Webhook 与自动接入

findings.md:5-7 未定义配置校验、首次接入的授权边界、仓库 URL/owner/repo 的规范化、默认分支和私有仓库权限失败处理。需要明确先快速返回 HTTP,再异步入队还是同步处理;验签失败、重复 delivery、非评论事件、非目标评论、Bot 自评论分别返回什么,避免 Gitea 重试风暴。

3. 工作区与 Git 认证

findings.md:40 的“脏工作区不 reset、不覆盖”是原则,不是行为契约。要决定脏状态时任务是失败、暂停、继续当前会话还是创建隔离 worktree;定义分支/ref 切换、fetch 冲突、仓库删除、磁盘不足、凭据泄露(命令行/日志/remote config)和清理策略。持久 checkout 与“同仓库串行”还需明确锁的持有范围。

4. Codex App 会话与 waiting_user

计划确认会话键(task_plan.md:59)和固定 codexapp + yolo(task_plan.md:58),但没有说明首次建线程、重启后的线程恢复、线程不存在/过期、app-server 断线、turn 超时及取消后的映射。waiting_user(task_plan.md:31、task_plan.md:64)没有定义由哪类 Gitea 评论恢复、是否阻塞同仓库、超时/过期和最大连续轮数;“连续评论投递”也没有顺序和幂等规则。

5. 管理 API 与前端

Phase 4 只写“实现管理 API 和前端页面”(task_plan.md:36),没有端点契约、权限角色、敏感配置展示规则、暂停/停用/取消/中止的并发控制、审计记录格式、分页过滤、实时刷新和错误提示。管理页面不能成为绕过队列状态机的第二套写入口;所有操作应复用同一领域命令和审计链。

6. 测试与验收证据

CSV 第 7、9 项虽覆盖“测试、构建、协议验收”,但没有测试矩阵、通过阈值或运行命令。至少应覆盖:重复/乱序 Webhook、伪造/重放签名、Bot 自触发、首次接入、同仓库并发、不同仓库并发上限、脏工作区、clone/fetch 失败、app-server 断线、MCP 缺失/工具报错、turn 中止、waiting_user、MCP 成功但查询延迟、补触发成功/失败、REST 兜底、进程 kill 后恢复、密钥轮换和管理 API 未授权。

协议测试不能只断言“调用成功”,还要断言真实参数形状、线程级 env、没有重复顶层字段、调用的是 MCP 工具而非动态工具,并保存 mock 输入/输出作为审计证据。应明确单元/集成/E2E 的最小通过标准和 CI/本地命令。

7. 运维、可观测性与交付

用户目标包含队列、恢复和文档,但计划未列指标、结构化日志、关联 ID、告警、数据保留、备份恢复、升级/回滚、配置校验和运行手册。Phase 5 的“文档、审计和最终交付”(task_plan.md:45)应明确至少包括架构/状态机、部署配置、Webhook 配置、密钥轮换、故障处理、恢复/重放、权限说明和已知限制。

建议的执行顺序与退出条件

  1. 先完成 Phase 1 冻结契约:补齐上述协议矩阵、状态机、schema/迁移、领域命令、错误/重试表、安全威胁模型和 mock fixture;每项有文档路径和评审人。
  2. 再实现持久化领域核心:先落地 inbox、任务、会话、outbox、审计的原子状态转移和恢复算法,再接 Webhook/工作区,避免入口先写出不可恢复的副作用。
  3. 接入 Codex App 与 gitea-mcp:以固定版本和协议 mock 验证线程级配置、turn 事件、取消/重连;所有回执发送经过幂等 outbox。
  4. 最后接 API/UI 和故障测试:API/UI 只发领域命令;并发、重启、自触发和回执异常测试必须在标记 Phase 4 完成前通过。
  5. Phase 5 交付门槛:构建、静态检查、全测试和协议形状断言均有可复现命令;文档、审计样例、恢复演练记录和回滚方案齐全。

推荐把每个阶段的状态改成“未开始/进行中/阻塞/完成”,并在完成条件中引用证据文件或测试名称,而不是只保留勾选框。

最小验收清单(对应用户目标)

  • Webhook:合法评论可入队;伪造、重放、重复 delivery、非目标事件和 Bot 自评论均按契约处理。
  • 持久会话:会话键稳定;重启后任务、锁、turn 和 waiting_user 状态可恢复且不重复执行。
  • 官方 MCP:固定版本、线程级配置、凭据不落盘/不泄露;读写工具调用可被 mock 和审计验证。
  • 回执:成功评论可确认;未知状态不会盲目重跑;只允许一次补触发,之后 REST 兜底仍幂等。
  • 队列/并发:同仓库串行、不同仓库并行、全局上限 2 可证明;暂停、取消、终止和死信可操作。
  • 管理面:认证授权、审计、状态查询和运维操作与领域状态机一致,不暴露 token/secret。
  • 可靠性测试:覆盖崩溃恢复、并发、网络/权限/协议失败和自触发回归,并有可重复命令与结果。
  • 文档交付:架构、配置、部署、密钥、故障恢复、重放、回滚和已知限制齐全。

审查结论摘要

CSV 与计划没有明显的宏观漏项,但粒度、状态和验收证据不一致;当前最大的风险不是缺少页面或接口,而是持久化原子性、状态机幂等、三方协议形状和全写权限安全边界尚未冻结。补齐 P0 并将其转成带 ID/依赖/证据的任务后,计划才具备可靠实施条件。