# 7-30 [done][bug] 单个 mnote.block 写工具未强制 selection scope

> 发现时间：2026-05-18
>
> 状态：`[done]`
>
> 关联主线：`07-ai`

## 1. 问题定义

`mnote.doc.apply_block_ops` 已经通过 `allowedTargetBlockIds` 限制 AI selection 范围内的结构性写入，但单个 `mnote.block.replace` / `mnote.block.insert_after` / `mnote.block.delete` / `mnote.block.move_after` 写工具没有同等服务端兜底。

这会导致模型或 ACP 调用者在 `scope=selection` 场景下，绕过批量工具直接调用单块写工具时，仍可能改到 selection 外的块。

## 2. 证据

- [block.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/block.rs) 的 `doc_apply_block_ops()` 对每个操作调用 `ensure_allowed_target()`。
- [block.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/block.rs) 的单个 block 写工具当前只校验 revision / editable / precondition，缺少同等 `allowedTargetBlockIds` 校验。
- [7-10](/mnt/Data1T/mnote/design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md:70) 已标注“单个 `mnote.block.*` 写工具尚未完成 `allowedTargetBlockIds` 矩阵”。

## 3. 影响

- AI 页面 selection 编辑边界不完整。
- `markdown_edit` 和 `apply_block_ops` 已拒绝越界写入，但单块工具仍可能成为绕过路径。
- ACP / Hermes tool guidance 即使要求 selection 内写入，也缺少 runtime 级强约束。

## 4. 修复结果

- [block.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/block.rs) 已为 `mnote.block.replace`、`mnote.block.insert_after`、`mnote.block.delete`、`mnote.block.move_after` 增加统一 `allowedTargetBlockIds` 服务端校验。
- `move_after` 同时校验被移动块和 anchor 块，避免 selection 内块被移动到 selection 外 anchor 后。
- [manifest.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/manifest.rs) 已在单块写工具 schema 中公开 `allowedTargetBlockIds`。
- [hermes_tools.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_tools.rs) 已增加回归测试，覆盖单块写工具越界时返回 `mnote_block_target_out_of_scope`。

## 5. 验证证据

```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web block_tools_selection_scope -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_block -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_manifest -- --nocapture
cargo fmt --manifest-path rust/Cargo.toml --all -- --check
```

验证结果：

- RED：修复前 `block_tools_selection_scope` 失败，越界单块写工具返回 `200`。
- GREEN：修复后 `block_tools_selection_scope` 通过：`2 passed`。
- `hermes_tools_block` 通过：`6 passed`。
- `hermes_tools_manifest` 通过：`3 passed`。
