Files
mnote/bugs/04-tree-domain/done/4-42-tree-move-live-delta-sort-order-ignored-v1.md
T
lix-2026 f292c6710a feat: EditorRuntimeActor - 三层缓存/delta/事件架构
Phase A — EditorRuntimeActor 内存缓存层
- 新增 editor_actor.rs: EditorBlockDocument 内存态 + apply_command + load_or_init
- block.rs 四个写工具(replace/insert/delete/move)接入 actor 路径
- editor_actor feature flag(MNOTE_WEB_ENABLE_EDITOR_ACTOR=true 默认开启)
- bridge-runtime 三个核心函数公开化
- rust-toolchain: 1.89 → stable(修复 spike WASM 编译阻塞)

Phase B — 编辑器增量 delta channel
- BlockDelta/DeltaOperation 类型 + actor.build_block_delta()
- leptos-tiptap spike: mnote:editor:block-delta CustomEvent 监听 + JSON patch
- DocumentAiAgentPanel: 拦截 blockDelta → window dispatchEvent
- 工具响应含 blockDelta 字段供前端消费

Phase C — 事件 stream delta
- broadcast channel 在 AppState/actor/SSE 三层贯通
- tree_events SSE 端点发 block.delta 事件
- 旧客户端降级兼容

环境修复
- rustc recursion_limit = 1024(修复 Leptos SSR 类型深度溢出)
- run-convex-deploy.js(封装 Convex function 部署到本地后端 3210)

ref: design/07-ai/process/7-13-page-block-editor-runtime-actor-v1.md
2026-05-16 22:03:30 +08:00

3.9 KiB
Raw Blame History

4-42 [done][bug] tree move live delta sortOrder 被 SSR shell 忽略 v1

更新时间:2026-05-16

分类归属:

  • 04-tree-domain/done

关联文档:

  • /mnt/Data1T/mnote/design/10-review/process/08-kernel-architecture-next-priority-review-and-checklist.md
  • /mnt/Data1T/mnote/design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md

1. 问题定义

/api/tree/eventstree:delta move_document 已携带 sortOrder,但 Rust SSR 文档 shell 在 B 端应用 live delta 时只移动到目标父节点末尾,没有按 sortOrder 重排直系子节点。

真实双浏览器 RED smoke

MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task447-tree-move-order-dual-browser-live-smoke.js

失败证据:

  • tmp/tree-live-cache-smoke/20260516-task447-move-order/result.json
  • RED fixture:同父级初始顺序 A/B/CA 端执行 move C -> parent=root, sortOrder=1,预期 B 端顺序 A/C/B
  • RED 结果:B 端收到 tree:deltaop=move_documentsortOrder=1liveApplied=deltaliveError="",但 Page Tree / File Tree DOM 顺序仍保持 A/B/C,直到 waitForExpectedOrder 超时。

2. 根因

rust/crates/mnote-web/src/ssr/pages/layout.rs 中:

  • applyMoveDocumentDelta(data) 只读取 documentIdparentId,未读取 sortOrder
  • moveDocumentRowForMode(mode, documentId, parentId) 无排序参数,最终固定 targetContainer.appendChild(node)
  • tree:local-command 的 optimistic move 分支也只传 { documentId, parentId },会在本地命令成功后先把节点放到末尾。

事件生成链路不是根因:tree.subtree.move command payload、domain event streamDelta/api/tree/events delta 均已携带 sortOrder=1

3. 修复

rust/crates/mnote-web/src/ssr/pages/layout.rs 已补齐:

  • sortOrderFromDelta(data):兼容读取 sortOrder / sort_order
  • insertTreeNodeAtSortOrder(targetContainer, node, sortOrder):按目标父节点直系 .tree-node sibling index 插入,缺少排序时保持 append 行为。
  • moveDocumentRowForMode(mode, documentId, parentId, sortOrder):消费排序参数。
  • applyMoveDocumentDelta(data):把同一 sortOrder 同步应用到 Page Tree 与 File Tree。
  • tree:local-command move 分支:把 body.sortOrder 传入 applyMoveDocumentDelta

同时补充字符串合同测试,防止后续再次丢失排序消费。

4. 验证

已通过:

node --check scripts/task447-tree-move-order-dual-browser-live-smoke.js
cargo test --manifest-path rust/Cargo.toml -p mnote-web sidebar_tree_runtime_handles_navigation_drag_and_filetree_actions -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command_move_returns_structured_payload -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command_response_includes_rust_artifact_plan_for_domain_event -- --nocapture
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task447-tree-move-order-dual-browser-live-smoke.js

GREEN smoke 证据:

  • tmp/tree-live-cache-smoke/20260516-task447-move-order/result.json
  • tmp/tree-live-cache-smoke/20260516-task447-move-order/b-document-after-move.png
  • tmp/tree-live-cache-smoke/20260516-task447-move-order/b-filetree-after-move.png

验证结果:

  • B 文档页和 B File Tree 页面均收到 /api/tree/events
  • tree:delta move_document payload 含 sortOrder=1
  • B 文档页 Page Tree / File Tree direct child order 均为 A/C/B
  • B File Tree 页面 Page Tree / File Tree direct child order 均为 A/C/B
  • move 后 navigationEvents=[],确认没有通过刷新或跳转掩盖 live order 更新。

5. 状态

当前状态:done

该缺陷已在真实代码中修复,并通过 Rust 合同测试与真实 3000 双浏览器 smoke 验证。