# PR14.5 LocalStorageAdapter 命名冲突：服务端 vs Desktop 端语义不一致

**日期**：2026-05-16
**触发**：Phase 2 PR14.5 准备落地时发现 backend 已有 `LocalStorageAdapter`（Phase 1 落地），但**语义与 PRD 不符**。

## 现象

- `backend/src/modules/agent/storage/local.adapter.ts` 的 `LocalStorageAdapter` 写到服务端 `/tmp/ffai-agent-storage`
- Phase 2 PRD US-501 "Desktop 用户切 Local backend 跑通" 的 LOCAL 是**用户本机** `~/FFAI Workspace/`（经 HostBridge.fs.write）
- 两者**同 kind='LOCAL'**但路由完全不同

## 影响

- 用户在 admin UI 选 "Local backend" 当前会落到服务端 /tmp，不符合期望（"我的文件在我电脑上"）
- 服务端 /tmp 是临时存储，重启即丢，Phase 1 期间没人真用它当持久 backend
- 文档与代码契约漂移：PRD §5 LocalStorageAdapter 实际指的是 Desktop fs，不是服务端 fs

## 当前 PR 处理（PR12-15 批量）

仅落 **skeleton**：`storage/desktop-local.adapter.skeleton.ts`，**不接入 module providers**。

## 待用户决策的清理方案

### 方案 A（推荐）：重命名 + 语义还原

1. `LocalStorageAdapter`（旧）→ `ServerTempStorageAdapter`
2. `StorageBackendKindLite` 加 `'SERVER_TEMP'` 枚举，旧 'LOCAL' 引用迁移
3. `DesktopLocalStorageAdapter`（新）升正用 `kind: 'LOCAL'`
4. admin UI / DataScope binding 选择项更新文案：
   - LOCAL = "我本机（Desktop App 必须在线）"
   - SERVER_TEMP = "服务端临时区（仅开发/staging 用）"

**改动面**（grep 估算）：
- `backend/src/modules/agent/storage/local.adapter.ts` 改类名 + kind
- `backend/src/modules/agent/storage/storage.types.ts` 枚举改
- `backend/src/modules/agent/agent.module.ts` provider 改名
- 数据库现有 StorageBinding 行 kind='LOCAL' 迁移到 'SERVER_TEMP'（Phase 1 应只有内部测试数据，迁移风险低）
- DataScope binding 配置文案更新

### 方案 B：双 kind 并存

`StorageBackendKindLite` 加 `'DESKTOP_LOCAL'`，两个 adapter 并存：
- LOCAL → server temp（原样保留）
- DESKTOP_LOCAL → 用户本机 fs

**好处**：零迁移、零破坏。**坏处**：admin UI 多一项、用户认知负担、文档要解释"LOCAL 不是真的 local"。

## 推荐路径

走方案 A——一次清干净，符合 PRD 原意。前提条件：

1. 用户确认 Phase 1 期间 StorageBinding 表里没有生产 LOCAL 数据需要保留
2. 改名走单独 PR（独立主题、独立风险），不在 PR12-15 批量内
3. PR14.5 真实化时（接 SSE tool_use round-trip）顺带把 DesktopLocalStorageAdapter 升正

## 当前 PR 不动 module providers 的理由

- 命名冲突未澄清前接入会让 admin UI 出现两个"LOCAL"选项之一（重复或错路由）
- skeleton 文件以 `.skeleton.ts` 后缀（参考 `mcp-client.skeleton.ts` 既有约定）标识"已写但未启用"
- 用户确认方案 A/B 后开新 PR 接入 + 数据迁移
