- wire SQLite control-plane access/session paths into Rust web local-folder routes - preserve local Markdown attachment semantics across upload, reload, and secondary-pane resource tabs - refresh design governance docs, Reasonix task templates, and bug records - retire root .mcp.json local MCP config
11 KiB
11 KiB
7-16 [done] Page Block AI 真实页面 Smoke 后续矩阵 v1
创建时间:2026-05-18
当前状态:
DONE归档说明(2026-05-21):本文范围内可执行的真实页面 smoke 已完成;剩余 UI / Review Mode 属于 Phase C 冻结范围,解冻时应新建设计稿承接。
来源:
/mnt/Data1T/mnote/design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md/mnt/Data1T/mnote/design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md/mnt/Data1T/mnote/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md
1. 目的
7-10 已完成大量工具合同、Rust route 测试和部分真实 3000 smoke,但仍有一组“必须真实页面验证”的矩阵项未完成。
本文只承接这些剩余 smoke,不新增 AI 功能面,不改变当前主路径:
- local-first 普通 Markdown 编辑主路径仍是“授权文件引用 + agent 原生 patch/diff + watcher 同步”;本文只验证 mnote tools 的历史结构性辅助和兼容证据。
- 2026-05-22 之后,
mnote.doc.markdown_edit不再作为 local-first 默认、fallback 或 remote fallback;本文中的 smoke 只代表历史在线 / compat 回归证据。 mnote.block.*仍只作为结构性辅助。mnote.page.save仍只作为页面级粗粒度兜底。- Phase C review / streaming apply 仍冻结,当前只验证基础合同和安全边界。
2. 当前已具备的前置证据
mnote.doc.fetch scope=selection format=page_xml/text、mnote.block.fetch format=page_xml/text、manifest annotations、mnote.doc.apply_block_ops allowedTargetBlockIds越界阻断已有真实 3000 smoke:tmp/page-block-ai-context-format-smoke/mp8ddr4n.jsontmp/page-block-ai-context-format-smoke/mp8ddr4n-page.png
mnote.block.replacestale revision / stale blockRevisionRef / idempotency replay 已有真实 3000 smoke:scripts/task-page-block-ai-conflict-idempotency-smoke.js- 证据记录在
08的 Page Block AI Tooling 章节。
mnote.block.insert_after多块插入和 20 个边界已有 Rust route 回归:cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_block_insert_after -- --nocapture
mnote.block.move_after复杂块阻断矩阵已有隔离 route smoke:cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_block_move_after_blocks_complex_and_nested_blocks -- --nocapture
3. 后续真实页面 Smoke 矩阵
3.1 Page Aggregate Block Projection
- 登录测试账号并创建综合页面
TEST-AI-BLOCK-TOOLS-<timestamp>。 - 写入段落、标题、todo、列表、mindmap/resource 占位。
- 调
/api/page-aggregate/:id并保存响应到tmp/hermes-tester/page-block-ai-tools-<run-id>/page-aggregate.json。 - 断言所有普通可编辑块有
blockId和revisionRef。 - 页面刷新后 block ids 不变化。
- projection 中
blockCount与页面块数量一致;复杂块返回editable=false与unsupportedReason。
证据(2026-05-18):
- JSON:
tmp/page-block-ai-tools-smoke/mpag4966.json - Page Aggregate:
tmp/hermes-tester/page-block-ai-tools-mpag4966/page-aggregate.json - 覆盖:Page Aggregate
blockProjectionVersion=1、projectionSource=documents.content、aggregateBlockCount=10,与mnote.doc.fetch块顺序一致;刷新后afterRefreshBlockIds保持最终顺序;table_1/mindmap_1/resource_1返回editable=false与unsupportedReason=复杂块暂不开放 AI 精确写入。
3.2 mnote.doc.fetch / mnote.doc.find
- 使用综合页面
TEST-AI-BLOCK-TOOLS-<timestamp>。 mnote.doc.fetch scope=full detail=with_ids读取整页。mnote.doc.fetch scope=outline detail=with_ids只返回标题结构。mnote.doc.find query=<唯一前缀>定位目标段落。- 保存工具返回到
tmp/hermes-tester/page-block-ai-tools-<run-id>/doc-fetch-find.json。 - 确认读取不依赖浏览器 DOM。
doc.find返回的 block id 能被block.fetch读取。- 大页面默认分块或限制输出,不默认返回无限正文。
证据(2026-05-18):
- 命令:
PLAYWRIGHT_CHROME_EXECUTABLE=/snap/bin/chromium MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-tools-smoke.js - JSON:
tmp/page-block-ai-tools-smoke/mpag4966.json - 工具返回:
tmp/hermes-tester/page-block-ai-tools-mpag4966/doc-fetch-find.json - 覆盖:
doc.fetch.initial读取heading_1/p_1/p_2/p_3等 10 个块;doc.fetch scope=outline只返回heading_1/heading_parent;doc.find query="第二段 <suffix>"定位p_2;maxBlocks=2返回truncated=true。 - 静态边界:
mnote.doc.fetch从 Page Aggregate block projection 构建上下文,不读取浏览器 DOM;默认maxBlocks=120且 clamp 到1..=240。
3.3 mnote.block.fetch
- 从
doc.find结果选择一个段落 block。 - 调
mnote.block.fetch includeChildren=true contextBefore=1 contextAfter=1。 - 断言 before/after 只来自同父级。
revisionRef可被后续 dry-run 使用。- 复杂块不会伪装成完全可编辑。
证据(2026-05-18):
- JSON:
tmp/page-block-ai-tools-smoke/mpag4966.json - 覆盖:
block.fetch读取p_2,返回revisionRef=pageRev:1:block:p_2:...,同父级before=["p_1"]、after=["p_3"];table_1/mindmap_1/resource_1均返回editable=false与unsupportedReason=复杂块暂不开放 AI 精确写入。
3.4 mnote.doc.plan_update / dry-run
command=str_replace不再作为当前plan_update目标;普通正文 search/replace 已由mnote.doc.markdown_edit合同承接。- 对目标段落执行
block_replace dryRun=true。 - 对目标段落执行
block_insert_after dryRun=true。 - 对两个同父级普通块执行
block_move_after dryRun=true。 - dry-run 前后分别读取
/api/page-aggregate/:id与mnote.doc.fetch,确认 revision / conflictDetectionKey / 正文文本不变。 - dry-run 不写 Convex。
- plan 能解释 before/after。
- 不支持场景返回
blocked=true。
证据(2026-05-18):
- JSON:
tmp/page-block-ai-tools-smoke/mpag4966.json - 覆盖:
plan_update.dry_run.replaceDiff.before/after、insertDiff.after/content、不支持move_after p_3 -> p_3返回blocked=true、dry-run 后revisionAfterDryRun=1且正文未变化。
3.5 mnote.block.replace
- 使用综合页面
TEST-AI-BLOCK-TOOLS-<timestamp>。 - 写入两段不同文本。
doc.find找到第二段 block id。block.replace dryRun=true查看 plan。block.replace dryRun=false替换第二段。- 页面截图和工具回读证明只替换第二段。
/api/page-aggregate/:id回读证明持久化。mnote.doc.fetch再次证明 AI 可读回。- 相邻块不变化。
- 目标 block id 保持不变。
- 旧 revision 写入返回 conflict。
证据(2026-05-18):
- JSON:
tmp/page-block-ai-tools-smoke/mpag4966.json - 截图:
tmp/page-block-ai-tools-smoke/mpag4966-page.png - 覆盖:
block.replace.changedBlocks[0]={blockId:"p_2",op:"replace"},targetBlockStillExists=true,adjacentTexts=["第一段 mpag4966","第三段 mpag4966"],mnote.doc.fetch与 Page Aggregate 均回读到第二段已替换 mpag4966,Page AggregateaggregateRevision=2、aggregateConflictDetectionKey=tree_1779062903017_3:2。 - 冲突 / 幂等补充 JSON:
tmp/page-block-ai-conflict-idempotency-smoke/mpafrevs.json,截图:tmp/page-block-ai-conflict-idempotency-smoke/mpafrevs-page.png。 - 覆盖:首次
block.replace写入p_2后,重复idempotencyKey=idem_conflict_replace_mpafrevsreplay 同一commandId=page_body_save_req_1779062303997_525且revisionAfterFirst=2、revisionAfterReplay=2;旧revision/conflictDetectionKey与旧blockRevisionRef均返回 HTTP400/mnote_tool_conflict,最终文本保持第二段首次替换 mpafrevs。
3.6 mnote.block.insert_after
- 使用综合页面
TEST-AI-BLOCK-TOOLS-<timestamp>。 - 在第一段后插入 todo。
- 截图证明位置准确。
- 刷新页面后再次确认。
mnote.block.fetch能读取新 block id。- 插入位置准确。
- 新 block id 不是 AI 自造未校验 id。
- 重复同一
idempotencyKey不重复插入。
证据(2026-05-18):
- 命令:
PLAYWRIGHT_CHROME_EXECUTABLE=/snap/bin/chromium MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-tools-smoke.js - JSON:
tmp/page-block-ai-tools-smoke/mpag4966.json - 截图:
tmp/page-block-ai-tools-smoke/mpag4966-page.png - 说明:该 smoke 使用
TEST-AI-BLOCK-TOOLS-*综合页面,不是单独TEST-AI-BLOCK-INSERT-*页面;已覆盖 todo 插入、插入后顺序、block.fetch 回读、刷新后可见和重复 idempotencyKey replay。
3.7 mnote.block.move_after
- 使用综合页面
TEST-AI-BLOCK-TOOLS-<timestamp>,包含三段普通段落。 - dry-run 移动第三段到第一段后。
- 正式执行同父级移动。
- 截图证明顺序为第一段、第三段、第二段。
mnote.doc.fetch回读顺序一致。- 对标题带子块、列表项、表格、mindmap 执行 move dry-run,必须返回 blocked。
- moving block id 保持不变。
- 同父级顺序正确。
- 复杂块不被误移动。
证据(2026-05-18):
- JSON:
tmp/page-block-ai-tools-smoke/mpag4966.json - 截图:
tmp/page-block-ai-tools-smoke/mpag4966-page.png - 覆盖:
heading_parent/list_item_1/table_1/mindmap_1/resource_1的plan_update block_move_after dryRun=true与正式mnote.block.move_after dryRun=false均返回blocked=true/block_move_after_blocked,阻断后revisionAfterBlocked=1且正文不变化;普通p_3 -> p_1正式移动后顺序为heading_1,p_1,p_3,ai_block_...,p_2,...,movingBlockStillExists=true。
3.8 UI / Review Mode 边界
- Hermes tool event UI 展示
plan/diff/warnings/risk。 - 本地 preview/suggestion 与持久 comment/tracked-change 分开。
- 协作可见审阅必须另走正式 comment/history/tracked-change 设计。
- 用户能看到 AI 将改哪个 block。
blocked=true的工具调用不会出现写入按钮。- preview 不写入正式 comment/history。
4. 验证原则
- 所有真实页面 smoke 必须使用测试账号,优先从
http://localhost:3000/auth快速登录。 - 证据必须保留 JSON 和截图,默认放入
tmp/hermes-tester/<run-id>/或专项tmp/page-block-ai-*目录。 - 发现失败时按 owner 写入
bugs/<category>/process/,不要只在本矩阵中留描述。 - 不用此矩阵扩展新 AI 功能;只补真实页面证据和安全边界。