# 103 与本地差异报告（2026-06-26）

## 目的

这份报告用于回答三个问题：

1. `103` 当前运行代码与本地代码差异到底在哪里。
2. 哪些差异可以忽略，哪些必须回收到本地。
3. 后续如何把生产发布收口到“只能本地打包发布”。

本次对比没有直接污染本地主开发目录，而是先从 `103` 拉出只读基线副本：

- `/Users/john/PycharmProjects/test/_103_baselines/Memind`
- `/Users/john/PycharmProjects/test/_103_baselines/memind_adm`

## 总结结论

### Memind

`test-memind` 当前代码内容与 `103` 拉下来的只读基线已经非常接近，重点业务文件基本一致。

可见差异主要是：

- 生产侧多了 `.release-manifest.txt`
- 本地多了一些文档、审计脚本和历史备份文件

结论：

- `Memind` 不存在明显的“线上独有核心逻辑未回收”问题
- 后续只需要继续坚持发布包流程，不应再直接改 `103`

### memind_adm

`test-memindadm` 与 `103` 基线仍然存在一批结构性差异，暂时不能直接把“线上就是最新”或“本地可以无脑全量覆盖”当成事实。

这些差异集中在：

- 用户详情与空间额度字段
- 订阅计划同步接口
- LLM provider 加载方式
- 启动注入与路由装配

结论：

- `memind_adm` 需要一次明确的差异回收
- 但回收动作应该发生在本地代码库中
- 生产只能作为对账依据，不能继续反向当开发主线

## 本次对比方法

### 只读基线

从 `103` 通过 SSH 22 拉取只读副本，并排除运行态内容：

- `.git`
- `.env`
- `node_modules`
- `dist`
- 日志
- pid 文件
- `.mindops`

这样做的目的是：

- 保留真实源码结构
- 不把线上运行态垃圾带回本地
- 不覆盖本地主开发工作区

### 对比范围

优先比对高价值文件：

- 服务启动入口
- API 路由
- 用户与计费相关页面
- 类型定义
- 发布脚本
- 部署文档

## Memind 对账结果

### 生产独有

- `.release-manifest.txt`

这是正常的发布产物，不需要回收到源码仓库。

### 本地独有

- `docs/103-reconciliation-2026-06-26.md`
- `scripts/audit-103-state.sh`
- `scripts/g2-lb.Caddyfile.bak-20260616-204004`
- `scripts/g2-lb.Caddyfile.bak-20260619-162631`
- `server.mjs.bak-20260616-195243`
- `.gitignore`

这些内容里：

- 文档与审计脚本应保留在本地仓库
- 备份文件需要后续择机清理

### 重点文件比对

以下关键文件对比结果为一致：

- `server.mjs`
- `user-auth.mjs`
- `db.mjs`
- `schema.sql`
- `src/App.tsx`
- `src/api/client.ts`
- `src/components/MindSpaceView.tsx`
- `package.json`
- `rsync_to_server.sh`
- `scripts/release-prod.sh`
- `docs/release-deploy.md`

判断：

- `Memind` 当前无需做额外的线上热修回收
- 可以直接进入“只允许发布包上线”的治理阶段

## memind_adm 对账结果

### 生产独有

- `server/llm-provider-loader.mjs`

这说明当前线上仍保留一层 provider 加载包装逻辑，而本地已改成直接走共享实现。

这不是简单的“多一个文件”，它意味着本地与线上在启动装配方式上已经分叉。

### 本地独有

- `PRODUCTION_RELEASE_RULES.md`
- `scripts/.releaseignore-prod`
- `scripts/release-prod.sh`
- `server/plan-sync.mjs`

这里面：

- 发布规则与发布脚本属于这次治理新增，应保留
- `server/plan-sync.mjs` 是本地新增业务能力，需要确认是否就是想带到生产的新主线

### 双方都改了的重点文件

- `.env.example`
- `docs/DEPLOY.md`
- `package.json`
- `scripts/rsync_to_server.sh`
- `server/app.mjs`
- `server/bootstrap.mjs`
- `server/index.mjs`
- `src/admin/pages/BillingPage.tsx`
- `src/admin/pages/UserDetailPage.tsx`
- `src/admin/pages/UsersPage.tsx`
- `src/api/client.ts`
- `src/types.ts`

### 高价值差异解读

#### 1. 用户详情与空间额度

本地版本新增了：

- `GET /users/:userId`
- `spaceQuotaBytes`
- `spaceUsedBytes`
- `spaceReservedBytes`
- `spaceAvailableBytes`

同时前端用户详情页和用户列表页也接入了这些字段。

这组改动和“后台可调空间、前台可购买空间”的需求方向一致，应视为本地主线能力，而不是线上应保留的旧逻辑。

#### 2. 订阅计划同步

本地版本新增了计划同步服务与同步结果结构：

- `server/plan-sync.mjs`
- `PlanSyncResult`
- Billing 页面同步结果展示

这组改动属于本地主线增强能力，线上基线暂未完整具备。

#### 3. LLM provider 装配方式

线上基线：

- `server/bootstrap.mjs` 通过 `./llm-provider-loader.mjs` 加载

本地版本：

- 直接从共享实现创建 `createLlmProviderService`

这是当前最需要审慎处理的一组差异，因为它影响服务启动边界，而不是单纯 UI 逻辑。

#### 4. 启动与监听方式

本地 `server/index.mjs` 增加了：

- `createPlanSyncService`
- 显式绑定 `127.0.0.1`

这类差异需要和 `103` 现有反向代理、双 Goose、启动脚本一起确认，但不需要为了本地开发去复制生产双负载拓扑。

## 风险判断

### 可以接受的不一致

- 生产 Goose 是双实例负载，本地不是
- 生产目录里有发布清单和运行态资产，本地没有
- 本地为了开发保留文档、审计脚本和发布脚本

这些不一致属于“环境差异”，不是“源码真相冲突”。

### 必须收口的不一致

- `memind_adm` 启动装配路径分叉
- 用户详情与空间字段相关接口分叉
- 订阅计划同步相关接口分叉
- 生产工作树仍然允许历史上留下的手改漂移存在

这些不一致会直接影响后续版本归属，必须在本地仓库中收口。

## 推荐收口顺序

1. 以本地 `test-memindadm` 为主线，明确保留“空间额度 + 用户详情 + 订阅同步”这组新能力。
2. 单独审查 `server/llm-provider-loader.mjs` 是否仍有线上必需逻辑。
3. 如果该文件只是在做兼容装配，则把必需逻辑回收进本地主线，再删除这层分叉。
4. 基于本地仓库走 `scripts/release-prod.sh` 做第一次正式发布。
5. 发布成功后，把 `103` 只保留为运行目标与审计对象，不再作为源码修改点。

## 最终原则

`103` 是运行事实来源，但不是源码主线。

后续必须坚持：

1. 本地仓库合并差异
2. 本地提交生成发布包
3. 生产只接收发布包
4. 不再直接 `rsync`
5. 不再在线改源码
