diff --git a/frontend/src/lib/components/recording/PipelineRecordingReplay.svelte b/frontend/src/lib/components/recording/PipelineRecordingReplay.svelte
index 033ff211fe..49b3fbfbd4 100644
--- a/frontend/src/lib/components/recording/PipelineRecordingReplay.svelte
+++ b/frontend/src/lib/components/recording/PipelineRecordingReplay.svelte
@@ -261,12 +261,24 @@
return (shownStatuses[selection.path] ?? finalStatuses[selection.path])?.status
})
- // Output (args/logs/result) vs the step's source code, for a runnable node.
- let runnableTab = $state<'output' | 'code'>('output')
+ // The step's source code vs its output (args/logs/result), for a runnable node.
+ let runnableTab = $state<'output' | 'code'>('code')
let selectedCode = $derived.by(() => {
if (selection?.kind !== 'runnable') return undefined
return recording.codes?.[selection.path]
})
+ // Land on the code, since that is what the step *is* — but fall back to Output
+ // when the recording carries none, so a recording made before `codes` existed
+ // does not open on an empty pane. Depends on the selected path alone: the
+ // lookup is untracked so a tab the viewer picked by hand survives until they
+ // move to another step, rather than resetting if the recording object changes.
+ $effect(() => {
+ const path = selection?.kind === 'runnable' ? selection.path : undefined
+ if (path === undefined) return
+ untrack(() => {
+ runnableTab = recording.codes?.[path] ? 'code' : 'output'
+ })
+ })
// Recorded data-sample for a selected asset node (ducklake/datatable).
let selectedAssetSample = $derived.by(() => {
@@ -382,8 +394,8 @@
on:selected={(e) => (runnableTab = e.detail)}
>
{#snippet children({ item })}
-
+
{/snippet}