Files
memind/docs/memind-control-execution-split-plan-20260702.md
T
2026-07-27 15:34:35 +08:00

26 KiB
Raw Blame History

Memind / MindSpace / Goose 解耦推进方案

日期: 2026-07-02

适用目标:

  • 把 MindSpace 从 Memind Portal 单体中拆出来,成为可以独立部署、独立扩容、独立迁移存储的服务。
  • Memind 继续负责产品入口、用户会话、聊天体验、套餐/能力编排和业务路由。
  • Goose 继续负责 agent 执行,但不直接拥有 MindSpace 状态,也不把某台机器的文件路径当作长期契约。
  • 每次对话生成或上传的图片、文件、页面、公开链接等,都要形成一个可浏览、可迁移、可打包的 conversation package。

本文只描述架构目标、边界和推进计划,不要求一次性完成所有代码拆分。

0. 结论

应该拆,但不要按“105 = Control Portal103 = Execution Portal”的机器绑定方式拆。

正确目标是服务边界:

Memind App
  - H5 / 服务号 / 认证入口 / 用户会话
  - 聊天 UI 和产品业务编排
  - 套餐、能力、计费、请求整形
  - 不拼接 MindSpace 物理路径
  - 不假设 MindSpace 部署在哪台机器

MindSpace Service
  - space / asset / page / publication / conversation package
  - canonical URL 生成和 public backing file 校验
  - 存储适配器: local fs / NAS / S3 / 其它对象存储
  - 权限、审计、manifest、元数据和实际文件一致性
  - 可以独立部署在任意位置

Goose Runtime
  - agent session / tool execution / long running job
  - 通过 MindSpace API 或 MindSpace MCP 读写文件
  - 不直接拥有 MindSpace 元数据
  - 不把本地 `MindSpace/<userId>` 路径作为产品级契约

103/105 只能作为当前生产部署拓扑的一个例子。103 是生产,不是本地开发依赖,也不应该成为 MindSpace 独立化后的架构前提。

硬性规则:

  1. MindSpace 的真实存储位置必须可替换,本地开发、NAS、S3 都应该只是 storage adapter。
  2. Memind 不得根据 userId、slug、fileName 自己拼接 MindSpace public URL。
  3. Goose 不得直接写业务数据库里的 MindSpace 状态,只能通过 MindSpace API/MCP 能力写入。
  4. MindSpace Service 是 asset/page/publication/package 元数据和 canonical URL 的唯一权威。
  5. 每个用户对话产生的文件必须归属到一个 conversation package,不能只散落在物理目录里。
  6. 物理目录结构不是外部契约;外部契约应该是 package id、asset id、page id、publication id 和 canonical URL。

1. 当前现状

当前 /Users/john/Project/Memind 更接近一个运行态 Portal 单体:

  • server.mjs 同时承载 H5 API、用户认证、MindSpace API、文件/发布服务、agent session proxy、Agent job worker、workspace watcher、微信/Plaza 等。
  • Goose 是执行后端,Portal 通过 TKMIND_API_TARGETS / TKMIND_API_TARGET 调它。
  • MindSpace 有两类本地状态:
    • workspace/public 文件: MindSpace/<userId>/...
    • asset/page/publication 存储: data/mindspace/users/...
  • MySQL/RDS 保存用户、资产、页面、发布、任务、会话、计费、Plaza/微信等业务状态。
  • h5_page_records 已有 source_session_idsource_message_idh5_agent_jobs 也有 session_id,说明页面和任务已经部分具备对话来源线索。
  • h5_assets 这类底层文件资产还没有完整的 conversation package 归属模型。

现在最危险的隐含假设不是 HTTP 能不能转发,而是代码里把“某台机器上的路径”和“产品里的 MindSpace 文件”混成了同一个概念。未来 MindSpace 可以在本机、NAS、S3 或独立服务中,Memind 和 Goose 都不能依赖这层物理细节。

2. 目标架构

flowchart LR
  U["Browser / WeChat"] --> M["Memind App"]
  M --> MS["MindSpace Service"]
  M --> AG["Agent Gateway"]
  AG --> G["Goose Runtime"]
  G --> MCP["MindSpace MCP / API"]
  MCP --> MS
  MS --> DB["Metadata DB"]
  MS --> ST["Storage Adapter"]
  ST --> LFS["Local FS"]
  ST --> NAS["NAS"]
  ST --> S3["S3 / Object Storage"]

核心变化:

  • Memind App 面向用户,不面向物理文件系统。
  • MindSpace Service 面向文件、页面、发布、包和存储后端。
  • Goose Runtime 面向执行,不面向 MindSpace 业务所有权。
  • Storage Adapter 面向字节和对象,不面向用户、会话、页面这些业务概念。

3. 服务边界

3.1 Memind App

Memind App 负责:

  • H5 静态入口和聊天体验。
  • 服务号 webhook、菜单、客服入口。
  • 用户登录、session、cookie/header 规范化。
  • 套餐、能力、计费和业务策略。
  • 把用户请求转成 MindSpace API、Agent Gateway API 调用。
  • 展示 MindSpace 返回的 URL、JSON、SSE、HTML 状态。

Memind App 禁止:

  • 拼接 MindSpace/<userId>/public/*.html
  • 直接读写 MindSpace/data/mindspace/
  • 根据文件名猜测 public URL。
  • 自己判断 public backing file 是否存在。
  • 把具体机器路径传给前端当长期 API。

3.2 MindSpace Service

MindSpace Service 负责:

  • Space、category、asset、asset version、page、page version、publication。
  • Conversation package 和 package manifest。
  • Canonical public URL 生成。
  • Public backing file 存在性校验。
  • 文件上传、下载、预览、缩略图、长图、HTML 页面落盘。
  • 存储适配器封装: local fs、NAS、S3、其它对象存储。
  • 权限校验、审计、配额和一致性修复。

MindSpace Service 应该提供稳定 API:

/api/mindspace/v1/spaces
/api/mindspace/v1/assets
/api/mindspace/v1/pages
/api/mindspace/v1/publications
/api/mindspace/v1/conversation-packages
/api/mindspace/v1/conversation-packages/:packageId/manifest
/api/mindspace/v1/conversation-packages/:packageId/artifacts

3.3 Goose Runtime

Goose Runtime 负责:

  • Agent session start/reply/resume/events。
  • Tool execution。
  • Long running job。
  • 通过 MindSpace MCP/API 读取输入文件、写入生成文件、创建页面、发布页面。

Goose Runtime 不应直接负责:

  • MindSpace 数据库表的业务写入。
  • Public URL 拼接。
  • 页面发布状态判断。
  • Conversation package manifest 的最终一致性。

短期内,如果 local filesystem adapter 仍需要 sandboxRoot,可以继续保留本地路径注入。但它只能是某个 adapter 的内部实现,不应该是 Memind/MindSpace/Goose 之间的长期契约。

4. Conversation Package 模型

用户要求的“每次对话里面的文件形成一个文件夹包”,建议抽象成 conversation package。

它在产品上像文件夹,在系统里是元数据包:

mindspace://users/<userId>/conversations/<sessionId>/
  manifest.json
  input/
  images/
  files/
  pages/
  public/
  generated/

注意: 上面是逻辑视图,不要求物理存储必须长这样。local fs 可以映射成真实目录,NAS 可以映射成共享目录,S3 可以映射成 object prefix。

Package manifest 应包含:

  • packageId
  • userId
  • sessionId
  • title
  • createdAt
  • updatedAt
  • storagePrefix
  • artifacts[]
  • pages[]
  • publications[]
  • messages[]
  • agentRuns[]

Artifact 应至少包含:

  • artifactId
  • assetId
  • pageId
  • publicationId
  • messageId
  • agentRunId
  • kind: input_image / input_file / generated_image / generated_file / page / public_html / long_image
  • displayName
  • mimeType
  • sizeBytes
  • storageKey
  • canonicalUrl
  • createdAt

推荐新增表:

CREATE TABLE h5_conversation_packages (
  id VARCHAR(64) PRIMARY KEY,
  user_id VARCHAR(64) NOT NULL,
  session_id VARCHAR(128) NOT NULL,
  title VARCHAR(255) DEFAULT NULL,
  status VARCHAR(32) NOT NULL DEFAULT 'active',
  storage_prefix VARCHAR(512) DEFAULT NULL,
  manifest_asset_id VARCHAR(64) DEFAULT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uniq_conversation_package_session (user_id, session_id)
);

CREATE TABLE h5_conversation_artifacts (
  id VARCHAR(64) PRIMARY KEY,
  package_id VARCHAR(64) NOT NULL,
  asset_id VARCHAR(64) DEFAULT NULL,
  page_id VARCHAR(64) DEFAULT NULL,
  publication_id VARCHAR(64) DEFAULT NULL,
  agent_run_id VARCHAR(128) DEFAULT NULL,
  message_id VARCHAR(128) DEFAULT NULL,
  role VARCHAR(32) DEFAULT NULL,
  artifact_kind VARCHAR(64) NOT NULL,
  sort_order INT NOT NULL DEFAULT 0,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  KEY idx_conversation_artifacts_package (package_id),
  KEY idx_conversation_artifacts_asset (asset_id),
  KEY idx_conversation_artifacts_page (page_id),
  KEY idx_conversation_artifacts_message (message_id)
);

也可以先用轻量方案过渡:

  • h5_assets 增加 source_session_idsource_message_idsource_run_id
  • 利用现有 h5_page_records.source_session_idh5_page_records.source_message_id 回填页面来源。
  • 利用现有 h5_agent_jobs.session_id 回填 agent 生成物来源。
  • 先做 package view,再补完整 package tables。

5. Storage Adapter

MindSpace Service 内部需要统一存储接口:

interface MindSpaceStorageAdapter {
  putObject(key, body, options)
  getObject(key)
  statObject(key)
  deleteObject(key)
  listObjects(prefix, options)
  copyObject(sourceKey, targetKey, options)
  createReadStream(key)
  createWriteStream(key, options)
  getSignedUrl(key, options)
}

推荐分层:

MindSpace Domain
  -> Asset/Page/Publication/Package services
  -> Storage adapter interface
  -> local fs / NAS / S3 implementations

关键要求:

  • Memind 不知道 storageKey 如何映射到磁盘或 S3。
  • Goose 不直接生成 public URL,只提交产物给 MindSpace。
  • public URL 可以是 MindSpace Service 的 route,也可以是 CDN/object storage URL,但必须由 MindSpace Service 生成。
  • 本地开发默认用 local fs adapter,不依赖 103。
  • 生产可以继续先用现有机器路径,之后切 NAS/S3 时不改 Memind/Goose 业务层。

6. Agent 执行契约调整

当前 agent policy 里的关键值包括:

  • sandboxRoot
  • serverPath
  • nodeExecPath
  • MCP envs

这些仍可作为短期兼容层,但长期应改成:

{
  "mindspace": {
    "workspaceRef": "mindspace://users/u_xxx/conversations/s_xxx",
    "packageId": "cp_xxx",
    "apiBaseUrl": "https://mindspace.example.com",
    "accessToken": "scoped-short-lived-token",
    "allowedTools": ["read_file", "write_file", "edit_file", "publish_page"]
  }
}

推进原则:

  • Local fs adapter 可以把 workspaceRef 映射到本机临时目录或真实目录。
  • NAS adapter 可以把 workspaceRef 映射到共享挂载目录。
  • S3 adapter 不应暴露 raw fs path,应通过 MCP/API 完成读写和预览。
  • Agent 写入完成后,MindSpace Service 负责把产物登记到 package manifest。

7. 推进阶段

P0: 盘点和冻结边界

目标: 先明确哪些代码还在直接使用路径、URL、数据库表。

输出:

  • 路径调用点清单: MindSpace/data/mindspace/sandboxRootpublic/*.html
  • URL 调用点清单: /MindSpace/canonicalUrlpublicationUrl
  • DB 调用点清单: asset/page/publication/job/session 相关表。
  • 当前本地开发拓扑和生产拓扑分开写清楚,避免继续把 103 当开发依赖。

P1: 在单体内抽出 MindSpace Service 边界

目标: 不改部署方式,先把边界从代码里立起来。

动作:

  • 新增或整理 MindSpaceService domain 层。
  • 引入 MindSpaceStorageAdapter interface。
  • local fs adapter 先包住现有 MindSpace/data/mindspace/
  • 禁止新代码直接拼接 MindSpace public URL。
  • 给 public URL 生成和 backing file 校验加集中入口。

验收:

  • 现有 H5、公开页、页面发布、文件下载行为不变。
  • 代码搜索可以证明新增业务不再直接依赖物理路径。

2026-07-27 增量进展:

  • Chat Save 的错误资源引用修复、私有图片物化和 HTML 写回已收进 chatSaveService.materializeWorkspaceHtml
  • local adapter 与 remote RPC 使用同一 contractPortal 不再在 resolveChatSaveBundle 中读取 storageRoot 或直接 writeFile
  • 已增加源码门禁,防止这条已完成的写路径重新泄漏回 server.mjs
  • 公开页交付、Finish public HTML 同步和其它 Portal 路径仍需按后续 P1 切片继续收口;本增量不代表 P1 整体完成。
  • 新增 conversationArtifactServicelocal 与 remote adapter/RPC 共用同一契约。
  • Finish 的 public HTML、聊天导出的 DOCX、发布长图不再由 Portal 直接调用 conversation package registry;物理目录解析、backing file 校验、artifact/package 登记与 manifest 刷新由 MindSpace 负责。
  • Portal 的 Finish 保留 SSE/锁/页面同步时序,仅向 artifact 服务传 user/session/relativePath/messageId 等逻辑信息。
  • 新增 publicFinishServiceSSE write_file/edit_file 兼容落盘、 Finish HTML/私有资源物化、DOCX 同步、workspace asset sync、 artifact 登记和 canonical URL 生成均在 MindSpace 内完成。
  • Quick Share 的私有资源内联、public/shared/*.html 落盘和 public URL 生成也已收进 chatSaveService.createSharedHtml
  • workspacePublicationDeliveryService 已成为 /MindSpace/u/:slug/public、workspace 长图、recent HTML discovery 和 Agent Run deliverable validation 的统一读交付入口;返回 HTML 或 Base64 body 等逻辑交付对象,禁止把绝对路径返回 Portal。
  • publication resolve 由 MindSpace 返回 workspacePublicUrl Portal 不再拼接 canonical workspace URL。
  • Finish 的 HTML 完整性检查、Page Data 自动绑定/验收,以及 workspacePageDeliveryService.syncAndDeliver 已迁入 local/remote adapterportal-session-routes 不再接收 publishDirstorageRooth5Root
  • 微信 Page Data 验收、HTML 链接交付和 fresh thumbnail 校验/修复 均改为调用 publicFinishService.prepareWechatPageDataDeliveryprepareWechatHtmlDeliveryensureWechatFreshPageThumbnails Portal bootstrap 只注入这些逻辑能力,不再向微信模块注入 MindSpace pool、storage root、publishDir 或 H5 root。
  • 资产下载、from-asset 读取和 Agent Job 输入资产交付改为 bodyBase64 契约;远程 adapter 不再暴露会泄漏物理路径的 readAsset / readPublicAsset
  • Portal 仅保留鉴权、HTTP 响应头、HTML 展示层注入、Finish 锁、 修复触发与 analytics 转发,并等待流式写入完成后才标记页面 ready。
  • P1 的 H5/Portal/微信 HTML/Page Data 主读写与交付链路已收拢;P4 仍需补齐真实 split-service 端到端 smoke,并继续收敛剩余 workingDir 兼容上下文。

P2: Conversation Package 首先落地

目标: 用户每次对话生成的图片、文件、页面、公开链接都能在一个包里看到。

动作:

  • 为每个 chat session 创建或懒创建 conversation package。
  • 上传文件、图片描述、页面生成、长图、HTML 发布都写入 artifact 归属。
  • 新增 package manifest API。
  • H5 增加 package view: 图片、文件、页面、公开链接按对话聚合展示。
  • 对历史数据做 best-effort 回填。

当前开发分支进展:

  • 已新增 conversation package 表/注册层/API/manifest 导出和 manifest 校验脚本。
  • H5 已增加“对话包”查看入口,隐藏内部 message UUID,只展示用户可理解的产物信息。
  • public/*.html 已接入 Finish 后登记和历史会话懒回填,可在 package 中看到公开页面。
  • 上传图片/文件已支持 sessionId/messageId provenance;全新会话首条图片上传会在 agent run 返回真实 sessionId 后按 messageId 后置认领进 package。
  • 公开页长图下载已登记为 long_image artifactPNG 同步写入 conversation package 私有对象,canonical URL 保持公开页长图下载入口。
  • Finish 后 public workspace 同步已携带同轮 messageId,让生成文件、图片、docx companion 进入 package 时具备消息级 provenance。
  • 聊天 docx 下载已抽出 package 登记模块并加入测试,确保 docx 私有对象、artifact、manifest 刷新一致。
  • 发布入口已覆盖 chat-sourced page 的 publication companion 流程,确认 public_html、同目录 docxlong_image 会在真实 publish() 调用中进入同一 package。
  • H5 package view 已增加按产物类型筛选、计数、空包引导和加载失败重试提示。
  • H5 package view 已增加按消息维度筛选,用户可从某一轮请求反查对应产物,且不展示内部 message UUID。
  • Manifest 已包含 messages[] / agentRuns[] provenance 聚合,便于追溯某条消息或某次 agent run 产生了哪些 artifact。
  • 已增加 package manifest 一致性校验脚本,覆盖 artifact URL / storage object 的可读性。
  • 读取 package 前已增加历史会话 best-effort 扫描回填,覆盖 h5_page_recordsh5_publish_recordsh5_upload_sessions 中已有 source_session_id 的页面、发布页、companion 文件和已完成上传。
  • Package 读取前的 backfill/hydrate 编排已收拢进 MindSpaceService facadeserver.mjs 路由层只负责鉴权后调用 facade。

剩余开发项:

  • P2 当前分支实现已完成;进入提交前需保持 guard、build、全量测试和回归 smoke 通过。

验收:

  • 一次对话中上传图片、生成 HTML、发布页面后,package 页面能看到所有产物。
  • package manifest 可以导出,并能指向真实可读的 backing file。
  • 不再只能靠散落目录追查某次对话产生了什么。

P3: MindSpace Service 本地独立进程

目标: 在本机开发环境先拆进程,不碰生产 103。

动作:

  • MindSpace API 单独启动,例如 localhost:<mindspace-port>
  • Memind App 通过 MINDSPACE_API_BASE_URL 调它。
  • Goose 仍可本地运行,但通过 MindSpace API/MCP 获取 workspace。
  • 本地 storage adapter 继续使用 local fs。

验收:

  • 停掉 MindSpace Service 后,Memind H5 能明确报 MindSpace 不可用,而不是静默写本地路径。
  • 换一个 local storage root 后,Memind 和 Goose 不需要改业务代码。

P4: MindSpace MCP Bridge

目标: Goose 不再把 raw filesystem path 当核心契约。

动作:

  • MCP tools 改为接受 workspaceRef / packageId
  • read_filewrite_fileedit_filepublish_page 通过 MindSpace Service 落元数据。
  • scoped token 限制到用户、session、package 和允许工具。

验收:

  • Agent 生成文件后,MindSpace package manifest 自动更新。
  • Policy 泄漏时也只能访问当前 package 范围。

2026-07-27 第一批实现进展:

  • 新增 workspaceToolService,以 workspaceRef + sessionId + packageId + relativePath 承载 read_filewrite_fileedit_file、目录操作和 publish_pagelocal/remote adapter 使用同一契约,返回值不暴露绝对路径。
  • MindSpace Service 新增专用 /mindspace/v1/mcp/:tool 入口。 HMAC scoped token 同时绑定 user、session、package、workspace 和 tool allowlist;请求不能覆盖 token 中的作用域。
  • Agent policy 在取得真实 session 后重新生成 scoped extension 配置; 签名 secret 只留在 Portal/MindSpace ServiceGoose sandbox 只接收 短期 token。
  • sandbox MCP 在配置 scoped endpoint 时通过 MindSpace Service 完成 逻辑读写;publish_page 只在该配置完整时开放。
  • write_file / edit_file 对公开 HTML 使用专用 public artifact 登记,对其它文件使用通用 workspace artifact 登记;每次写入均刷新 package manifest,不依赖 asset sync 是否因相同 checksum 跳过。
  • 本批已完成核心工具的逻辑写入与 package 自动登记,但 P4 尚未整体 关闭:当前 scoped token 能防止跨 user/session/package 身份写入, read_file 的内容范围仍是该用户的逻辑 workspace,并非仅限当前 package 已登记对象。要满足“token 泄漏也只能读取当前 package” 的完整验收,还需增加 package artifact read capability。
  • 第二批已新增受 scoped token 保护的 write_binary_file 内部操作: generate_docx 只在 sandbox 临时目录生成文件,随后把二进制交给 MindSpace Service 写入目标 workspace 并登记 packageremote 模式 不再把 DOCX 直接写到 Goose 的 workspace path。
  • generate_long_image 已改为由 MindSpace Service 校验 backing HTML、 生成 canonical source URL、渲染 PNG、写入 workspace 并登记 artifact sandbox 不再读取目标 HTML 的物理路径或写目标 PNG。
  • 微信 HTML 交付与 fresh thumbnail 已改为 MindSpace Service 内部解析 backing file、生成 canonical URL 并返回逻辑 artifact;真实 split-service 端到端 smoke 仍需后续切片收口。

P5: NAS/S3 Adapter

目标: 存储后端可替换。

动作:

  • 实现 NAS adapter 或 S3 adapter。
  • 增加 migration/backfill 工具,把现有文件迁移到新 storage prefix。
  • 增加校验脚本: DB record、manifest、object stat、public URL 一致。
  • 必要时先 shadow-read 或 dual-write,降低迁移风险。

验收:

  • local fs 切到 NAS/S3 后,Memind App 不改代码。
  • Goose 不改业务契约。
  • 公开页、下载、预览、长图、package manifest 都正常。

P6: 生产部署迁移

目标: 等本地和 staging 验证后,再考虑生产拓扑。

原则:

  • 103/105 只是部署位置,不是架构边界。
  • 当前 103 可以继续承载旧 Portal 和 MindSpace,直到 MindSpace Service 独立进程稳定。
  • 生产迁移前必须有回滚方案、manifest 校验、public URL 抽样验证。
  • 不从本地直接依赖 103 做开发验证。

8. 当前 103/105 如何理解

如果短期还要用 103/105 描述生产部署,可以这样表述:

105 = public edge / Memind App entry
103 = current production host running legacy Portal + MindSpace + Goose

但这只是当前生产状态,不是最终架构。

最终应该允许:

Memind App:      105 / k8s / 任意 Web 服务
MindSpace:       独立 VM / NAS 旁路服务 / S3-backed 服务 / k8s service
Goose Runtime:   本机 / worker pool / 独立执行集群
Storage Backend: local fs / NAS / S3 / CDN-backed object storage

9. 验收标准

拆分成功不以“服务能启动”为准,而以这些行为为准:

  1. 一次对话上传的图片、文件、生成页面、公开 HTML、长图都能在同一个 package 中看到。
  2. Package manifest 中的每个 artifact 都能追溯到 asset/page/publication/message/run。
  3. Memind App 不直接拼接 MindSpace 物理路径或 public URL。
  4. Goose 生成文件后,MindSpace 元数据和实际 backing file 一致。
  5. 切换 local fs / NAS / S3 adapter 时,Memind App 和 Goose 的业务逻辑不需要改。
  6. 公开 URL 由 MindSpace Service 生成并校验。
  7. 本地开发不依赖 103,生产 103 也不是架构上的必须组件。

10. 风险

风险 表现 控制方式
路径假设太深 代码到处拼 MindSpace/<userId> P0 做调用点清单,P1 加 service/adapter 边界
URL 权威混乱 Memind、Goose、MindSpace 各自拼 URL URL 只由 MindSpace Service 生成
Agent 直写绕过元数据 文件存在但 package 看不到 MCP/API 写入后必须登记 artifact
S3 非文件系统语义 edit_file、stream、rename 行为不一致 先定义 adapter 能力,必要时用临时工作区 materialize
迁移丢历史关系 老页面找不到来源对话 利用现有 source_session_id、job session 做 best-effort 回填
权限过宽 agent token 访问其它用户文件 scoped short-lived token,绑定 user/session/package
package 过大 长对话产物太多 manifest 分页、artifact 分类、归档策略
生产切换风险 public link 失效 迁移前跑 object stat + URL 抽样 + 回滚

11. 建议下一步

建议按这个顺序推进:

  1. 保留本文档为总纲,另外新增 docs/mindspace-service-contract.md 写 API、storage adapter、package manifest 的详细契约。
  2. 做 P0 audit: 搜索所有 MindSpace/data/mindspacesandboxRoot/MindSpace/canonicalUrl 调用点。
  3. 先在单体内做 P1,不急着拆进程,避免一次同时改部署、存储、执行链路。
  4. 优先实现 P2 conversation package,因为这是用户可见价值,也能倒逼所有产物建立 provenance。
  5. 本地完成 P1/P2 smoke 后,再做 P3 独立 MindSpace Service。
  6. 等 P3 稳定后再考虑 P4 MCP 契约和 P5 NAS/S3。
  7. 生产 103/105 迁移放到最后,只作为部署迁移,不作为架构设计的出发点。

最小可交付版本:

单体内 MindSpaceService 边界
+ local fs storage adapter
+ conversation package tables/API
+ H5 package view
+ public URL 集中生成
+ 现有发布/下载/预览回归通过

这个版本即使还没有真正拆进程,也已经把未来独立部署、NAS/S3 和 Goose 解耦的地基打好了。

12. 启动门禁和回退策略

本轮推进只能在独立分支上开始,禁止直接提交 main

当前建议分支:

codex/mindspace-decouple-20260702

开始任何代码改动前必须先确认:

git branch --show-current
git status --short --branch
git merge-base --is-ancestor origin/main HEAD

通过条件:

  • 当前分支不是 main
  • 当前分支基于最新 origin/main 创建。
  • 工作区里只出现本轮 MindSpace 解耦相关文件。
  • 不允许从本机开发流程依赖 103。

本地保护:

  • .git/hooks/pre-commit 应阻止在 main 上直接 commit。
  • 如果需要新分支,必须使用 bash scripts/new-branch.sh <branch-name>,不要直接在脏工作区切分支。
  • 每个阶段开始前先记录 git status --short --branch

回退分三层:

  1. 单文件回退: 如果某个文件改坏,只恢复该文件,不影响其它正在推进的内容。
  2. 阶段回退: P1/P2/P3 每个阶段独立提交;如果阶段失败,只 revert 该阶段提交。
  3. 分支回退: 如果方向整体不对,保留 main 不动,直接放弃 codex/mindspace-decouple-20260702 分支即可。

禁止事项:

  • 禁止在 main 上 commit。
  • 禁止从脏工作区发布。
  • 禁止把 103 当作本地开发依赖。
  • 禁止在没有 package provenance 的情况下继续扩大文件生成链路。
  • 禁止把 storage backend 细节暴露成 Memind 或 Goose 的长期 API。

第一批可执行任务:

  1. P0 audit: 生成路径、URL、policy、DB 调用点清单。
  2. 新增 docs/mindspace-service-contract.md,只写契约,不改运行逻辑。
  3. 设计 conversation package schema migration,但先不执行生产迁移。
  4. 在单体内抽 MindSpaceStorageAdapter 和 public URL 生成入口。
  5. 给现有发布/下载/预览跑回归,再进入下一阶段。