Update P2 Plan

This commit is contained in:
2026-06-16 20:26:23 +08:00
parent 4b09ce3096
commit 2d91675ceb
7 changed files with 352 additions and 1 deletions

View File

@@ -2246,3 +2246,10 @@
- 影响范围:`server-rs/crates/spacetime-module/src/editor_project_storage.rs``server-rs/crates/spacetime-client/src/editor_project.rs``server-rs/crates/api-server/src/editor_project.rs``src/services/image-editor/editorProjectClient.ts``src/components/image-editor/ImageCanvasEditorView.tsx`、后端数据契约文档和图片画布前端技术方案。
- 验证方式:`npm run spacetime:generate -- --rust-only``npm run test -- src/components/image-editor/ImageCanvasEditorView.test.tsx src/services/image-editor/editorProjectClient.test.ts``npm run typecheck``npm run check:spacetime-schema``npm run check:encoding``cargo check -p spacetime-client -p api-server --manifest-path server-rs/Cargo.toml``git diff --check`
- 关联文档:`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md``docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`
## 2026-06-16 Editor Agent P2 先补持久任务再接 SandboxRuntime
- 背景:`/editor/agent` P1 已用 Mock Agent 跑通 snapshot、patch、runner、artifact 和独立 preview后续讨论需要支持 Docker sandbox、Shell 和开源 coding agent但这些能力都依赖可靠的任务生命周期、日志恢复、取消和崩溃恢复。
- 决策P2 不直接跳到长驻 Docker 工作区或 Shell而是先新增 `web_project_runtime_job`、worker / lease / controller、日志分页和 SSE 重连,再抽象 `SandboxRuntime`。第一版 SandboxRuntime 可继续复用当前 temp-dir runnerDocker / gVisor / Kata / microVM 作为后续执行面实现snapshot 仍是唯一事实源sandbox diff 必须转为 `WebProjectPatch` 并经过 api-server 校验后落库。
- 影响范围:`docs/planning/【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md``docs/technical/【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md``docs/technical/【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md`、Web Project runtime job 后续实现。
- 验证方式P2 落地时需覆盖 runtime job 状态机、worker claim / renew / complete / fail、failed / cancelled / expired / stale 不覆盖 active preview、日志分页 / SSE 重连、真实浏览器 happy path 和破坏构建保留上一版预览。

View File

@@ -21,7 +21,7 @@
微信小程序虚拟支付接入、`wechat_mp_virtual` 渠道、`wx.requestVirtualPayment` 承接页和后端签名配置见 [【技术方案】微信虚拟支付接入-2026-05-26.md](./%E3%80%90%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88%E3%80%91%E5%BE%AE%E4%BF%A1%E8%99%9A%E6%8B%9F%E6%94%AF%E4%BB%98%E6%8E%A5%E5%85%A5-2026-05-26.md)。
`/editor/agent` 浏览器内 AI Web 工程编辑器的静态 SPA 沙箱预览 MVP采用“平台编辑器壳 + api-server 控制面 + 独立 runner worker + 独立预览域”四层结构;技术方案、威胁模型和验收清单见 [【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md](./technical/【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md)、[【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md](./technical/【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md) 和 [【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md](./technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md)。P1 先用确定性 mock Agent 生成结构化 patch、真实打通项目 / 快照 / 构建 / artifact / 预览闭环,落地拆分见 [【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md](./technical/【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md),可执行开发计划见 [【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md](./planning/【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md)。
`/editor/agent` 浏览器内 AI Web 工程编辑器的静态 SPA 沙箱预览 MVP采用“平台编辑器壳 + api-server 控制面 + 独立 runner worker + 独立预览域”四层结构;技术方案、威胁模型和验收清单见 [【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md](./technical/【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md)、[【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md](./technical/【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md) 和 [【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md](./technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md)。P1 先用确定性 mock Agent 生成结构化 patch、真实打通项目 / 快照 / 构建 / artifact / 预览闭环,落地拆分见 [【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md](./technical/【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md),可执行开发计划见 [【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md](./planning/【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md)。P2 先补持久 runtime job、worker / lease、日志恢复和 SandboxRuntime 抽象,计划见 [【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md](./planning/【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md)。
`/editor/canvas` 图片画布编辑器的画布素材 ZIP 导出能力,入口放在右上角标题栏下载图标内,第一版采用前端 JSZip 打包画布中有效图层引用的上传图、生成图和修改结果,方案见 [【前端架构】图片画布素材导出方案-2026-06-15.md](./technical/【前端架构】图片画布素材导出方案-2026-06-15.md)。

View File

@@ -6,6 +6,7 @@
- [【玩法创作】创作流程统一总计划-2026-05-30.md](./【玩法创作】创作流程统一总计划-2026-05-30.md):创作入口、统一创作页、统一生成页、结果页、发布、作品架、广场和运行态的阶段计划、进度记录、并行波次和可直接派发的任务包。
- [【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md](./【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md)`/editor/agent` Mock Agent P1 的可执行波次、任务包、验收门禁和覆盖矩阵,完整承接技术落地计划。
- [【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md](./【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md)`/editor/agent` P2 的持久 runtime job、worker / lease、日志恢复和 SandboxRuntime 抽象计划。
## 维护规则

View File

@@ -638,4 +638,6 @@ P2 优先接:
- [ ] 构建日志分页与可重连 SSE。
- [ ] 真实 Agent 接入,但继续产出同一结构化 patch。
P2 的可执行拆分已经单独沉淀到 [【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md](./【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md)。后续应先按该计划补 runtime job / worker / lease再接 Docker sandbox、Shell 或真实 coding agent避免跳过任务生命周期基础设施。
真实 Agent 接入前不得扩大 P1 的执行权限任意依赖安装、HMR、dev server 和作品化发布必须进入后续独立评审。

View File

@@ -0,0 +1,337 @@
# Editor Agent P2 持久任务与 SandboxRuntime 计划
更新时间:`2026-06-16`
## 计划定位
本文承接 `/editor/agent` Mock Agent P1。P1 已经跑通“用户输入 -> 结构化 patch -> snapshot -> runner 构建 -> artifact -> 独立 preview”的最小闭环P2 的目标不是先做更聪明的 AI也不是直接开放 Shell而是把 P1 的一次性构建升级为可恢复、可取消、可审计的后台任务系统,并为后续 Docker sandbox、Shell 和真实 coding agent 留出稳定接口。
一句话:
```text
P2 先把执行任务做可靠,再把执行环境逐步替换成更强沙箱。
```
## 当前基线
P1 当前形态:
```text
前端 /editor/agent
-> Mock Agent 返回 WebProjectPatch
-> api-server 校验 patch
-> 保存 WebProjectSnapshot
-> 创建 preview build
-> api-server 触发一次性 web-project-runner
-> runner 临时展开 snapshot 构建
-> 写入 immutable artifact
-> preview gateway 签发 previewUrl
```
当前工作区关系:
- `snapshot` 是事实源,保存在 SpacetimeDB。
- runner 构建时创建一次性临时目录,构建完成后删除。
- artifact root 只保存构建产物,不作为用户工作区。
- Agent 通过结构化 patch 连接工作区,不直接读写本机文件,也不执行 Shell。
## P2 目标
- 新增 Web Project 专用持久任务模型,支撑 preview build、后续 sandbox 命令和同步任务。
- 将 preview build 从“请求内触发一次性 runner”迁移到 `api-server -> job -> worker` 模式。
- 支持任务取消、stale、expired、runner crash 恢复。
- 持久化构建日志,支持分页读取和 SSE 断线重连。
- 抽象 `SandboxRuntime` 接口,为后续 Docker / gVisor / Kata / microVM 工作区替换留口。
- 保持 snapshot 作为唯一事实源sandbox 文件变化必须通过 diff / patch 校验后保存为新 snapshot。
## P2 非目标
P2 明确不做:
- 不开放用户或 Agent 的交互式 Shell。
- 不允许 Agent 直接执行宿主机命令。
- 不开放任意 npm 依赖、用户 registry、用户 lockfile 或自定义 build script。
- 不做 HMR、长驻 dev server、WebSocket 端口代理。
- 不做 Web project 作品化发布。
- 不把 Docker workspace 直接提升为事实源。
- 不把真实 coding agent 深度绑定到宿主文件系统。
这些能力进入后续阶段前必须单独补安全模型、验收清单和资源隔离方案。
## Snapshot 与 Sandbox 的关系
P2 继续保持以下关系:
```text
snapshot = 项目版本化事实源
sandbox = 某个 snapshot 展开后的隔离执行环境
```
标准流转:
```text
读取 active snapshot
-> hydrate 到 sandbox workspace
-> 在 sandbox 中 build / test / 后续 shell
-> 收集 sandbox diff
-> 转成 WebProjectPatch
-> api-server 校验 patch
-> 保存新 snapshot
```
因此 P2 的第一步不是先做长驻 Docker workspace而是先做能管理执行生命周期的持久 job。没有 job / worker / leasesandbox 会缺少创建、回收、取消、超时、崩溃恢复和日志恢复的基础设施。
## 总体执行顺序
| 波次 | 主题 | 目标 |
| --- | --- | --- |
| P2a | 持久任务表与状态机 | 新增 `web_project_runtime_job`,固化状态、日志和 owner 校验 |
| P2b | Worker / lease / controller | 让任务由 worker 领取、续租、完成、失败和过期重领 |
| P2c | Preview build 迁移 | 将 P1 preview build 接到 runtime job保留现有 runner 和 artifact 语义 |
| P2d | SandboxRuntime 抽象 | 定义执行环境接口,第一版可用当前 temp-dir runner 实现 |
| P2e | 日志和恢复 | 日志分页、SSE 重连、刷新恢复、取消和 stale 验收 |
| P2f | 文档与门禁 | 更新架构文档、验收清单和 smoke 流程 |
## P2a持久任务表与状态机
新增 SpacetimeDB 表建议:
```text
web_project_runtime_job
web_project_runtime_job_log
```
`web_project_runtime_job` 建议字段:
- `job_id`
- `project_id`
- `snapshot_id`
- `owner_user_id`
- `job_kind`P2 先支持 `preview_build`
- `status``queued | running | succeeded | failed | cancelled | expired | stale`
- `attempt`
- `worker_id`
- `lease_token`
- `lease_expires_at`
- `cancel_requested_at`
- `stale_reason`
- `artifact_id`
- `preview_build_id`
- `error_summary`
- `created_at`
- `started_at`
- `finished_at`
- `updated_at`
`web_project_runtime_job_log` 建议字段:
- `log_id`
- `job_id`
- `project_id`
- `owner_user_id`
- `sequence`
- `level`
- `message`
- `created_at`
状态机规则:
- `queued` 只能被 worker claim 为 `running`,或被用户取消为 `cancelled`
- `running` 只能由持有当前 `worker_id + lease_token` 的 worker 完成、失败或续租。
- lease 过期的 `running` 可以被重新 claim`attempt` 递增。
- 新 snapshot 创建后,旧 snapshot 的未终态 preview job 标记为 `stale` 或保持旧日志但不得推进 active preview。
- `succeeded` 只有在 `snapshot_id == project.active_snapshot_id` 时才能推进 active preview。
- `failed / cancelled / expired / stale` 永远不能覆盖上一版成功 preview。
## P2bWorker / Lease / Controller
新增 Web Project runtime worker 角色,避免把 Web 工程构建塞进 `external_generation_job`
建议职责:
- `api-server`:鉴权、创建 job、读取状态、取消任务、SSE / 日志查询。
- `web-project-runtime-worker`claim job、hydrate snapshot、调用 runner、写日志、回写状态。
- `web-project-runtime-controller`:后续按队列压力管理 worker 数量P2 本地可先手动或随 `api-server` 开发态启动。
worker claim 规则:
- 只领取 `queued` 或 lease 已过期的 `running`
- claim 时写入 `worker_id`、新的 `lease_token``lease_expires_at``started_at``attempt`
- renew / complete / fail 必须带同一个 `worker_id + lease_token`
- SpacetimeDB 事务使用数据库时间判断 lease不信任 worker 本机绝对时间。
## P2cPreview Build 迁移
P2 不推翻 P1 runner而是把触发方式迁移为持久 job
```text
POST /api/runtime/web-project/projects/{projectId}/preview-builds
-> 创建 web_project_preview_build
-> 创建 web_project_runtime_job(kind=preview_build)
-> worker claim job
-> worker 调 web-project-runner
-> 写 artifact / preview token / previewUrl
-> 成功时推进 active preview
```
兼容要求:
- 前端仍通过现有 preview build API 创建构建。
- SSE 事件类型保持 P1 口径,底层事件来源改为 runtime job log / status。
- preview URL 仍由后端返回,前端不拼接。
- preview gateway 的独立 origin、CSP、CORS 和 iframe `sandbox="allow-scripts"` 保持不变。
## P2dSandboxRuntime 抽象
P2 应先抽象接口,不急于直接开放 Docker Shell。
建议接口:
```text
SandboxRuntime
createWorkspace(projectId, snapshotId)
hydrateSnapshot(workspaceId, snapshot)
runBuild(workspaceId, jobContext)
execCommand(workspaceId, commandSpec)
collectDiff(workspaceId)
destroyWorkspace(workspaceId)
```
第一版实现:
- `TempDirBuildRuntime`:复用 P1 runner 的一次性临时目录构建。
后续实现:
- `DockerSandboxRuntime`:每个 project/session 独立容器或 volume。
- `GVisorSandboxRuntime` / `KataSandboxRuntime` / `MicroVmSandboxRuntime`:生产安全要求提高后替换。
接口边界:
- sandbox 不持有平台密钥、用户 cookie、SpacetimeDB 直连 token 或 OSS 写权限。
- sandbox 只能访问当前项目 workspace。
- sandbox 文件变化不能直接落库,必须转成 patch 后走现有校验。
- sandbox 网络默认 deny后续如需 npm mirror 必须走白名单。
## P2e日志、取消与恢复
日志要求:
- worker 写入持久日志表。
- API 支持按 `jobId + cursor/sequence` 分页读取日志。
- SSE 断线后,前端先读取 job 状态和缺失日志,再重新订阅。
- 日志限长、脱敏,不能包含平台 token、完整宿主路径和环境变量 dump。
取消要求:
- 用户取消时写 `cancel_requested_at` 并把未开始 job 标为 `cancelled`
- running job 由 worker 检测取消请求后停止 runner 并回写 `cancelled`
- P2 若暂不支持强杀子进程,也必须明确返回“取消请求已记录 / 等待 runner 收敛”的状态。
刷新恢复要求:
- 打开 `/editor/agent?projectId=...` 后读取 project、active snapshot、active preview 和未终态 jobs。
- 前端不会因为旧 job 成功覆盖新 snapshot 的 preview。
- 页面刷新后日志和 build 状态以后端为准。
## 真实 Agent 与 Shell 的后续接入
P2 可以为真实 Agent 预留工具接口,但不默认接真实 coding agent。
推荐后续形态:
```text
Agent service
-> sandbox file/shell tools
-> WebProjectPatch
-> api-server 校验
-> snapshot
```
如果后续改编 Codex、opencode 等开源 coding agent
- Agent 不能直接以宿主仓库为 cwd。
- 读写文件工具必须指向 sandbox workspace 或 Sandbox FS API。
- shell tool 必须通过 runtime job 在 sandbox worker 中执行。
- agent 修改后的文件 diff 必须转成 `WebProjectPatch` 并校验后保存。
## 验收场景
P2 最小验收:
1. 打开 `/editor/agent`,创建或恢复 Web Project。
2. 输入“做一个蓝色计数按钮页面”。
3. 后端创建 `web_project_runtime_job(kind=preview_build)`
4. worker claim job 并写入 running 日志。
5. runner 构建成功job 进入 `succeeded`
6. preview URL 可访问iframe 切到成功预览。
7. 输入“破坏构建”,新 job 进入 `failed`
8. 上一版成功 preview 保留。
9. 连续提交两次,旧 job 不覆盖新 snapshot preview。
10. 刷新页面后恢复 project、active snapshot、active preview、job 状态和日志。
11. 取消 queued job 后状态为 `cancelled`
12. 模拟 worker crash / lease 过期后任务可重领或进入确定失败 / expired 状态。
## 验证命令
涉及 schema
```bash
npm run spacetime:generate
npm run check:spacetime-schema
```
后端:
```bash
cargo test -p spacetime-module web_project --manifest-path server-rs/Cargo.toml
cargo test -p spacetime-client web_project --manifest-path server-rs/Cargo.toml
cargo test -p api-server web_project --manifest-path server-rs/Cargo.toml
cargo test -p web-project-runner --manifest-path server-rs/Cargo.toml
cargo check -p api-server --manifest-path server-rs/Cargo.toml
```
前端:
```bash
npm run test -- src/services/web-project src/components/editor/agent --reporter verbose
npm run typecheck
npm run check:encoding
git diff --check
```
浏览器 smoke
```text
打开 /editor/agent
提交计数按钮指令
等待 runtime job succeeded
确认 iframe 预览和按钮点击
提交破坏构建
确认 failed job 不覆盖上一版 preview
刷新页面确认状态和日志恢复
```
## 风险与处理
| 风险 | 处理 |
| --- | --- |
| 直接先做 Docker workspace 导致生命周期失控 | 先做 runtime job / worker / lease再接 SandboxRuntime |
| sandbox 文件成为第二事实源 | snapshot 仍为事实源sandbox diff 必须转 patch 并校验 |
| 真实 Agent 绕过 patch 校验 | Agent 只产出 patch 或工具结果,保存仍走 api-server 校验 |
| 旧 job 成功覆盖新 preview | 成功推进 active preview 必须校验 active snapshot |
| worker crash 后 job 永久 running | lease 过期可重领或标记 expired |
| 日志丢失导致刷新不可恢复 | 日志进入持久表SSE 只做实时补充 |
| 把 Web 工程任务塞进 external_generation_job | 使用 Web Project 专用 runtime job避免语义污染 |
## 完成定义
P2 完成必须满足:
- `web_project_runtime_job` 和日志持久化落地。
- preview build 已由 runtime worker 执行。
- lease / claim / renew / complete / fail / expired 基础流转可测。
- failed / cancelled / expired / stale 不覆盖 active preview。
- 日志分页和 SSE 重连可恢复。
- P1 的真实浏览器 happy path 和破坏构建保留预览继续通过。
- `SandboxRuntime` 接口已形成,后续 Docker / Shell / coding agent 不需要推翻 P1/P2 控制面。

View File

@@ -527,4 +527,6 @@ P1 完成后进入 P2 时,优先补:
- 构建日志分页与可重连 SSE。
- 真实 Agent 接入,但继续产出同一结构化 patch。
P2 的执行计划见 [../planning/【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md](../planning/【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md)。该计划明确 P2 先补持久任务、worker / lease 和日志恢复,并提前抽象 SandboxRuntimeDocker sandbox、Shell 和开源 coding agent 改编应作为后续执行面接入,不应绕过 snapshot / patch / preview 控制面。
真实 Agent 接入前不得扩大 P1 的执行权限任意依赖安装、HMR、dev server 和作品化发布必须进入后续独立评审。

View File

@@ -338,6 +338,8 @@ draft snapshot
引入 `web_project_runtime_job`,按 lease / controller / worker 模式实现任务队列、取消、stale、刷新恢复和日志 SSE。
Phase 2 的可执行计划见 [../planning/【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md](../planning/【开发计划】EditorAgentP2持久任务与SandboxRuntime计划-2026-06-16.md)。执行顺序以“runtime job / worker / lease 先行SandboxRuntime 抽象随后接入”为准Docker 工作区、Shell 和真实 coding agent 都应挂在该任务系统之后。
### Phase 3受控依赖安装
支持白名单依赖、lockfile 固化、依赖层缓存、安装失败可读错误、依赖封禁和审计。