# 3-22 [done][bug] ACP permission 自动拒绝后 UI 仍展示审批动作

> 发现时间：2026-05-18
>
> 状态：`[done]`
>
> 关联主线：`03-rust-web` / ACP runtime 与页面 AI 事件映射

## 1. 问题定义

当前 ACP client 收到 `session/request_permission` 后会立即返回 JSON-RPC error，并把事件转换为 `permission.denied`。这是为了避免 agent 等待权限响应直到超时。

但页面 AI UI 仍在权限卡片和权限弹窗里展示“允许 / 拒绝”按钮。即使这些按钮在 `permission.denied` 下会被禁用，用户仍会看到审批入口，误以为可以把真实协议结果改成允许。

## 2. 证据

- [acp_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_client.rs:350) 对 incoming `id + method` request 直接返回 JSON-RPC error。
- [acp_session_manager.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_session_manager.rs:121) 对 `session/request_permission` 生成 `decision="denied"`。
- [acp_bridge.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_bridge.rs:237) 将 decision 映射为 `permission.denied`。
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:4060) 权限弹窗仍渲染“允许 / 拒绝”按钮。
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:5805) 权限消息卡片仍渲染“允许 / 拒绝”按钮。

## 3. 影响

- 用户看到的“允许”动作与 ACP wire contract 不一致。
- 点击动作只修改本地 UI 状态，不会回写 ACP JSON-RPC response。
- 对已经自动拒绝的权限请求展示审批按钮，会掩盖真实失败原因。

## 4. 修复

- [acp_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_client.rs:350) 维持 `session/request_permission` 自动拒绝协议响应，避免 agent 等待超时。
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:4003) `pageAiApplyPermissionEvent()` 对 `permission.denied` / `permission.allowed` 只保留结果态，不再展示可点击审批弹窗。
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:4048) `pageAiShowPermissionDialog()` 对已决权限事件直接隐藏对话框。
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:5797) 权限消息卡片对已决事件只展示结果，不再渲染审批按钮。

## 5. 验证

```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web acp_permission_request_emits_frontend_decision_event -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web ssr::pages::layout::tests -- --nocapture
cargo fmt --manifest-path rust/Cargo.toml --all -- --check
git diff --check -- rust/crates/mnote-web/src/ssr/pages/layout.rs bugs/03-rust-web/done/3-22-acp-permission-auto-deny-ui-shows-approval-actions-v1.md
```

结果：

- `page_ai_uses_backend_acp_session_runtime_store`：`1 passed`。
- `acp_permission_request_emits_frontend_decision_event`：`1 passed`。
- 版面相关静态测试继续通过，权限消息代码路径未破坏。
