Skip to content

Commit af6c315

Browse files
d-csclaude
andcommitted
fix(webapp): hide admin Debug-Run button for buffered runs + break SpanRun type cycle
Two coupled changes that must land together: 1. The Debug Run dialog's loader (resources.taskruns.$runParam.debug.ts) looks up the run by friendlyId in PG, so it returns 404 for buffered runs and the dialog renders the global "404: Page not found" view instead of the debug surface. Until the debug loader gains its own buffered-aware path, gate the button on the synthetic SpanRun's new `isBuffered` flag — set true in the buffer fallback, false on the PG path, checked at the AdminDebugRun render site in the spans route. 2. Introducing the `isBuffered` literal would alone trigger the long-standing SpanRun circular type alias error: SpanRun is inferred from `SpanPresenter.call`'s return, which routes through `buildSyntheticSpanRun` on the mollifier-buffered branch — and that helper is annotated `Promise<SpanRun>`. The literal narrowing made the cycle TS-visible ("Type alias 'Result' circularly references itself", surfacing as 7 cascading errors across SpanPresenter and the spans route). Fix the cycle by grounding SpanRun in the PG-path `getRun` method (the canonical source for the shape) so the synthetic helper's annotation no longer feeds back into SpanRun's definition. Span continues to be derived off `call` because its path through `#getSpan` has no synthetic indirection and no cycle. Squashed because applying step 1 without step 2 leaves the branch typecheck-broken. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 372fe78 commit af6c315

3 files changed

Lines changed: 16 additions & 2 deletions

File tree

apps/webapp/app/presenters/v3/SpanPresenter.server.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,21 @@ function extractPromptSpanData(properties: Record<string, unknown>): PromptSpanD
7474
};
7575
}
7676

77+
// SpanRun is grounded in the PG-path `getRun` method rather than
78+
// inferred from `call`'s return type. The buffered branch of `call`
79+
// routes through `buildSyntheticSpanRun`, and that helper is annotated
80+
// `Promise<SpanRun>` — if SpanRun were derived from `call` it would
81+
// close a loop TS no longer tolerates ("Type alias 'Result' circularly
82+
// references itself"). `getRun` is the canonical source for the shape
83+
// (the synthetic helper just rebuilds the same shape from a buffer
84+
// snapshot), and it doesn't recurse, so grounding here breaks the
85+
// cycle while keeping Span available off `call` (Span's path through
86+
// `#getSpan` has no synthetic indirection).
87+
export type SpanRun = NonNullable<
88+
Awaited<ReturnType<InstanceType<typeof SpanPresenter>["getRun"]>>
89+
>;
7790
type Result = Awaited<ReturnType<SpanPresenter["call"]>>;
7891
export type Span = NonNullable<NonNullable<Result>["span"]>;
79-
export type SpanRun = NonNullable<NonNullable<Result>["run"]>;
8092
type FindRunResult = NonNullable<
8193
Awaited<ReturnType<InstanceType<typeof SpanPresenter>["findRun"]>>
8294
>;
@@ -406,6 +418,7 @@ export class SpanPresenter extends BasePresenter {
406418
traceId: run.traceId,
407419
spanId: run.spanId,
408420
isCached: !!linkedRunId,
421+
isBuffered: false,
409422
machinePreset: machine?.name,
410423
taskEventStore: run.taskEventStore,
411424
externalTraceId,

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@ function RunBody({
10971097
{run.isCached ? "Jump to original run" : "Focus on run"}
10981098
</LinkButton>
10991099
)}
1100-
<AdminDebugRun friendlyId={run.friendlyId} />
1100+
{!run.isBuffered && <AdminDebugRun friendlyId={run.friendlyId} />}
11011101
</div>
11021102
<div className="flex items-center">
11031103
{run.logsDeletedAt === null ? (

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ export async function buildSyntheticSpanRun(args: {
177177
traceId: run.traceId ?? "",
178178
spanId: run.spanId ?? "",
179179
isCached: false,
180+
isBuffered: true,
180181
machinePreset: narrowMachinePreset(run.machinePreset),
181182
taskEventStore: "taskEvent",
182183
externalTraceId: undefined,

0 commit comments

Comments
 (0)