Files
Jyotisha/docs/tasks/PROGRESS-data-layer-types-20261013.md
T
jesse-uxandGrok (agent loop) b184448871 fix(db): check callers against the adapter that actually runs
The self-hosted client was typed as a full Supabase client, so an old scoring poll called .single() on a plain promise and failed. The new DataClient only lists methods the adapter implements.

Co-Authored-By: Grok (agent loop)
2026-10-15 09:21:14 +08:00

6.2 KiB
Raw Blame History

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<Readonly<{ data: any; error: Readonly<{ message: string; code?: string | undefined; }> | 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 条里。