7.3 KiB
7.3 KiB
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/*.htmlmaterialize、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 |
主要路径形态:
MindSpace/<userId>/public/*.html
MindSpace/<userId>/oa/*
data/mindspace/users/<userId>/*
SANDBOX_ROOT=<absolute workspace path>
MINDSPACE_STORAGE_ROOT=<absolute storage path>
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/<userId>/...。 - 所有新 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 目标:
{
"mindspace": {
"workspaceRef": "mindspace://users/<userId>/conversations/<sessionId>",
"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_packagesh5_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. 回归守卫
后续改这些区域前必须跑:
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:syncSessionMessagesmerge + 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 作为本地开发依赖。