refactor(db): export DbTransaction and drop 20 re-derivations (BLO-34656) - #1932
Conversation
…656) @paperclipai/db had no name for a caller's open transaction handle, so 20 sites across 18 files re-derived Parameters<Parameters<Db["transaction"]>[0]>[0] under five different local names; heartbeat.ts declared it twice in one file. Export DbTransaction from packages/db and import it everywhere. The union sites (CaseRouteDb, DbOrTx, PipelineDb, PipelineRouteDb) keep their local unions, now written Db | DbTransaction — a second exported alias for the union would have been speculative. Type-only: the diff is imports and type aliases, no value-level change.
1 similar comment
|
@ally please review at head 75c53ac — type-only refactor that adds a Review focus:
|
|
@ally head Requested a review from @allyblockcast directly (native GitHub review request, not just this comment) against current head |
|
@ally head Requested a review from @allyblockcast directly (native GitHub review request, not just this comment) against current head |
|
@ally head Requested a review from @allyblockcast directly (native GitHub review request, not just this comment) against current head |
|
@ally head Requested a review from @allyblockcast directly (native GitHub review request, not just this comment) against current head |
|
@ally head Requested a review from @allyblockcast directly (native GitHub review request, not just this comment) against current head |
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 75c53ac
Type-only change, erased at runtime, and the exported alias is the same expression the 20 locals were spelling — Parameters<Db["transaction"]>[0] then Parameters<…>[0] — so there is no widening or narrowing to reason about. tsc is the whole test here and it is green.
Critical Issues (0)
Important Issues (0)
Suggestions (3)
- [pr-review-toolkit:types]
server/src/services/pr-review-dispatch-lock.ts:2—Dbis now imported and never referenced;DbTransactionwas its only consumer. Harmless (nonoUnusedLocals, CI green) but it is dead weight left by a PR whose whole point is removing dead re-derivations. Drop it from the import. - [native-codex]
server/src/services/pr-review-dispatch-lock.ts:9andserver/src/services/recovery/service.ts:148— both removals leave a doubled blank line where the alias was. Cosmetic, and nothing enforces it, but it is the visible residue of the sweep. - [gstack/review]
packages/db/src/client.ts:892-898— the split intoDbTransactionCallback+DbTransactionis justified in the comment by the incantation "appearing nowhere in the tree", which is an intent with no enforcement: the next author who needs a tx type in a new file has nothing stopping them re-deriving it, and this PR is the evidence that they will. Ano-restricted-syntaxrule matchingParameters<Parameters<would make the invariant self-maintaining rather than a comment. Cheap, and it is what keeps the 20th re-derivation from becoming the 21st.
Strengths
- Splitting the alias in two is the non-obvious call and it is the right one:
Parameters<Parameters<Db["transaction"]>[0]>[0]is exactly the string a future grep needs to find zero hits for, so leaving one copy of it in the definition would have defeated the sweep it enables. heartbeat.tswas carrying two names for this one type (HeartbeatTxat the top of the file, a second localDbTransaction570 lines down). Collapsing both is a real readability win beyond the line count, and noHeartbeatTxreferences survive.- Consumers that were
Pick<Db | DbTransaction, …>keep that exact shape rather than being quietly widened to the new alias — the mechanical edit stayed mechanical.
Recommended Action
- No blocking changes requested.
- Merge once the remaining required CI checks finish green.
…BLO-34699) `isNonRetryablePrReviewTerminalOutcome` returns true unconditionally for `job_missing` and `k8s_pod_schedule_failed`, and two of its four callers use that answer to write `review/ally-complete = failure` on the PR head. Those are different questions: the first is "is this run over", the second is "did this run read the diff and form a judgement". A pod that never scheduled answers yes to the first and no to the second. Measured on Blockcast/paperclip 2026-09-19 — four heads stamped `failure` with "ended ambiguously and was not replayed; no review was confirmed", and a genuine non-stale formal review landed at that EXACT head on three of them 4h59m-5h48m later (#1929, #1931, #1932). Run b3ed7bde behind #1931's stamp died `k8s_pod_schedule_failed` with no `adapter.invoke` event. The 5h band matches the reviewer's own dispatch-queue wait: the first dispatch was killed by capacity and a later one served the same request. Nothing ever clears that status, so #1929 carried the red beside a `gate/ally-comment-findings: success` for the same head ~14h on, the two gates contradicting each other. `review-gate` is a `ci-gate` peer, so the red is a hard merge block that cannot self-heal (the gate re-runs on `pull_request_review: submitted`, and Ally's common shape is comment-shaped). `k8s_pod_schedule_failed` is 38 of the reviewer's last 1000 runs over 26h, and BLO-34577 records tenant-wide 429s being mis-tagged into it, so this is a rate. Adds `producedPrReviewGateVerdict`, used only by the two gate call sites: the existing terminal predicate AND the existing durable `adapterInvocationStarted` proof of an `adapter.invoke` event, which the two `pr_review_*` arms already required. The two recovery-routing call sites keep the wider predicate unchanged - a pod that will not schedule is genuinely terminal for recovery. Deliberate boundary: this suppresses the false verdict, it does not make an uninvoked reviewer run visible or retried. That is BLO-34577. Test: server/src/__tests__/pr-review-gate-verdict.test.ts. Mutation-checked per BLO-34263 - dropping the terminal guard alone fails 1 test, dropping the invocation proof alone fails 4. Co-Authored-By: Claude <noreply@anthropic.com>
|
This PR is clean at its current head but still has an outstanding code-owner review request (allyblockcast). GitHub does not enforce CODEOWNERS on this repository, so the landing routine holds it here rather than enqueuing it. |
… (BLO-34812) Base #1932 landed on master as a squash, so this branch is retargeted to master. Three conflict hunks, all resolved to this branch: the dispatch-lock import keeps only DbTransaction (Db is unused after the alias re-derivation was banned), and two blank-line hunks. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* refactor(db): export DbTransaction and drop 20 re-derivations (BLO-34656) @paperclipai/db had no name for a caller's open transaction handle, so 20 sites across 18 files re-derived Parameters<Parameters<Db["transaction"]>[0]>[0] under five different local names; heartbeat.ts declared it twice in one file. Export DbTransaction from packages/db and import it everywhere. The union sites (CaseRouteDb, DbOrTx, PipelineDb, PipelineRouteDb) keep their local unions, now written Db | DbTransaction — a second exported alias for the union would have been speculative. Type-only: the diff is imports and type aliases, no value-level change. * chore(ci): enforce the DbTransaction alias ban instead of commenting it (BLO-34812) BLO-34656 swept 21 re-derivations of the drizzle transaction-handle type out of 20 files and left a comment in packages/db/src/client.ts as the only thing holding the count at zero. Those 21 copies are the evidence that a comment does not hold. Adds scripts/check-db-transaction-alias.mjs, wired into the pr.yml `policy` job alongside the other check-*.mjs gates. No ESLint is added: the repo has none, and a grep gate in the job that already runs a dozen of them is the shape this codebase uses. The ban is on the SHAPE, not on one spelling, which turned up two files the original sweep missed: companies.ts and heartbeat.ts spell it `typeof db.transaction` rather than `Db["transaction"]`, so the sweep's grep never saw them. Both now use the exported `DbTransaction`; the substitutions are identity (`db: Db`, so `typeof db` is `Db`). It deliberately does not fire on nested `Parameters<...>` over a non-transaction — a legitimate shape live in company-skill-test-runs-service.test.ts — nor on the two-alias split that defines the replacement. Also drops the `Db` import left unused in pr-review-dispatch-lock.ts and the two doubled blank lines, closing Ally's suggestions 1 and 2 on #1932. * fix(ci): carve the DbTransaction definition site out by path, not by shape Ally Important (scripts/check-db-transaction-alias.mjs:36): the nested Parameters<Parameters<...>> pattern let the two-line split from packages/db/src/client.ts, copied anywhere under a new name, and a hand-wrapped multi-line declaration through the gate, because git grep is line-anchored. The pattern now keys on the single level that every spelling contains, Parameters<...transaction...>[0], and client.ts is excluded by pathspec instead. The trailing [0] keeps a test double that spreads (...args: Parameters<typeof db.transaction>) unflagged; two such mocks exist in server/src/__tests__. Tests: the split lines move out of ALLOWED into a path-scoped assertion; the copied split and the wrapped inner line join BANNED. Verified by mutation: a fixture carrying both forms fails the scan, the clean tree passes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(server): import DbTransaction in the two files master added after the sweep (BLO-34812) check-db-transaction-alias.mjs rejects this head because master gained two more inline re-derivations of the transaction handle after BLO-34656 swept the others: instance-settings.ts and pr-issue-backlink-lock.ts. Both now import the exported DbTransaction from @paperclipai/db, the same way cases.ts, pipelines.ts and agent-invokability.ts already do. The guard's own tests still pass and the server typechecks. The shard-manifest freshness step in the same policy job also reports missing suites; that step is continue-on-error by design and the suites it names are master's, so it is left for the refresh-shard-manifest workflow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Staff Engineer <staff-engineer@paperclip.blockcast.net> Co-authored-by: Omar Ramadan <oramadan@blockcast.net> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Omar Ramadan <omar@blockcast.net>
Thinking Path
Linked Issues or Issue Description
readInstanceSettingsOnwidening, BLO-34471). Ally called it "the third copy"; the measured count was 21 at that head, 20 at this one.What Changed
packages/db/src/client.ts: exportDbTransaction. Written as two aliases (DbTransactionCallback→DbTransaction) rather than the one-line nested-Parametersform, so the string this PR removes appears nowhere in the tree — that is what makes the AC-2 grep below literally zero rather than "one, the definition".packages/db/src/index.ts: re-export it.heartbeat.tsloses both of its declarations (HeartbeatTxat:15,DbTransactionat:587) and now uses the single imported name.CaseRouteDb,DbOrTx,PipelineDb,PipelineRouteDb) keep their local unions, now spelledDb | DbTransaction. A second exportedDbOrTransactionalias was considered and skipped as speculative — the issue left that call to implementation.Verification
pnpm -r typecheck→ exit 0 across every workspace package (server, ui, cli, packages, plugins). For a type-only change that is the whole load-bearing check: if any of the 20 sites resolved to a different type than the export, it fails here.import type, atypealias, or the comment on the new export. No value-level expression is touched. Verified mechanically:pnpm test:runandpnpm build. The suite needs a database and the change has no runtime surface to exercise; the fourGeneral tests (server N/4)CI shards cover it, and per the issue's own verifying signal no new test is warranted — a test with no failing mutation would be a comment (BLO-34263).Risks
Low. Type-only, no migration, no runtime path. The failure mode a refactor like this can have — a site whose local alias silently meant something other than the exported type — is exactly what
pnpm -r typecheckcatches, and it is green.Model Used
claude-opus-4-8), extended thinking, tool use, via Claude Code / Paperclip Staff Engineer agent.Checklist
Fixes: #/Closes #/Refs #OR (b) described the issue in-PR following the relevant issue templatepnpm -r typecheck(green); did not run the vitest suite (needs a DB, no runtime surface here). CI shards cover it.