Files
app/迭代/04.runtime_workspace/01.design_review.md
T

15 KiB
Raw Blame History

04.runtime_workspace 设计评审(一)

评审编号: 01 日期: 2026-08-06 评审对象: 04.runtime_workspace.md03.sdk_and_coreapp.md01.kernel.md00.base.mdplan.mdAPP架构设计.md 评审方法: 对照既有 Runtime 所有权、SDK v1、Tool、生命周期、App 子会话和 Web/Tauri Host 契约,检查第 04 次迭代是否引入相互矛盾或无法按既有边界实现的设定。 总体结论: 第 04 次迭代对 MiniApp 隔离、Interact 标准交互、关闭收口和 Host 基线的方向与第 03 次迭代及权威架构一致。Pomodoro 已收敛为 Agent 直接启动的单次专注 operationRuntime 托管 instance state、deadline 和唯一结果;Pomodoro 只渲染与请求退出。D04-01~D04-05 已回填主定义或总体计划,所有 P0~P3 设计问题已清零;D04-06 是有明确触发条件的 P5 遗留项,不阻塞实施。

问题清单(Outline

状态标记:🔴 未解决,必须处理;🟡 已提出修复方向,尚未确认或落入主定义; 已解决; 可延期但必须保留记录。P0~P3 必须在当前迭代处理;P4~P5 可以延期,但必须记录延期原因和重新评估条件。

状态 优先级 编号 问题 当前结论 / 下一步
P1 D04-01 Pomodoro 状态由 Runtime 保存,但 Runtime 又“不解释番茄钟业务”;SDK v1 没有对应的私有状态持久化/恢复契约 Runtime 已在正式方案中定义按 app_scope + instance_id 隔离、Manifest schema 校验、revision 控制的业务状态快照;04 已明确 operation 与 instance state 的不同事实来源和最小数据。
P1 D04-02 用户暂停/继续/取消与 Agent Tool 的关系未定义;现有 sdk.tools.* 只能终结 Runtime 已投递的 Agent Tool 已收敛为 Agent Tool pomodoro.start(长操作)和 pomodoro.interrupt(短操作);不支持暂停/继续。用户以语言请求停止时由 Agent 调用 interrupt;切换/关闭由 Runtime 生命周期以相同规则中断,均不伪造 Agent Tool。
P1 D04-03 “后台继续计时、到点回传、重启按 ends_at 恢复”没有 Runtime deadline 裁决和 Tool 终态规则 已确定 Runtime deadline operation 是唯一裁决者:持久化 ends_at,到点/中断竞争一个原子终态,唯一 result/outbox;重启已到点结算一次,进程未运行时不承诺即时提醒。
P2 D04-04 “创建或恢复 App 子会话”与“新 instance 必须新子会话”、以及关闭后 pending Interact 问题仍可回答的既有规则未完整写出 已明确仅恢复同一个未结束 instance 才复用子会话;关闭后子会话只读,pending Interact 问题留在主 IM 等待且不得追加到旧子会话;验收已加入该场景。
P3 D04-05 总体计划把 Pomodoro 写成第 03 次迭代已完成的参考 MiniApp,并要求第 04 次工作区可切换 Whiteboard;第 04 次定义却将 Pomodoro 作为新验证应用且只承诺 Interact/Pomodoro 切换 已更新 plan.md:第 03 次参考实现只含 Task Dashboard / WhiteboardPomodoro 在第 04 次引入。Whiteboard 本轮仅保持第 03 次回归,不接入工作区切换或完成范围。
P5 D04-06 未来是否将 SDK 的实现迁入 Rust 层以提升运行效率 延期讨论: 当前没有性能瓶颈证据,且 Web Reference Host / sandbox iframe 中的 SDK 与 UI Bridge 必须保留 TypeScript/浏览器侧实现。未来可评估把状态存储、schema 校验、deadline 调度、Tool/outbox 原子收口等无 UI Runtime Core 下沉到 Rust。重新评估触发:profiling 证明这些路径是热点,或 Rust Runtime Core 成为跨 Host 的正式实现边界。

通过项

  • 信任与隔离没有倒退。 第 04 次迭代将 Pomodoro 定为 bundled,要求受限 Surface/SDK,禁止访问 Transport、Store、Agent、Host DOM、Tauri 和系统能力。这与权威架构对 bundled MiniApp 的限制一致,也避免了第 03 次验收已修复的“业务逻辑回到可信 Host JS”问题。
  • Interact 的归属正确。 notice / choice / confirm / input 仍由 Interact 呈现;Pomodoro 前台时仅允许 Interact 覆盖层,视觉位置不改变 owner。这符合既有“标准交互不属于 MiniApp SDK”的规则。
  • 关闭收口正确。 文档保留“停止新普通 Tool 投递 → 未终态 Tool 收敛为 cancelled(app_closed) → 已 submitted 结果继续 outbox → 恢复有效前台 App”的顺序;也没有把 Tool 完成错误地等同于关闭 App。
  • Host 范围正确。 Web Reference Host 与 Tauri Desktop Host 作为同一 Runtime/MiniApp 代码的两种 Host 验收,与权威架构一致。

D04-01:状态所有权与持久化边界未定义

已解决(2026-08-06)。 正式方案已增加 app.instance-state.v1Runtime 为当前 app_scope + instance_id 托管 Manifest schema 校验、revision 控制和 lifecycle 清理的业务状态快照。 本迭代已将 Pomodoro 的 instance snapshot 与 deadline operation 分开:前者服务 UI 恢复,后者是 ends_at、Tool 终态和 outbox 的唯一事实来源。以下为发现时的风险分析。

第 04 次定义要求 Runtime“保存计时状态和工作区快照”,并要求 Pomodoro 根据 Runtime 状态刷新;同时又规定 Runtime 不解释番茄钟业务,Pomodoro 负责暂停、继续和取消。它给出的 timer_idduration_secondsstarted_atends_atremaining_secondsstate 正是需要跨刷新和重启持久化的业务状态。

但既有 SDK v1 只开放 Inbox、Agent Tool 的 progress / complete / fail / cancel、生命周期、Surface 与 Capability。它不提供 MiniApp 私有状态的读取、schema 校验写入、版本迁移或恢复快照 API;并且 Runtime 是 Conversation Store 的唯一所有者,bundled iframe 不能直接写它。若不补契约,实现只能在两条均违反边界的路径中选择:由 Runtime 写死 Pomodoro 的字段/状态机,或由 MiniApp 自己绕过 SDK 访问持久化。

建议把 Runtime 的职责限定为通用的、按 instance 隔离的持久化容器和 deadline-operation 调度,而非理解“番茄钟”。Pomodoro Manifest 应声明其状态 schema 和可恢复 operation schemaMiniApp 通过一个最小、受 Runtime 校验的 SDK 请求提交状态变更;Runtime 负责原子持久化、恢复投影和审计元数据。主定义还应说明:remaining_seconds 是派生展示值,还是暂停时的持久化事实值,避免与 ends_at 双事实源冲突。

D04-02:用户控制动作没有合法的 SDK 入口

已解决(2026-08-06,后续澄清)。 Pomodoro 接受 Agent 的长期 Tool pomodoro.start 和短 Tool pomodoro.interrupt;用户不再有暂停或继续入口。用户以 IM / Voice 表达“停止/结束这次专注”时,由 Agent 调用 pomodoro.interrupt({});Runtime 只从该调用所在会话绑定当前 focusing instance,负责路由与唯一终态 裁决。切换工作区和关闭则由 Runtime 生命周期以同一中断规则处理,但不伪造 Agent Tool。Runtime 只接受第一 次有效中断;重复/迟到调用只返回稳定回执,不能改写终态或直接写第二条 outbox。以下为发现时的备选分析。

第 04 次迭代要求用户在 Pomodoro 内暂停、继续、取消;又列出 pomodoro.start / pause / resume / cancel / status。前置契约中,sdk.tools.* 表示 MiniApp 对 Runtime 已投递的 Agent Tool Call 报告进度或唯一终态,不能被用于任意用户动作,更不能由 bundled MiniApp 自行构造 Agent call 或写 outbox。

因此必须先选择并写清一个模型:

  1. pomodoro.pause / resume / cancel / status 都是 Agent 可调用 Tool,用户点击只请求 Runtime 执行相同的已声明 MiniApp command;或
  2. 只有 pomodoro.start 是长操作 Tool,用户动作是独立的实例内 command,不会伪造额外 Agent Tool,Runtime 可按产品协议选择是否产生状态事件;或
  3. 另一种明确的、同样受 Manifest、schema、instance 和幂等校验约束的模型。

无论选择哪种,需给出 command ID、输入/输出 schema、目标 instance_id、重复点击行为、状态非法时的稳定拒绝码,以及关闭竞态下命令被拒绝还是已持久化。否则 Web/Tauri 两个 Host 会分别把按钮实现为局部状态或直接 Tool 操作,无法证明 Runtime 的唯一所有权。

D04-03:后台/重启到点完成缺少唯一裁决者

已解决(2026-08-06)。 Runtime 的通用 deadline operation 持久化绝对 ends_at;到点、用户中断和 关闭竞争同一原子终态,先成功者产生唯一 Tool result/outbox。自动暗屏、锁屏和 Surface 重载不终止专注; 重启发现已到点时只结算一次。Runtime / Host 完全未运行时不承诺即时提醒。以下为发现时的风险分析。

“后台继续运行”在受限 iframe 不等于存在可靠的定时器:Surface 可能卸载、浏览器页面可能被节流,进程也可能在 deadline 前后重启。仅在 UI 中 setTimeout 会导致漏完成、重复完成或把全时长重新开始。第 04 次虽然正确要求重启按 ends_at 计算剩余时间,却没有定义 Runtime 在何时把 operation 原子转为 completed、谁完成关联 Tool、以及同时发生暂停、取消、App close、恢复和 deadline 时谁胜出。

建议新增一个通用 Runtime deadline-operation 状态机。运行中的 operation 持久化绝对 ends_at;恢复时 Runtime 用当前时间重新计算,若已到期则以一次原子转换完成并写唯一 result/outbox,若未到期则投影更新。暂停把剩余时长固化并清除/失效 deadline;恢复从新的 deadline 开始。接受 AppLifecycleManager.close 时,先让关闭取得与 operation 完成相同的终态竞争权:先完成者生效,另一个仅收到稳定幂等回执。这样 Runtime 仍不需要知道“番茄钟”,只实现可复用的 deadline 可靠性。

还须明确第一版“App 内完成提示”的含义:它应由 MiniApp 在收到 Runtime 已完成状态时显示;系统通知仍不在范围内。若运行进程完全不存在,到点时不承诺即时可见提示,但下次 Runtime/Host 可运行时必须按已到期状态恢复,不能重置或重复回传。

D04-04:子会话复用、只读与关闭后问题的措辞不完整

已解决(2026-08-06)。 主定义已限定:只有恢复同一个未结束 instance 才能复用子会话;关闭后子会话 只读。仍 pending 的 Interact 标准交互保留在主 IM 中等待回答、dismiss、超时或 Runtime 失败,且不得向 已结束子会话追加记录。以下为发现时的风险分析。

前置契约只允许在“恢复同一个未结束 instance”时复用同一个 App 子会话;以后启动的每个新 instance 都必须新建子会话。第 04 次的“创建或恢复 App 子会话”没有限定这一前提,容易被实现为按 app_scope 或旧子会话复用,和“继续处理新建 instance / 新子会话”冲突。

另外,既有规则规定 App 真正关闭后:子会话结束并成为只读历史,仍 pending 的标准交互不被取消,留在 Interact/主 IM 中等待回答、dismiss、超时或 Runtime 失败。第 04 次仅说“已结束子会话只读”,没有写出这个例外;若把回答追加进已关闭子会话,就破坏只读,若关闭时取消问题,又违反 Interact 归属规则。

建议在第 04 次的子会话章节和验收中逐字继承这一关闭后路径,并加一条自动化场景:Pomodoro 关闭时存在带 app_session_context 的 pending choice,App 覆盖层消失、子会话只读、用户仍可在主 IM 回答,且产生一次结果/outbox。

D04-05:计划与第 04 次最小范围相互矛盾

已解决(2026-08-06)。 总体计划已将 Pomodoro 从第 03 次已完成参考实现中移除,明确它在第 04 次 作为 Agent 直接启动的专注验证应用引入;Whiteboard 在本轮仅保持第 03 次已有回归,不参与工作区切换、 完整闭环或完成验收。以下为发现时的风险分析。

plan.md 说第 03 次已完成的参考 MiniApp 包含 Pomodoro,但第 03 次主定义及其验收对象是 Interact、Task Dashboard 和 Whiteboard;第 04 次又明确把 Pomodoro 选为本轮验证应用。与此同时,计划要求第 04 次工作区支持 Interact、Pomodoro、Whiteboard 切换,而第 04 次主定义只承诺 Interact/Pomodoro。

这不会改变底层架构,却会直接导致实现范围、浏览器验收用例和“第一条完整用户流程”的判断不一致。建议以第 04 次主定义选择的“单一 Pomodoro 闭环”为基准:将计划中的“Pomodoro 已完成参考实现”改成“Pomodoro 在第 04 次引入”;对白板明确标注为本轮仅保持既有回归,或若确实要求可切换则把它加入第 04 次工作内容、验收和时间预算。

D04-06SDK 是否迁入 Rust 层(P5,后续讨论)

这是值得保留的性能和实现演进方向,但当前没有证据表明它阻塞第 04 次迭代。需要先分清 SDK 的 协议/能力语义和 SDK 的运行位置:协议必须跨 Host 保持一致,具体实现不必全部使用同一种语言。

必须留在 TypeScript / 浏览器侧的部分
→ Web Reference Host、bundled MiniApp 的 sandbox iframe、postMessage Surface Bridge、DOM 与 UI 渲染。

适合未来评估迁入 Rust 的 Runtime Core 部分
→ 状态快照持久化、schema 校验、revision 比较、deadline operation 调度、Tool/outbox 原子终态、
  生命周期收口和审计。

如果把全部 SDK 都迁入 Rustbundled MiniApp 仍必须经浏览器 Bridge 调用 Runtime,反而可能增加 Tauri IPC、序列化和跨语言错误处理开销;它不能替代 Web Reference Host 中必须运行的 TypeScript Bridge。 因此候选方向是“保持版本化 SDK 契约与 TypeScript Surface API,按需把 Runtime 的无 UI 核心实现下沉到 Rust”, 而不是把 MiniApp SDK 整体替换为 Rust。

重新评估前必须先有可重复的 profiling 证据,包括:状态快照读写频率与耗时、deadline/Tool 路由吞吐、主线程 阻塞、Tauri IPC 往返、JSON 序列化成本以及 Web/Tauri 两个 Host 的差异。只有收益大于跨 Host 实现、测试、 调试和错误边界的复杂度时,才为此创建独立设计和迁移迭代。

设计就绪条件

D04-01D04-05 已形成决议并回填到 04.runtime_workspace.mdplan.md。所有 P0~P3 设计问题已清零;D04-06 作为 P5 carryover 保留,不阻塞本迭代。