# Prisma migrate diff 生成的 enum rename 块会引用未创建的表

**date**: 2026-05-17
**context**: PR2-4 v3 重构生成 migration 时 `prisma migrate diff --from-migrations ... --to-schema-datamodel ...` 输出的 SQL 应用失败。

## 症状

```
ERROR: relation "robot_manager.robot_unit_snapshots" does not exist
当前 transaction is aborted, commands ignored until end of transaction block
```

migration.sql 顶部 ~第 28 行：

```sql
-- AlterEnum
BEGIN;
CREATE TYPE "robot_manager"."RobotLifecycleStage_new" AS ENUM (...);
ALTER TABLE "robot_manager"."robot_units" ALTER COLUMN "current_status" DROP DEFAULT;
ALTER TABLE "robot_manager"."robot_unit_snapshots" ALTER COLUMN "current_stage" TYPE ...;  -- ❌ 表不存在
ALTER TABLE "robot_manager"."robot_lifecycle_events" ALTER COLUMN ...;                      -- ❌ 表不存在
ALTER TYPE ... RENAME TO ..._old;
ALTER TYPE ..._new RENAME TO ...;
DROP TYPE ..._old;
COMMIT;
```

后面 700 行才出现 `CREATE TABLE robot_unit_snapshots / robot_lifecycle_events`。

## 根因

Prisma migrate diff 在生成 enum 变更（删除旧 value）时，会**预设所有最终 schema 里使用该 enum 的列都已存在**，然后逐个 ALTER TABLE。但实际上 v3 schema 包含很多新表（Snapshot / Event）——这些表在 migration 顺序里要等到后半段才被 CREATE，所以前半段的 ALTER TABLE 必然失败。

## 解决

手动改写 enum rename 块：

```sql
-- 1. 把当前实际存在的列处理掉
ALTER TABLE "robot_manager"."robot_units" ALTER COLUMN "current_status" DROP DEFAULT;
ALTER TABLE "robot_manager"."robot_units" ALTER COLUMN "current_status" TYPE TEXT USING "current_status"::text;

-- 2. CASCADE 把还在引用 enum 的旧表列也带走（这些表在下文都会被 DROP）
DROP TYPE "robot_manager"."RobotLifecycleStage" CASCADE;

-- 3. CREATE 新 enum（同名）
CREATE TYPE "robot_manager"."RobotLifecycleStage" AS ENUM (28 个 v3 值...);
```

关键点：
- 用 **CASCADE** 一次性带走所有依赖旧 enum 的列；这些列对应的表 / 列在 migration 下文都会被 DROP，CASCADE 顺序提前不影响最终一致性
- 不需要 prisma 标配的 _new / _old 双 enum 倒手——直接 DROP + CREATE 更简洁
- 配套要把 current_status 列先 CAST 到 TEXT（保留旧字符值，DROP TYPE 时不会因列类型还是 enum 而失败）

## 顺带踩坑：Prisma diff 还会塞无关 ALTER

同一份 migration 里出现了：
- `ALTER TABLE platform_ai_usage.ai_usage_events ALTER COLUMN total_tokens DROP DEFAULT;`
  → PG 拒绝：generated column 不能 DROP DEFAULT
- 5 个 `ALTER INDEX platform_ai_usage.ai_usage_*_org_idx RENAME TO ..._organization_id_idx`
  → 上一轮 baseline 跟 schema 漂了，跟本次 PR 完全无关

这些是历史 baseline 漂移积累，把整个仓库的 schema 偏差全部塞进任何下一个 migrate diff 输出里。直接 sed 删除即可。

## 可复用做法

1. **大改动用 `prisma migrate diff` 时务必先看输出**，肉眼扫一遍：
   - 找 `BEGIN;...COMMIT;` 块，确认引用的表 / 列在前面真的存在
   - 找跟当前 PR 主题无关的 ALTER（不同 schema 的 RENAME INDEX / DROP DEFAULT），全部删
2. **enum 删值场景优先用 CASCADE drop + recreate**，少绕弯
3. **修完用 shadow DB 验一遍**：`docker exec ... psql ... CREATE DATABASE shadow_v3` + `DATABASE_URL=...shadow_v3 npx prisma migrate deploy` — 比直接跑测试快很多

## 关联
- PR feature/robot-manager-v3-full-refactor commit 6e176a30
- 之前 PR1 也踩过 ADD VALUE 跟 UPDATE 同事务的相似坑：[`2026-05-16-pg-alter-type-add-value-same-txn.md`](./2026-05-16-pg-alter-type-add-value-same-txn.md)
- standard 04 / 16 都没覆盖这条，建议加到 `docs/standards/04-database-architecture.md` 「迁移 checklist」段
