## [ERR-20260508-006] 新 worktree 首次 db push 失败的真因是 citext 扩展缺失，iam-seed.ts 的 TS 报错是下游症状

**日期**: 2026-05-08
**类别**: 工具链 / Prisma / 容器初始化
**严重度**: 中（每个新 worktree 必踩；之前的 learning 给的是绕行方案，根因没解决）

### 现象

`bash scripts/dev/setup-worktree.sh <path> <branch>` 跑到最后两步连环失败：

```
# 步骤 1：prisma db push
Error: ERROR: type "citext" does not exist
   0: sql_schema_connector::apply_migration::migration_step
           with step=CreateTable { table_id: TableId(133) }

# 步骤 2：npm run db:seed
TSError: ⨯ Unable to compile TypeScript:
prisma/seeds/iam-seed.ts(194,36): error TS7006: Parameter 'e' implicitly has an 'any' type.
```

### 因果链（关键）

两个错误是**同一根因**的连锁：

1. `prisma/schema/platform_ops_center.prisma` 中 `userPrincipalName String @db.Citext`，schema 注释写明"需要在 migration.sql 顶部加 CREATE EXTENSION"
2. 本地走 `prisma db push`（无 migration 文件），没人帮忙执行 `CREATE EXTENSION citext;` → push 失败
3. **`prisma db push` 失败 → 它会顺带触发的 `prisma generate` 也没跑** → `node_modules/.prisma/client/index.d.ts` 只有 ~110 行的占位 stub（正常生成后是几万行，含所有模型类型）
4. ts-node 编译 `iam-seed.ts` 时，`prisma.roleDataScope.findMany()` 返回类型解析为 `any[]` → `existing.filter((e) => ...)` 里 `e` 是 implicit any → `noImplicitAny` 报错

### 验证因果链的方法

```bash
# 在新 worktree backend 目录
grep -c "RoleDataScope" node_modules/.prisma/client/index.d.ts
# 0 → client 没生成（schema 里有这个模型但 client 里没）
wc -l node_modules/.prisma/client/index.d.ts
# 110 → 占位 stub，不是真生成结果
```

如果看到这两个症状 + iam-seed.ts 报 implicit-any，就是这条链。

### 正确解决（修根因）

在 `setup-worktree.sh` 的 PG 就绪之后、`prisma db push` 之前，加一步装扩展：

```bash
local PG_EXTENSIONS=(citext)
for ext in "${PG_EXTENSIONS[@]}"; do
  docker exec -e PGPASSWORD="${db_password}" "${container_name}" \
    psql -U "${db_user}" -d "${db_name}" -tAc "CREATE EXTENSION IF NOT EXISTS ${ext};"
done
```

修完后 `db push` 通 → `prisma generate` 自动跑 → client 类型完整 → seed 也直接通过，**不需要碰 iam-seed.ts 也不需要改 `db:seed` 脚本**。

### 与 ERR-20260429-014 的关系（重要）

[ERR-20260429-014](ERR-20260429-014.md) 也记的是同一个 iam-seed.ts TS7006 报错，但当时给的方案是"`db:seed` 加 `--transpile-only` 绕过 ts 严格检查"。**那是绕行，不是修根因**：

- `--transpile-only` 让 ts-node 跳过类型检查，所以错误"消失"了。但运行时如果 prisma client 真的没生成，`prisma.roleDataScope` 就是 undefined，第一次访问就 NPE。当时大概因为之前 worktree 有遗留的 client，没暴露出来。
- 真正问题是 client 没生成。client 没生成的原因是 db push 失败。db push 失败的原因是 citext 缺。
- **修了 citext 这一条之后，ts-node 严格类型检查没问题、不需要 --transpile-only**。

教训：看到"TypeScript 类型错"不要直接归因为"代码或 ts 配置问题"。如果错误指向的代码看起来明显合理（比如 prisma 调用），先怀疑**类型来源（生成的 client）是不是缺了**，而不是"这文件该 fix"。

### Metadata

- Reproducible: yes（任何首次 setup 的 worktree，只要 PG 没有 citext 都会触发）
- Related Files:
  - scripts/dev/setup-worktree.sh（修复点）
  - prisma/schema/platform_ops_center.prisma:21（citext 使用点）
  - prisma/seeds/iam-seed.ts:194（被错误归咎的下游文件）
  - .learnings/ERRORS/ERR-20260429-014.md（前一条诊断错的 learning，被本条订正）
- Fixed in: chore/workflow-optimization 分支 setup-worktree.sh
