diff --git a/frontend/src/lib/components/assets/AssetGraph/resolveGraph.test.ts b/frontend/src/lib/components/assets/AssetGraph/resolveGraph.test.ts index 2663c52e28..6d38a8c119 100644 --- a/frontend/src/lib/components/assets/AssetGraph/resolveGraph.test.ts +++ b/frontend/src/lib/components/assets/AssetGraph/resolveGraph.test.ts @@ -1322,6 +1322,35 @@ describe('pipelineNodeErrors', () => { ).toBe(0) }) + it('does not count a flow write as starting an asset-triggered script', () => { + const g = baseGraph({ + assets: [{ kind: 'ducklake', path: 'main/raw' }], + runnables: [ + { path: 'f/x/reader', usage_kind: 'script', in_pipeline: true }, + { path: 'f/x/loader', usage_kind: 'flow' } + ] as any, + edges: [ + { + runnable_path: 'f/x/loader', + runnable_kind: 'flow', + asset_kind: 'ducklake', + asset_path: 'main/raw', + access_type: 'w' + } + ], + triggers: [ + { + trigger_kind: 'asset', + asset_kind: 'ducklake', + asset_path: 'main/raw', + runnable_kind: 'script', + runnable_path: 'f/x/reader' + } + ] + } as any) + expect(pipelineNodeErrors(g, new Map()).untriggered.get('f/x/reader')).toBe('unwritten-inputs') + }) + it('clears a subscription the workspace writes outside the pipeline', () => { const errors = pipelineNodeErrors( graph, diff --git a/frontend/src/lib/components/assets/AssetGraph/resolveGraph.ts b/frontend/src/lib/components/assets/AssetGraph/resolveGraph.ts index 8c48e4d0fa..b178de3387 100644 --- a/frontend/src/lib/components/assets/AssetGraph/resolveGraph.ts +++ b/frontend/src/lib/components/assets/AssetGraph/resolveGraph.ts @@ -339,8 +339,7 @@ export type PipelineNodeErrors = { * Nodes the pipeline cannot work with, with the reason. Assets (keyed * `kind:path`): one nothing uses at all. Scripts (keyed by path): one * subscribed (`// on `) to an asset nothing writes, in the pipeline or, - * per `writtenElsewhere`, anywhere else in the workspace (asset triggers fire - * on any write), since the subscription can never fire; the asset itself is + * per `writtenElsewhere`, by a script anywhere else in the workspace, since the subscription can never fire; the asset itself is * fine, and is reported in `unwritten`. A body read of an external asset is fine and is not passed here: * only the explicit `// on` annotations, per script path, count as subscriptions. */ @@ -350,9 +349,12 @@ export function pipelineNodeErrors( writtenElsewhere: ReadonlySet = new Set() ): PipelineNodeErrors { const referenced = referencedAssetKeys(graph) + // Only a script's write fires an asset trigger: a flow's never does. const written = new Set( graph.edges - .filter((e) => e.access_type === 'w' || e.access_type === 'rw') + .filter( + (e) => e.runnable_kind === 'script' && (e.access_type === 'w' || e.access_type === 'rw') + ) .map((e) => `${e.asset_kind}:${e.asset_path}`) ) for (const k of writtenElsewhere) written.add(k) diff --git a/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte b/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte index bd6c799c08..09bd462cb8 100644 --- a/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte @@ -1,4 +1,5 @@