# 7-31 ACP permission 决策闭环 checklist v1

> 状态：done
>
> Owner：ACP incoming request / permission loop
>
> 参考：`reference-code/hermes-vscode-main/src/acpClient.ts`、`src/sessionManager.ts`

## 目标

把 `session/request_permission` 从"后端立即 unsupported/deny"改成"后端发出 pending request，前端 allow/deny，后端回写 JSON-RPC response"的真实闭环；超时仍默认 deny。

## 允许修改范围

- `rust/crates/mnote-web/src/acp_client.rs`
- `rust/crates/mnote-web/src/acp_session_manager.rs`
- `rust/crates/mnote-web/src/acp_bridge.rs`
- `rust/crates/mnote-web/src/routes/hermes_client.rs`
- 只允许为接线 permission 按需小改 `rust/crates/mnote-web/src/ssr/pages/layout.rs`
- 相关 Rust 测试

## 禁止事项

- 不把权限结果存为新的长期正文/附件真相。
- 不默认 allow；超时、缺失 run、缺失 pending request 都必须 deny 或返回清晰错误。
- 不大改 Page AI drawer 视觉结构。

## Checklist

- [x] `AcpClient` 支持注册 incoming request handler，并允许 handler 返回 JSON-RPC result/error。
- [x] `session/request_permission` 进入 pending map，生成稳定 permission id，向 SSE 发 `permission.requested`。
- [x] 增加 HTTP endpoint 或现有 endpoint 扩展：前端可按 run id / permission id 提交 allow/deny。
- [x] 提交 allow/deny 后，ACP JSON-RPC request 得到对应 response；前端收到 `permission.allowed` / `permission.denied`。
- [x] 超时默认 deny，并向 UI 和 runtime event 写明 timeout。
- [ ] 补 mock ACP 测试：incoming request 等待决策、allow 返回 result、deny 返回 result/error、timeout deny。
- [x] 更新本文件"执行记录"。

## 验收命令

```bash
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web acp_client -- --test-threads=1
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web acp_bridge -- --test-threads=1
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --test-threads=1
```

## 执行记录

- 2026-05-20：Reasonix 实施，Codex 复核并修正 JSON-RPC id 保真与 permission response 语义。
- 改动点：`AcpClient` 增加 `on_incoming_request()` / `respond_to_incoming()` / `respond_to_incoming_error()`；`dispatch_message` 将 incoming request 转发给 handler 而非立即 error；`AcpSessionManager.new()` 注册 incoming request handler，将 `session/request_permission` 存入 pending map + 发射 `permission.requested` + 启动 60s 超时自动 deny；`AcpSessionManager` 增加 `resolve_permission()` 方法；`acp_bridge` SSE 转换支持 `permission.requested`；`hermes_client.rs` 增加 `resolve_permission` HTTP endpoint；`routes/mod.rs` 注册路由；`layout.rs` 中 `pageAiResolvePermission` 调用后端。
- Codex 修正：incoming JSON-RPC request id 使用原始 `serde_json::Value` 保存和回写，避免字符串 id 被改成 0；allow/deny 正常路径改为参考 Hermes VSCode 插件的 `{ outcome: "selected", optionId }`，并补 `permission_response_selects_allow_and_deny_options` 测试。
- 未完成：已有 `acp_client` incoming request 基础测试和 option 选择 helper 测试，但还缺“mock ACP 发 permission -> HTTP resolve endpoint -> agent 收到 selected option”的端到端测试，故该 checklist 的 mock 闭环项保留未完成。
- 验收：`cargo test -p mnote-web acp_client -- --test-threads=1`、`cargo test -p mnote-web acp_bridge -- --test-threads=1`、`cargo test -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --test-threads=1`、`cargo test -p mnote-web acp -- --test-threads=1` 通过。
