Skip to content

Commit b76ef34

Browse files
d-csclaude
andcommitted
fix(webapp): set completedAt for FAILED synthetic span runs
Symmetric fix to the just-applied `ApiRetrieveRunPresenter` change. PG-resident SYSTEM_FAILURE rows always have `completedAt` populated; the synthetic span run was returning null for FAILED, so the run-detail panel and any caller using `isFinished && completedAt` saw a finished run with no completion timestamp. Fall back to `run.createdAt` when `isFailed` is true (the buffer entry has no separate failedAt — createdAt is the best proxy for when the terminal state landed). Regression locked in `mollifierSyntheticSpanRun.test.ts` — the FAILED test now asserts `completedAt === NOW`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d4a4ae9 commit b76ef34

2 files changed

Lines changed: 14 additions & 1 deletion

File tree

apps/webapp/app/v3/mollifier/syntheticSpanRun.server.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,14 @@ export async function buildSyntheticSpanRun(args: {
102102
updatedAt: run.cancelledAt ?? run.createdAt,
103103
delayUntil: run.delayUntil ?? null,
104104
expiredAt: null,
105-
completedAt: run.cancelledAt ?? null,
105+
// Symmetric with `ApiRetrieveRunPresenter` — FAILED buffered runs
106+
// must surface a non-null `completedAt` so the run-detail panel
107+
// (and any caller checking `isFinished && completedAt`) doesn't
108+
// render a finished run with no completion timestamp. PG-resident
109+
// SYSTEM_FAILURE rows always have completedAt set; the buffer
110+
// entry has no separate failedAt, so we fall back to createdAt
111+
// as the best proxy for when the terminal state landed.
112+
completedAt: run.cancelledAt ?? (isFailed ? run.createdAt : null),
106113
logsDeletedAt: null,
107114
ttl: run.ttl ?? null,
108115
taskIdentifier: run.taskIdentifier ?? "",

apps/webapp/test/mollifierSyntheticSpanRun.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ describe("buildSyntheticSpanRun", () => {
182182
type: "STRING_ERROR",
183183
raw: "GATE_REJECTED: buffer rejected the run",
184184
});
185+
// PG-resident SYSTEM_FAILURE rows always have completedAt set;
186+
// mirror that on the synth path so callers checking
187+
// `isFinished && completedAt` don't render a finished run with
188+
// no completion timestamp. The buffer entry has no separate
189+
// failedAt, so createdAt is the best-available proxy.
190+
expect(synth.completedAt).toEqual(NOW);
185191
});
186192

187193
it("flags the synthetic run as 'not cached' since cache lookup did not match it", async () => {

0 commit comments

Comments
 (0)