P4.7 P2 write 审批载体选型 —— 决策前的完整权衡(2026-07-09)
P4.7 P1(read-class dispatch)已完成 + 验收。P2 做 write-class tool 审批半场。核实(只读,file:line 亲验)发现 spike 锁定的 ExpertQueueItem 与 gateway 现有实现正面冲突,且两个载体各有真实代价。本文档把选型权衡摊开,供决策,动工前不写代码。用户回来读完拍板载体 + P2 范围。
已锁 / 已知(不复议的部分)
- 方向 A + 甲(复用 gateway,凭证留控制平面)—— P1 已落地内部信任认证,P2 延续。
- write tool 流程:write-class → gateway 判 accessClass=write → 不执行真副作用 → 建审批载体 → Expert 批准后 server-side 执行。PRD R6.4 验收:
A write-class tool call creates an Expert approval item; nothing executes before approval. - messageId 技术门槛已被 P1 意外解决:AgentRun 有
messageId字段(entities.ts:1846),P1 createRun 时填了 inbound 用户消息 id(conversations.service.ts:3236),gatewayexecute已加载 run 对象(tool-gateway.service.ts:85)→run.messageId立即可用。所以"建审批项需要非空真实 messageId"能满足。
核实出的真实冲突(三方不自洽)
| 来源 | 审批载体 | 返回语义 | 证据 |
|---|---|---|---|
| gateway 现状 | ApprovalRequest(表 approval_requests,有 payload jsonb + runId FK,runtime 原生,无 Expert UI) | waiting_approval(挂起——Hermes 会阻塞) | tool-gateway.service.ts:211-242 require_approval 分支已建 ApprovalRequest + AgentRun.status→waiting_approval + pendingApprovalCount++(approval-request.service.ts:83-85) |
| spike 结论(用户曾锁) | ExpertQueueItem | queued_for_approval(正常成功——Hermes 不阻塞) | docs/superpowers/specs/2026-07-09-p4.7-hermes-runtime-spike-results.md:49-52 |
| PRD R6.4 | 措辞"Expert queue approval item"(偏 ExpertQueueItem)但点名 ActionPolicyService(那是 ApprovalRequest 路径) | 未明说 | docs/specs/prd-specialist-value-output.md:202 |
关键:spike 锁 ExpertQueueItem 时,可能未充分意识到 gateway 现有 require_approval 已经走 ApprovalRequest。核实后 ApprovalRequest 在 tool 审批场景语义反而更贴。这个锁定值得复议。
两个载体的完整权衡
选项 A:ApprovalRequest(复议 spike,推荐)
- 优点:①天生有
payloadjsonb 承载 write 动作(tool/action/params)②有 runId FK,runtime 原生 ③gateway 现状已建它,改动最小 ④与"甲=复用 gateway/runtime 栈"一致 ⑤Hermes 那侧看到"挂起"直到批准,是 tool-call 的自然语义。 - 代价:①没有任何 Expert workspace UI——ApprovalRequest 从没在前端露过(
ops/agent-runs|approvals|machines是 SA 只读运维面板,非 Expert 审批面)。要新建 Expert 审批界面(dev 演示期前端难端到端验)②返回语义waiting_approval(挂起)vs spike 要的queued_for_approval(正常成功不阻塞 Hermes)——需定:让 Hermes 挂起等批准(同步阻塞,但 /chat 有超时)还是返回成功让 Hermes 继续(异步,真副作用后补)。这点本身是子决策。 - 偏离:违背 spike 明写"审批载体=ExpertQueueItem(用户已锁)"——需用户确认复议。
选项 B:ExpertQueueItem(守 spike)
- 优点:①对齐 PRD"Expert queue approval item"措辞 ②复用 Expert workspace 现有 HITL 队列(有 UI)③Expert 已习惯在那审草稿。
- 代价:①messageId 语义不对——现有语义是"待审 AI 草稿"(P3.5/escalation 全传
agentMsg.id),tool 审批场景传run.messageId(inbound 用户提问),现有 Expert UI 渲染逻辑(如expert-queue.service.ts:1168读item.messageId当草稿比对)会拿到语义错误对象 ②无 payload 字段——write 动作只能塞metadatajsonb(entities.ts:921),Expert UI 需专门识别"tool 审批 item"而非草稿 item ③可能需 migration 让messageId可空(有@Index+ expert-queue.service.ts 十余处item.messageId读点,blast radius 大)④释放机制(F3 atomic release)假定背后是草稿发送,tool 审批的"释放=执行副作用"是不同动作。 - 偏离:无(守 spike),但代价是硬塞一个不匹配的数据模型。