From cc1e1892ade08e45af7d58ca1bb5af8c1c91c561 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 16 Jun 2026 18:31:20 +0200 Subject: [PATCH] fix: deploy pipeline drafts with freshly-inferred assets, not a stale snapshot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Save all" spread `...draft.script` into createScript, which carries a `assets` snapshot that isn't refreshed when the body is edited. So a renamed/removed output (e.g. an old `CREATE TABLE exciting_en32z9` later changed to `exciting_880909`) was re-deployed as a phantom write edge and lingered as an orphan asset on the graph — shown with no producer, and shifting position on click as the graph re-derived. saveDraft now re-runs inferAssets on the current body and passes the result as `assets`, overriding the snapshot — mirroring the per-pane save. The backend clears+reinserts from the sent set, so a re-deploy drops the stale rows. Verified: deploying with the fresh asset set removes the orphan from the graph. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../(logged)/pipeline/[folder]/+page.svelte | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte b/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte index 8025216921..3b83e4cadb 100644 --- a/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte @@ -789,6 +789,19 @@ // per-pane save uses). The createScript call is the real // validation gate — if the body is broken it'll reject there. } + // Re-infer the asset lineage from the CURRENT body. The draft's + // `script.assets` is a snapshot that isn't refreshed on edit, so without + // this a renamed/removed output (e.g. an old `CREATE TABLE foo`) would + // be re-deployed as a phantom write edge and linger as an orphan asset. + // Mirrors the per-pane save, which sends live-inferred assets. + let assets: AssetWithAltAccessType[] = [] + try { + const inferred = await inferAssets(script.language, script.content) + if (inferred?.status !== 'error') assets = (inferred?.assets ?? []) as AssetWithAltAccessType[] + } catch { + // Same fallback as above — an unparsable body deploys with no + // lineage rather than the stale snapshot. + } await ScriptService.createScript({ workspace: ws, requestBody: { @@ -805,7 +818,10 @@ is_template: false, tag: script.tag, kind: script.kind as Script['kind'] | undefined, - lock: undefined + lock: undefined, + // Freshly inferred above — overrides the stale snapshot carried + // by `...script`, so the deployed lineage matches the body. + assets: assets as any } }) }