Skip to content

Commit 24b0f87

Browse files
committed
fix(run-store): prefer task_run_v2 on cross-table single-row reads
When a non-id predicate matches a row in both physical tables, findFirstAcrossTables now returns the v2 copy instead of legacy. Under this PR a run is in exactly one table (createRun routes by id format), so this is a no-op today; it forward-aligns with the later slow legacy to v2 migration, which copies a run into task_run_v2 (the canonical, operated-on copy) before operating. A comment in findRuns marks the matching dedup-by-id work for that migration PR.
1 parent 5282e01 commit 24b0f87

1 file changed

Lines changed: 29 additions & 11 deletions

File tree

internal-packages/run-store/src/PostgresRunStore.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,18 @@ export class PostgresRunStore implements RunStore {
8080

8181
/**
8282
* Read a single row matching a non-id predicate from BOTH physical tables.
83-
* A run lives in exactly one table (chosen by its id format), so a key-based
84-
* predicate (idempotency key, "has this env any runs") can match a row in
85-
* either. Query both in parallel and return the first match — at most one
86-
* side is non-null, and legacy is preferred for a stable result if a
87-
* predicate ever matches both. `task_run_v2` is an identical clone of
88-
* `TaskRun`, so the SAME args (select/include and the security-scoping
89-
* `where`) run unchanged against either delegate.
83+
* A key-based predicate (idempotency key, "has this env any runs") can match
84+
* a row in either table. Query both in parallel and return the match,
85+
* preferring `task_run_v2` when both are non-null.
86+
*
87+
* Today a run lives in exactly one table (createRun routes by id format), so
88+
* at most one side is non-null and the preference never bites. The later
89+
* slow legacy->v2 migration copies a run into task_run_v2 before operating on
90+
* it, so it transiently lives in BOTH tables with the v2 copy as the
91+
* canonical/operated-on one; preferring v2 returns the current row, not the
92+
* stale legacy source. `task_run_v2` is an identical clone of `TaskRun`, so
93+
* the SAME args (select/include and the security-scoping `where`) run
94+
* unchanged against either delegate.
9095
*/
9196
async #findFirstAcrossTables(
9297
prisma: ReadClient,
@@ -100,7 +105,7 @@ export class PostgresRunStore implements RunStore {
100105
v2Model.findFirst({ where, ...args }),
101106
]);
102107

103-
return legacyRun ?? v2Run;
108+
return v2Run ?? legacyRun;
104109
}
105110

106111
async createRun(
@@ -871,9 +876,22 @@ export class PostgresRunStore implements RunStore {
871876
return model.findMany(args as Prisma.TaskRunFindManyArgs);
872877
}
873878

874-
// BOTH tables in play. Offset pagination can't be expressed across two
875-
// tables (applying `skip` to each skips N rows from its own result, not N
876-
// from the merged result), so reject it rather than silently double-skip.
879+
// BOTH tables in play.
880+
//
881+
// FORWARD-LOOKING (slow legacy->v2 migration, a later stage): that migration
882+
// copies a run into task_run_v2 before operating on it, so a run can briefly
883+
// live in BOTH tables. When that lands, the cross-table reads below (both the
884+
// ordered #mergeOrdered path AND the unordered concat) must DEDUP BY id,
885+
// keeping the canonical v2 copy, or a doubly-present run is returned twice.
886+
// Dedup needs `id` forced into the projection (and stripped when the caller
887+
// didn't select it), and the "v2 wins" policy is part of the copy protocol,
888+
// so it belongs with the migration PR that introduces the overlap. Today
889+
// createRun routes by id format, so no run is in both tables and concatenation
890+
// is already duplicate-free.
891+
//
892+
// Offset pagination can't be expressed across two tables (applying `skip` to
893+
// each skips N rows from its own result, not N from the merged result), so
894+
// reject it rather than silently double-skip.
877895
if (args.skip !== undefined) {
878896
throw new Error(
879897
"RunStore.findRuns: `skip` (offset pagination) is not supported across the legacy TaskRun " +

0 commit comments

Comments
 (0)