# MindSpace 解耦 P0 边界审计 日期: 2026-07-02 分支: `codex/mindspace-decouple-20260702` 目标: - 找出当前代码中直接依赖 MindSpace 物理路径、公开 URL、agent sandbox policy、MindSpace DB 表的边界点。 - 为后续 P1 `MindSpaceService`、P2 conversation package、P3 独立进程拆分提供改造顺序。 - 本文只做审计和分层,不改变运行行为。 ## 1. 审计结论 当前 MindSpace 已经具备资产、页面、发布、agent job 的基础模型,但边界仍混在 Portal 单体里: - 物理 workspace 路径由 `user-publish.mjs`、`user-space.mjs`、`server.mjs`、`capabilities.mjs` 共同参与。 - 公开 URL 由 `user-publish.mjs`、`mindspace-assets.mjs`、`mindspace-publications.mjs`、`server.mjs` 等处生成或修正。 - Agent sandbox policy 仍以 `sandboxRoot` / `SANDBOX_ROOT` 为核心契约。 - DB 层已有 `h5_page_records.source_session_id`、`h5_page_records.source_message_id`、`h5_agent_jobs.session_id`,但 `h5_assets` 还缺 conversation provenance。 - 现有回归守卫重点保护 `public/*.html` materialize、Finish merge、用户消息内部前缀隐藏,这些路径后续改造时不能绕过。 架构判断: - P1 先抽 `MindSpaceService` 和 storage adapter 边界,不拆进程。 - P2 先落 conversation package 元数据和 manifest,不立即替换所有文件路径。 - P3 以后再把 MindSpace Service 独立进程化。 - 103/105 只作为生产部署说明,不作为开发或架构依赖。 ## 2. 物理路径边界 核心文件: | 文件 | 当前职责 | 风险 | P1 处理方式 | | --- | --- | --- | --- | | `user-publish.mjs` | `PUBLISH_ROOT_DIR = MindSpace`、用户发布目录、公开 URL helper、skill 约束文本 | URL 和路径耦合在同一层 | 保留兼容 helper,但新代码走 `MindSpaceService` URL/storage 接口 | | `user-space.mjs` | `MINDSPACE_STORAGE_ROOT`、workspace 分区、上传镜像、agent hints | workspace 和 asset storage 同时出现 | 把 storage root、workspace root 分离为 adapter 能力 | | `server.mjs` | watcher、static route、shared upload、public serving | Portal 直接掌握所有路径 | P1 先集中成 MindSpace route/service facade | | `mindspace-sandbox-mcp.mjs` | OS 层 `SANDBOX_ROOT` 文件操作 | Goose 以 raw fs path 作为契约 | P4 改成 `workspaceRef` / `packageId`,短期保留兼容 | | `capabilities.mjs` | 注入 sandbox MCP env 和 args | policy 直接依赖 `sandboxRoot` | 新增 policy adapter,避免业务层自己拼 path | 主要路径形态: ```text MindSpace//public/*.html MindSpace//oa/* data/mindspace/users//* SANDBOX_ROOT= MINDSPACE_STORAGE_ROOT= ``` ## 3. URL 权威边界 核心文件: | 文件 | 当前职责 | 风险 | P1 处理方式 | | --- | --- | --- | --- | | `user-publish.mjs` | `buildPublicUrl()`、`buildPublicZonePageUrl()` | 调用方可能把 helper 当长期权威 | 标记为 legacy compatibility,新增 canonical URL service | | `mindspace-assets.mjs` | public temp image URL | asset public URL 与 storage key 绑定 | 改成 `MindSpaceService.createPublicAssetUrl()` | | `mindspace-publications.mjs` | publication response、public URL、标准图片替换 | 发布 URL 权威分散 | publication canonical URL 统一收口 | | `server.mjs` | `/MindSpace/*` route、redirect、shared upload public URL | Express route 同时做 URL 修复和文件服务 | route 仅调用 MindSpace service facade | | `mindspace-chat-save.mjs` | 修正聊天中的 MindSpace 链接 | 后续仍需兼容旧 URL | 保留兼容,新增 canonicalize API | 短期规则: - 不删除旧 URL helper。 - 新增代码不得直接拼 `/MindSpace//...`。 - 所有新 public URL 生成必须经过 MindSpace service facade。 ## 4. Agent Policy 边界 核心文件: | 文件 | 当前职责 | 风险 | P1/P4 处理方式 | | --- | --- | --- | --- | | `capabilities.mjs` | 将 sandbox MCP 注入 Goose extension | policy 里暴露 raw path | 先增加 policy builder 边界,后续改 workspaceRef | | `mindspace-agent-runner.mjs` | agent job claim 后创建 goosed 运行上下文 | job 与 workspace/path/publish layout 混合 | job runner 改为请求 MindSpace workspace capability | | `user-space.mjs` | hints 中告诉 agent 目录和公开链接格式 | agent 直接学习物理路径 | hints 改为逻辑 workspace + 兼容说明 | | `mindspace-sandbox-mcp.mjs` | read/write/edit/create_dir | 只能处理 filesystem backend | 后续新增 MindSpace MCP bridge | 长期 policy 目标: ```json { "mindspace": { "workspaceRef": "mindspace://users//conversations/", "packageId": "cp_xxx", "apiBaseUrl": "https://mindspace.example.com", "accessToken": "scoped-short-lived-token" } } ``` ## 5. DB 和 Provenance 边界 已有基础: - `h5_assets`: asset 基础元数据,当前没有 `source_session_id`、`source_message_id`、`source_run_id`。 - `h5_asset_versions`: `storage_key` 是当前 asset 到物理存储的主要桥。 - `h5_page_records`: 已有 `source_session_id`、`source_message_id`、`source_asset_id`。 - `h5_page_versions`: 已有 `source_snapshot_json`,可承载页面生成时的上下文。 - `h5_publish_records`: 保存 `public_url`,是公开 URL 现有权威记录。 - `h5_publication_asset_refs`: publication 与 asset 引用关系。 - `h5_agent_jobs`: 已有 `session_id`、`result_page_id`、`result_asset_id`。 - `h5_agent_runs`: 已有 `agent_session_id`、`request_id`。 缺口: - 没有 conversation package 表。 - 没有 package 与 asset/page/publication/job/message 的统一 artifact 关系表。 - Asset 层没有完整对话来源,导致“这次对话生成了哪些文件”只能间接推断。 建议新增: - `h5_conversation_packages` - `h5_conversation_artifacts` 过渡策略: - 先通过 `h5_page_records.source_session_id` 和 `h5_agent_jobs.session_id` 回填页面/任务。 - 新增 asset 时尽量携带 `session_id`、`message_id`、`run_id` 到 artifact 表。 - 不急着修改旧 asset schema,优先用 junction table 降低迁移风险。 ## 6. 回归守卫 后续改这些区域前必须跑: ```bash npm run verify:mindspace-publish-guards npm run verify:mindspace-publish-guards:full ``` 重点保护: - `mindspace-public-finish-sync.mjs`: `edit_file` 必须 materialize 到 `public/*.html`。 - `chat-finish-sync.mjs`: Finish / UpdateConversation 必须 merge,禁止盲覆盖。 - `conversation-display.mjs` 和 `src/utils/message.ts`: 用户消息不得展示 routing/skill 内部前缀。 - `src/hooks/useTKMindChat.ts`: `syncSessionMessages` merge + retry。 - `server.mjs`: session snapshot 缓存必须保守。 ## 7. 第一阶段落点 P1 最小代码目标: - 新增 `MindSpaceStorageAdapter` 契约和 local fs adapter 包装层。 - 新增 canonical public URL facade。 - 新增 conversation package manifest 纯函数。 - 先不替换现有 route,不改生产行为。 P2 最小产品目标: - 为每个 chat session 懒创建 package。 - 新上传文件、生成文件、页面、发布记录写入 artifact 归属。 - H5 增加 package view。 - 历史数据 best-effort 回填。 本轮已经开始的安全基线: - 当前工作必须在 `codex/mindspace-decouple-20260702`。 - `main` 本地 pre-commit 已阻止直接提交。 - 不允许把 103 作为本地开发依赖。