# PROGRESS · 数据访问层 DataClient 类型(第一阶段) - 分支:`codex/data-layer-types-20261013` - 基线:`origin/staging` `9274491681f6fcacbc87e3797441d2c5221de874` - 前置:`origin/codex/node-runtime-resources-20261013` 已是 `origin/staging` 的祖先(`merge-base --is-ancestor` 退出码 0)。`local-postgres-client-core.ts` 只加了 `import type` 和两处 `implements`。 - `frontend/src/lib/rectification-agentic/session.ts` 已不在,本单没有改它。 - 编号:任务书预留 BUG-1343。开工时 `docs/BUG_HISTORY.md` 最大号是 BUG-1350,1343 没有条目。按台账规则从最大号往后,记为 **BUG-1351**。 ## T1 · 编译器暴露的 2 条 `DataClient` 换上之后、缺陷尚未修时,`tsc --noEmit` 退出码 2,恰好 2 条: ``` src/app/api/chart-profiles/route.ts(59,40): error TS7006: Parameter 'row' implicitly has an 'any' type. src/lib/birth-time-scoring-job-store.ts(103,10): error TS2339: Property 'single' does not exist on type 'Promise | null; count?: number | null | undefined; }>>'. ``` `grep`:`as unknown as SupabaseClient` 在 `frontend/src` 无结果。`@supabase/supabase-js` 只剩 `admin-client-core.ts` 的 `createClient` 回滚分支。 ## T2 · 缺陷修复红转绿 修复前,`claimScoringJob` 对返回数组的假 `rpc` 调用 `.single()`: - `claimScoringJob reads the first row when rpc returns an array`:失败,`TypeError: supabase.rpc(...).single is not a function` - `claimScoringJob also accepts the single-object rpc shape`:同样失败 去掉 `.single()` 并兼容数组与单对象之后,这两条通过。真实迁移用例 `claim_birth_time_scoring_job returns an array and claimScoringJob accepts it` 通过:`data` 是数组,第一行 `claim_state` 为 `claimed`,store 返回 `{ kind: "claimed", algorithmVersion }`。第一次启动测试库时迁移进程只留下笼统的 `database migration failed`(脚本会把非预期异常收成这一句),容器未到 Healthy。同一条用例在容器 Healthy 后重跑通过。 `chart-profiles/route.ts` 的 `row` 标为 `unknown`。 修完后 `tsc --noEmit` 退出码 0。`npm run lint` 退出码 0,0 error,123 warning(与改动前的存量警告数量一致,本单没有新增 warning)。 ## T3 · 转译差分 类型层改动用 esbuild 0.28.1、`--format=esm`、`--tsconfig=frontend/tsconfig.json`,旧文件与新文件都按这份 tsconfig 转译。除 T2 的两个文件和新建的 `data-client.ts` 外,全部 `SAME`: - `src/lib/birth-time-journey-case-loader.ts` - `src/lib/birth-time-journey-store.ts` - `src/lib/birth-time-journey-turn-persistence.ts` - `src/lib/db/local-postgres-client-core.ts` - `src/lib/rectification-agentic/v9/case-service.ts` - `src/lib/rectification-agentic/v9/product-domain.ts` - `src/lib/rectification-agentic/v9/tool-service.ts`(只改了一句注释;转译后注释被去掉,产物相同) - `src/lib/rectification-in-chat-server.ts` - `src/lib/supabase/admin-client-core.ts` - `src/lib/supabase/server.ts` - `src/mastra/rectification-v9-tools.ts` 任务书把旧文件写到系统临时目录再转译。esbuild 0.28.1 会沿文件所在目录寻找 `tsconfig.json`。临时目录找不到本仓库的 `tsconfig.json`(`target` 为 ES2017),类字段的转译结果会和仓库内文件不一致,即使源码只有类型或注释差别也会报 DIFF。两边都带上同一份 `--tsconfig` 后为 SAME。这不是运行时变化。 ## T4 · 把 data 收成 unknown 的错误清单 临时把 `UntypedData` 改成 `unknown` 后 `tsc --noEmit` 退出码 2,共 93 条、12 个文件。随后已改回 `any`。 | 条数 | 文件 | | ---: | --- | | 24 | `src/app/api/account/route.ts` | | 17 | `src/app/api/consult/route.ts`(其中 1 条是 `DataClient` 不能赋给 `GuardedTitleClient`,`consult/route.ts` 约 1055 行) | | 16 | `src/app/api/consult/status/route.ts` | | 12 | `src/app/api/payment/epay/status/route.ts` | | 7 | `src/lib/epay/availability.ts` | | 5 | `src/lib/rectification-agentic/v9/product-domain.ts` | | 4 | `src/app/api/sessions/route.ts` | | 3 | `src/lib/rectification-agentic/v9/agent-route-request.ts` | | 2 | `src/app/api/chart-profiles/[id]/route.ts` | | 1 | `src/app/api/account/avatar/route.ts` | | 1 | `src/app/api/chart-profiles/route.ts` | | 1 | `src/app/api/sessions/[id]/route.ts` | 和任务书写作时的 122 条相比,`consult/route.ts` 少了 10 条,`chart-profiles/route.ts` 少了 1 条(本单已把 `row` 标成 `unknown`)。没有单独再出现一条 `session-title-guard.ts` 的错误,`GuardedTitleClient` 那条记在 `consult/route.ts` 里。这些留给第二阶段,本单没有改那些业务文件。 ## test:db `npm run test:db`(`tsx --test --test-concurrency=1 tests/database-*.test.ts`)约 19 分钟,退出码 1。汇总:85 条,通过 72,失败 13,取消 0,跳过 0。 失败的 13 条与 `tools/agent-loop/windows-known-failures.txt` 逐条一致,没有多出来的失败: - staging backups are encrypted, atomic, private, and retain the newest three - rejects destructive backup directory aliases and symlink components before mutation - rejects unsafe writable backup parents before creating the target - rejects a direct canonical sticky shared backup directory before chmod - creates every absent backup path component privately despite a permissive caller umask - same-second backups publish once without overwriting the completed archive - find enumeration failures preserve existing backups and do not report completion - refuses full disks and removes a failed-pipeline partial file - database env validator accepts punctuated literal required secrets - database env validator enforces an explicit staging owner uid without printing values - database env validator accepts a private valid file without printing values - personal report job migration is atomic, lease-bound, recoverable, and owner read-only - personal report sections enforce owner-read RLS and service-owned durable transitions 本单新增的 3 条(两条假客户端、一条真实迁移认领)都在通过的 72 条里。