# 04.runtime_workspace 技术实施规范评审(二) **评审编号:** 02 **日期:** 2026-08-06 **评审对象:** [04.runtime_workspace.md](04.runtime_workspace.md)(产品/验收权威)、[05.technical_implementation_spec.md](05.technical_implementation_spec.md)、[06.technical_implementation_spec_review.md](06.technical_implementation_spec_review.md),以及 [运行时与智能体工具.md](../../设计/02.正式方案/运行时与智能体工具.md)、[LineUp Runtime 与 App SDK 架构方案](../../设计/02.正式方案/lineup-runtime-sdk-architecture.md)、[LineUp App 最终设计方案](../../设计/02.正式方案/app_final_design.md)。 **评审方法:** 由独立子代理只读复核当前文件,不沿用上一轮“已解决”结论;重点检查统一 activation、Agent Tool 路由、SDK session data、Runtime 原子提交,以及 Web / Tauri 是否能按同一契约实现。 **总体结论:** Pomodoro 前台语义、`activation_not_required`、通用 session data 和“先持久化、后对账”已经对齐。本轮进一步确认:Runtime 只按已验证的 App、方法、参数和当前 ready App session 做路由,不理解 MiniApp 的业务参数或直接写其数据;前台只是个别 Tool 的额外业务前提。MiniApp 通过 SDK 声明 Agent Tool 与 handler,构建时自动生成 Manifest 的不可执行 Tool 描述,开发者无需维护第二份手写 Manifest。长期 Tool 已分开协议回执 / 进度与最终业务结果;activation ready 也成为 Runtime 持久化、向 Agent 可见的进度事实,同时不把提前到达的合法调用丢给 Agent 处理。session data 已冻结 revision 0、订阅首帧、严格递增和重连对齐语义。因此 TIS2-01~TIS2-05 已解决;TIS2-06 是有明确触发条件的 P4 延续项。**本轮没有剩余 P0~P3,第 04 次技术规范可以进入实现阶段。** ## 问题清单(Outline) 状态标记:🔴 未解决,必须处理;🟡 已提出修复方向,尚未确认或未回填实施规范;✅ 已确认通过;⚪ 可延期但必须保留记录。P0~P3 必须在当前迭代处理;P4~P5 可以延期,但须记录原因与重新评估条件。 | 状态 | 优先级 | 编号 | 问题 | 证据与当前结论 / 下一步 | |---|---:|---|---|---| | ✅ | P1 | TIS2-01 | Runtime 如何在页面未前台显示时调用 MiniApp 的方法。 | **已确认并回填:** Runtime 只验证并路由 `app_scope + method + 参数`,解析或建立当前 App session 并等待 MiniApp active / ready;随后将调用投递给 MiniApp。MiniApp 自己理解方法和参数、修改 session data、返回结果。`app_ready` 不要求前台;`foreground_required` 在其上额外要求前台;`activation_not_required` 不启动 App。具体无界面执行容器是后续实现选择,不改变这条 Runtime / MiniApp 契约。 | | ✅ | P1 | TIS2-02 | MiniApp 如何声明面向 Agent 的方法,并让 Runtime 路由到正确的处理逻辑。 | **已确认并回填:** MiniApp 在 SDK 中用 `defineAgentTools(...)` 声明公开 method、schema、activation requirement 和 handler;构建自动生成 Manifest 的不可执行 Tool 描述,开发者不写第二份 Manifest。Runtime 只按已验证 Tool 路由到 ready App session 的统一 SDK 接收入口;SDK 在 Bundle 内按 method 分发本地 handler。Registry 不保存私有函数 target。 | | ✅ | P1 | TIS2-03 | 长期 `pomodoro.start` 在 `starting` / `focusing` 时的 Agent 回执与冻结 result schema 不一致。 | **已确认并回填:** `accepted / starting` 与 `started` 是持久化、可重放的协议回执 / 进度;只有 `completed`、`interrupted`、`not_started` 是符合 output schema 的唯一最终业务结果。Agent 只能在 `started` 后说“已开始计时”。同一 call_id 返回最新已持久化回执,终态后返回最终结果,不追加 outbox。 | | ✅ | P1 | TIS2-05 | Agent 如何得知 MiniApp 已启动就绪,以及是否必须等待该通知后才能发送后续调用。 | **已确认并回填:** Runtime 将 activation 的 `starting / ready / failed / cancelled` 作为与触发 call_id 关联的受控协议进度通知 Agent;Agent 收到 `activation_ready` 后再编排依赖调用是推荐方式,但不是硬门槛。Runtime 持久化并排队提前到达的 `app_ready` / `foreground_required` 调用,ready 后按顺序投递;失败 / 取消则受控拒绝。`activation_not_required` 仍立即执行。Pomodoro 的 `started` 包含 ready,不重复发 `activation_ready`。 | | ✅ | P2 | TIS2-04 | `sessionData.get()` 与 `subscribe()` 之间可能丢失一次更新,首帧与 revision 语义未冻结。 | **已确认并回填:** 空数据固定 revision 0;订阅在同一 App 子会话的串行顺序中注册并先收到当前完整快照,后续 revision 严格递增;因此读与订阅之间的 replace 要么成为首帧、要么紧随其后。重复 / 旧 revision 忽略,跳跃 / Bridge 重连重新 get 并订阅;Web / Tauri 共享 fixture。revision CAS 不做业务自动合并,TIS2-06 延续。 | | ⚪ | P4 | TIS2-06 | 多入口同时修改 session data 时,是否建立 Runtime 通用 mutation queue。 | **延续项,不属于第 04 次实现:** 当前 Pomodoro 没有修改型 UI Action,保持 `get / replace / subscribe + revision CAS` 即可。首次实现“Agent Tool 与 UI Action 都可修改同一 App 子会话”的 MiniApp(例如可手动修改的 To-do 或 Whiteboard)前,必须先冻结统一 mutation queue、操作顺序、幂等恢复与业务冲突边界;离线多端协同 / CRDT 另行设计。 | | ✅ | — | TIS2-C1 | Pomodoro 的前台即专注语义 | 前台确认后才创建 operation;仅挂载 / 预载不等于开始,失败 / 取消不产生 operation 或 IM 静态记录。 | | ✅ | — | TIS2-C2 | `pomodoro.interrupt` 不唤醒 App | `activation_not_required` 可取消已有 starting 或中断已有 focusing,但不会因停止指令新开 App。 | | ✅ | — | TIS2-C3 | session data、operation 与 IM 记录的职责边界 | session data 按 `app_scope + app_session_id` 隔离并由 MiniApp 自解释;operation / outbox 是 Runtime 事实;IM 是不可变静态结果。 | | ✅ | — | TIS2-C4 | 原子提交和三条入口 | Runtime 先持久化 operation、activation、session data、workspace、receipt / outbox,再让 Lifecycle / Host / Surface 对账;Agent Tool、UI Action、Host 生命周期意图不混同。 | ## 本轮已通过的边界 ### TIS2-C1:Pomodoro 只有进入前台才真正开始 `pomodoro.start` 被接受后,Runtime 可以创建 instance、App 子会话和 `starting` activation;但 Host 必须明确确认该 instance 已成为用户当前看到的前台 App,Runtime 才创建 `focusing` operation 与 `ends_at`。iframe 创建、资源加载或后台预载都不是这个确认。最终激活失败、启动中取消或用户在启动中离开,都表示“本次计时未开始”,不产生 `operation_id`、deadline、专注中断记录或专注 IM 静态记录。 ### TIS2-C2:停止指令不会反而打开 Pomodoro `pomodoro.interrupt` 只查询调用所在 conversation 已有的 `starting` 或 `focusing` Pomodoro:前者取消启动,后者中断 operation;两者都不会为这条停止指令创建 instance、Surface 或前台焦点。 ### TIS2-C3:通用 session data 不泄露 Runtime 业务事实 SDK 从不可伪造的 context 推导 `app_scope + app_session_id`,MiniApp 只能读取和替换自己的 JSON 数据字典。Pomodoro 可自行组织活动、显示信息、current 或 history;Runtime 不识别这些字段,也不直接向字典写 Pomodoro 私有业务数据。deadline、终态竞争、Tool receipt、outbox 和恢复继续属于 Runtime operation;一次完成后写入 Interact / IM 的记录是独立的不可变静态副本。 ### TIS2-C4:持久化仍先于 Host 副作用 `RuntimeOperationCommitCoordinator` 的职责没有被 activation 新模型削弱:持久化失败时 activation、operation、session data、workspace、receipt、outbox、Lifecycle 和 Surface 均保持旧状态;持久化成功后 Host / Surface 对账失败时,Runtime 从已保存事实恢复或重试,不能倒写或伪造终态。 ## TIS2-01:Runtime 如何调用未前台显示的 MiniApp 方法 **已解决(2026-08-06,收敛决议)。** 此前问题错误地把重点放在“后台执行容器究竟是 Worker、iframe 还是别的实现”。用户已明确 Runtime 的架构职责: 它接收 Agent Tool 后只根据 schema 验证调用结构,找到 `app_scope` 下的 method 与参数,确认目标 MiniApp 当前 session 是否 active / ready,然后把调用路由给 MiniApp。Runtime 不理解参数字段和数值的业务意义,也不直接写 MiniApp 的数据;MiniApp 才知道 `todo.add` 表示新增待办,并自行通过 session data 完成业务修改。 ```text Agent Tool Call → Runtime:验证 Tool、schema、scope、幂等 → Runtime:解析或建立目标 App session,等待 MiniApp ready → Runtime:投递 method + 已验证参数 → MiniApp:理解业务、修改自己的 session data、返回结果 → Runtime:验证、持久化 receipt / result,并回传 Agent ``` 三个 activation requirement 的意义随之明确: ```text app_ready = MiniApp 已 active / ready,Runtime 可路由方法调用;不要求前台 = 未来 todo.add foreground_required = app_ready,且 Host 已确认 MiniApp 成为当前前台 = pomodoro.start;前台是“开始专注”的业务前提 activation_not_required = 不为这次调用启动或唤醒 MiniApp,只操作已有 Runtime 事实 = pomodoro.interrupt ``` 运行中但不在前台的 MiniApp 如何落到具体 Host 容器,是后续实现层的选择;它不得改变上述统一的 Runtime 路由、 MiniApp 业务处理与 SDK 回传契约。本轮不再把“Runtime 是否直接写 To-do 数据”或“是否前台”误当作这个问题。 Runtime 同时会把 activation 的受控状态回传给触发启动的 Agent:`accepted / starting`、`activation_ready`,或 `activation_failed / activation_cancelled`。这条通知帮助 Agent 在需要时顺序编排后续调用,但 Runtime 不把正确性 交给 Agent:如果合法的 `app_ready` / `foreground_required` 调用在 ready 前已经到达,它会被持久化到同一 activation 等待队列,ready 后按顺序投递;`activation_not_required` 则保持立即执行。 ## TIS2-02:SDK 声明 Agent Tool,构建自动生成 Manifest **已解决(2026-08-06,收敛决议)。** MiniApp Manifest 的 Tool 区块仍是 Runtime 安装、Registry、Inventory 和 Agent 调用所依赖的能力说明书;但它不应是 开发者手写和维护的第二份图纸。每个 MiniApp 在自身代码中通过 SDK 的 `defineAgentTools(...)` 声明公开 Tool、 输入 / 输出 schema、activation requirement 和 `miniapp_sdk` Tool 的本地 handler。构建阶段从该声明自动生成 Manifest 的不可执行 Tool 投影,并与 Bundle 一同校验、签名和安装。 ```text MiniApp 源码中的 SDK Tool 声明 ├── 供 TypeScript 校验 handler、输入和输出 ├── 供 Bundle 内 SDK 建立 method → handler 本地映射 └── 构建自动生成 Manifest tools 描述 → Runtime 安装时验证并投影 Registry → Runtime 发布 Agent Inventory ``` 运行时对普通 MiniApp Tool 的路径固定为: ```text Agent 调用 app_scope + method + params → Runtime 按生成 Manifest 校验、定位 ready App session → Runtime 投递到该 session 的统一 SDK Tool 接收入口 → SDK 按 method 调用 Bundle 内已声明 handler → MiniApp 处理业务、写 session data、返回受控结果 ``` Runtime 不保存、更不调用 MiniApp 私有函数 target;Manifest 不包含函数、URL、回调或其他可执行内容。`delivery = miniapp_sdk` 表示上述固定入口;`delivery = runtime` 才使用 Runtime 内部 handler key,例如第 04 次 Pomodoro 的 deadline / interrupt 可靠性操作。构建必须拒绝重复 method、非法 schema、miniapp_sdk Tool 缺少 handler 或 handler 与 schema 不匹配;runtime Tool 则必须匹配 Runtime 内置的受控 execution。 ## TIS2-03:长期 Tool 的协议 receipt 与业务 result 分层 **已解决(2026-08-06,收敛决议)。** `pomodoro.start` 的业务 result schema 只允许最终业务结果:已完成、已中断或未开始。同一个 call_id 在 `starting` 或 `focusing` 时不能伪造终态,也不能把 activation / operation 对象塞进业务 result。因此这条调用固定分成两层: ```text Tool protocol receipt / progress = accepted / starting:Runtime 已收到请求,正在把 Pomodoro 打开到前台 = started:Host 已确认前台,Runtime 已创建 operation,计时真实开始 = 对 Agent 只包含 call_id、app_scope、受控状态,以及 started 后必要的时间事实 = 不属于 Tool 的业务 result_schema;每个阶段各自只写一次可重试 outbox Tool business result = 已完成、已中断、未开始等业务终态 = 必须符合 Manifest result_schema = 每次 Tool Call 只持久化并回传一次 ``` 首次 start 与开始成功的原子提交分别写 `accepted / starting` 和 `started` 协议消息。相同 call_id 在 `starting` / `focusing` 时返回已持久化的最新协议回执;仅在进入 completed、interrupted 或 not_started 后返回已持久化的业务 result。`accepted` 只表示 Runtime 接到请求,不代表 Agent 可以对用户说“已开始计时”;真正开始仍以 Host 前台确认和 operation 创建为准。 ## TIS2-05:activation ready 如何通知 Agent、提前调用由谁负责 **已解决(2026-08-06,收敛决议)。** 所有 MiniApp 都有 `starting → ready | failed | cancelled` activation。Runtime 在持久化状态变化后,通过与原启动 call_id 关联的 protocol receipt / progress 向 Agent 发出 `accepted / starting`、`activation_ready` 或 `activation_failed / activation_cancelled`;MiniApp、Surface 与 Host 都不得直接通知 Agent。通知只携带 call_id、 app_scope、状态和受控失败原因,不能把 instance / App 子会话变成 Agent 可指定的控制目标。 Agent 在收到 `activation_ready` 后再发送依赖该 App 的后续指令,是推荐的编排方式,但不是请求能否接收的硬门槛。 Runtime 自己持久化并排队在 ready 前到达的合法 `app_ready` / `foreground_required` Tool,ready 后按到达顺序投递; 若启动失败或取消,Runtime 不执行业务 handler,而为每个等待调用回传稳定错误。`activation_not_required` 保持立即处理, 因而启动中的 `pomodoro.interrupt` 可以直接取消当前启动。Pomodoro 的 `started` 同时表达 activation ready、前台确认与 operation 已开始,故不额外向 Agent 发送重复的 `activation_ready`。 ## TIS2-06:通用 mutation queue 与多入口协作写入 **优先级:P4(延续项,不在第 04 次迭代实现)。** To-do 若只展示数据、所有修改都经 Agent Tool 进入,实际上天然只有一个业务写入来源;画板若同时允许 Agent Tool 和用户 UI Action 修改同一份 session data,则需要 Runtime 为同一个 `app_scope + app_session_id` 建立统一、持久化、 幂等的 mutation queue,避免两个来源各自基于旧 JSON 快照整体覆盖。该机制应让 Agent Tool、UI Action 与受控 Runtime 动作都以“业务操作”而非完整 JSON 快照进入同一顺序,再由 MiniApp 在最新数据上实现自己的业务效果。 这个方向是通用 Runtime 能力,不应要求开发者预先选择“单点 / 协作”模式;实际有哪些写入入口,是 MiniApp 已经 声明的 Tool / UI Action 自然决定的。但实现它会同时引入写入 handler 上下文、队列持久化与重启恢复、UI Action 写入 协议、顺序 / 幂等规则,以及未来离线多人协作与 CRDT / OT 的清晰边界。第 04 次只验证没有修改型 UI Action 的 Pomodoro,不能为此提前扩大范围。 本迭代继续使用通用 `sdk.sessionData.get / replace / subscribe` 与 revision CAS;CAS 只防止旧版本覆盖,不承诺 自动合并业务冲突。**重新评估触发条件:** 在开始任何一个“Agent Tool 与 UI Action 都能修改同一 App 子会话”的 功能之前,例如手动编辑 To-do 或 Whiteboard 的首个交互式绘制流程,必须先将本项提升为该迭代的 P1 并完成设计。 ## TIS2-04:session data 首帧与 revision 同步窗口 **已解决(2026-08-06,收敛决议)。** 本项只处理 Surface 读取自身 session data 时的版本同步,不处理 Agent 与 UI 同时修改数据的业务合并;后者已作为 TIS2-06 的 P4 延续项。若 Surface 先 `get()`、再 `subscribe()`,两次调用之间发生的 replace 不能被遗漏。第 04 次 冻结以下最小且跨 Host 一致的规则: ```text 不存在 session data → get() 返回 { data: null, revision: 0 } subscribe(listener) → 在同一 app_scope + app_session_id 串行顺序中注册 → 注册后先投递当前完整 { data, revision } → 之后投递 revision 严格递增的 session_data.changed ``` 因此,若 replace 在注册前提交,首帧就是新 revision;若注册先完成,则新 revision 作为后续事件抵达。SDK 收到重复或 旧 revision 时忽略;若发现 revision 跳跃或 Bridge 重连,取消旧订阅、重新 `get()` 并建立新的订阅。Web / Tauri 共享 golden fixture,且必须测试“get(revision 3) 与 subscribe 之间发生 replace(revision 4)”以及反向注册顺序的场景。 `expected_revision` 冲突只返回稳定错误 `session_data_revision_conflict`,第 04 次不自动合并 JSON。 ## 本轮关闭条件 1. TIS2-01~TIS2-05 已回填主迭代定义、实施规范与正式方案;TIS2-06 是已记录的 P4 延续项,在其重新评估触发条件出现前不阻塞第 04 次验收。 2. 第 04 次进入实现后,必须以本文件和实施规范的 Web / Tauri fixture、单元测试、构建与代表性 Host 流程验证这些决议;实现完成后进行下一轮独立验收评审。