edit | blame | history | raw

Phase 3.8 实现方案

日期:2026-06-26

用户目标

用户询问 Phase 3.8 最小生产切片如何实现,并要求保存会话。

已完成事项

  • 解释了 Phase 3.8 生产实现完成与 spike 完成的区别。
  • 明确真实验收前必须先实现最小生产切片,否则只能验证 spike 状态机。
  • 梳理了最小生产切片的实现路径:
  1. App 暴露 live context。
  2. App 暴露 document lease。
  3. App 暴露受控 commit result Frame。
  4. commit 后复用现有保存路径,保护 dirty 用户编辑。

关键决策

  • App 正在打开同一个 .mindraw 包时,外部工具不能直接改目录包,必须继续返回 APP_LEASE_REQUIRED
  • 最小生产切片应让 Mindraw App 成为唯一写入方。
  • 必须区分 diskRevisionworkingRevision
  • diskRevision 代表磁盘 scene。
  • workingRevision 代表 App 当前 editor snapshot。
  • dirty 文档不是绝对 No-Go;只要外部工具基于 App live workingRevision 获取 lease 并 commit,App 可以安全合并 result Frame。
  • 受控 commit 第一版只允许创建 AI result Frame,不允许任意 JSON patch。

建议实现切片

切片 1:只读 live context API

改动重点:

  • src/store/useStore.ts
  • 新增 getOpenDocumentState(documentId | packagePath)
  • 新增 getLiveFrameContext(documentId, sourceFrameId)
  • 复用 flushActiveEditorSnapshot()
  • 计算 workingRevision = sha256(active editor snapshot content)
  • src/components/ExcalidrawEditor.tsx

  • 继续复用 setActiveEditorSnapshotProvider()
  • 不在组件中直接做写入逻辑。

完成标准:

  • App 打开 .mindraw 时能返回 documentIdpackagePathisOpenisDirtyactiveTabIdworkingRevision
  • App 未打开目标文档时返回 APP_DOCUMENT_NOT_OPEN
  • dirty 文档的 workingRevision 能反映未保存编辑。

切片 2:Lease manager

建议新增:

  • src/lib/documentLease.ts

职责:

  • acquireWriteLease(input)
  • getActiveLease(documentId)
  • releaseWriteLease(leaseId)
  • expireLeases(now)
  • assertLeaseCanCommit(leaseId, expectedWorkingRevision)

必须覆盖错误码:

  • LEASE_ALREADY_HELD
  • LEASE_EXPIRED
  • LEASE_NOT_FOUND
  • WORKING_REVISION_MISMATCH

切片 3:受控 commit result Frame

建议新增:

  • src/lib/aiResultFrameMutation.ts

职责:

  • 找到 source Frame。
  • 在 source Frame 右侧创建 result Frame。
  • 在 result Frame 内创建 title / body / prompt / status 等元素。
  • 写入 customData.m4c
  • 保证 source Frame 和既有用户元素不被修改。

src/store/useStore.ts 新增 action:

  • commitAiResultFrameWithLease(input)

内部流程:

  1. flushActiveEditorSnapshot()
  2. 校验 active tab 是目标 .mindraw
  3. 计算当前 workingRevision
  4. 校验 lease 与 expectedWorkingRevision
  5. 调用 aiResultFrameMutation
  6. updateActiveTabContent(newContent, true)
  7. 调用 saveTab(activeTabId, newContent)
  8. 保存成功后释放 lease
  9. 保存失败返回 SAVE_FAILED,保留 dirty

未决问题

  • 尚未实现生产 Tauri command 或外部 MCP server。
  • 尚未接入真实外部调用入口。
  • 尚未验证多 tab、多窗口、App 后台启动、焦点切换和 UI 错误反馈。
  • Phase 4 .assets 权威资产治理仍未完成。

后续建议

下一步应按垂直切片实现:

  1. 先做 documentLease.ts 纯逻辑和测试。
  2. 再做 aiResultFrameMutation.ts 纯逻辑和测试。
  3. 再接 useStore action。
  4. 最后接最小外部触发入口,做真实 App smoke。

真实验收时,由用户在 App 中打开 .mindraw 并输入未保存文字,Codex 运行外部写入命令,双方共同确认 result Frame 出现且未保存文字不丢。