Skip to content

Commit 2936dfc

Browse files
fix(workflows): retain safe trace output fallback
1 parent e92b6ab commit 2936dfc

2 files changed

Lines changed: 60 additions & 4 deletions

File tree

apps/sim/lib/logs/execution/trace-store.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,66 @@ describe('projectExecutionDataForDisplay', () => {
136136
expect(JSON.stringify([...materialized.blockOutputs])).not.toContain('12345678')
137137
})
138138

139+
it('falls back to projected trace output for a requested block missing from partial state', async () => {
140+
const emptyProvenance = {
141+
version: 1 as const,
142+
complete: true,
143+
entries: [],
144+
scope: { userId: 'user-1', workspaceId: 'workspace-1' },
145+
}
146+
const materialized = await materializeExecutionDataForDisplayWithBlockOutputs(
147+
{
148+
secretProjectionVersion: SECRET_PROJECTION_VERSION,
149+
traceSpans: [
150+
{
151+
id: 'span-1',
152+
blockId: 'trace-only',
153+
name: 'Trace-only block',
154+
type: 'function',
155+
duration: 1,
156+
startTime: '2026-08-11T00:00:00.000Z',
157+
endTime: '2026-08-11T00:00:00.001Z',
158+
output: { result: 'trace-output' },
159+
},
160+
],
161+
executionState: {
162+
resolvedSecretTraceProvenance: emptyProvenance,
163+
blockStates: {
164+
'state-only': {
165+
output: { result: 'state-output' },
166+
resolvedSecretTraceProvenance: emptyProvenance,
167+
},
168+
},
169+
},
170+
},
171+
CONTEXT,
172+
['state-only', 'trace-only']
173+
)
174+
175+
expect(materialized.blockOutputs).toEqual(
176+
new Map([
177+
['trace-only', { result: 'trace-output' }],
178+
['state-only', { result: 'state-output' }],
179+
])
180+
)
181+
})
182+
139183
it('omits state-only block outputs that lack usable secret provenance', async () => {
140184
const materialized = await materializeExecutionDataForDisplayWithBlockOutputs(
141185
{
142186
secretProjectionVersion: SECRET_PROJECTION_VERSION,
187+
traceSpans: [
188+
{
189+
id: 'span-1',
190+
blockId: 'function-1',
191+
name: 'Function 1',
192+
type: 'function',
193+
duration: 1,
194+
startTime: '2026-08-11T00:00:00.000Z',
195+
endTime: '2026-08-11T00:00:00.001Z',
196+
output: { token: 'trace-fallback' },
197+
},
198+
],
143199
executionState: {
144200
blockStates: {
145201
'function-1': { output: { token: 'unproven-secret' } },

apps/sim/lib/logs/execution/trace-store.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,11 @@ export async function materializeExecutionDataForDisplayWithBlockOutputs(
296296

297297
const executionState = readRecord(materialized.executionState)
298298
const blockStates = readRecord(executionState?.blockStates)
299+
const displaySource = displayData as FunctionalExecutionDataSource
299300
if (!blockStates) {
300301
return {
301302
executionData: displayData,
302-
blockOutputs: collectFunctionalBlockOutputs(
303-
displayData as FunctionalExecutionDataSource | undefined
304-
),
303+
blockOutputs: collectFunctionalBlockOutputs(displaySource),
305304
}
306305
}
307306

@@ -310,13 +309,14 @@ export async function materializeExecutionDataForDisplayWithBlockOutputs(
310309
executionState?.[RESOLVED_SECRET_PROVENANCE_KEY],
311310
'traceStore.blockOutputRunProvenance'
312311
)
313-
const blockOutputs = new Map<string, unknown>()
312+
const blockOutputs = collectFunctionalBlockOutputs({ traceSpans: displaySource.traceSpans })
314313
const projectionStore = createReadOnlyProjectionStore(context)
315314

316315
for (const blockId of new Set(blockIds)) {
317316
const blockState = readRecord(blockStates[blockId])
318317
if (!blockState || blockState.output === undefined) continue
319318

319+
blockOutputs.delete(blockId)
320320
const hasExactProvenance = Object.hasOwn(blockState, RESOLVED_SECRET_PROVENANCE_KEY)
321321
const registry = hasExactProvenance
322322
? await importResolvedSecretTraceRegistry(

0 commit comments

Comments
 (0)