diff --git a/frontend/src/lib/components/assets/AssetGraph/AssetGraphDetailsPane.svelte b/frontend/src/lib/components/assets/AssetGraph/AssetGraphDetailsPane.svelte index 425565353a..beb160b234 100644 --- a/frontend/src/lib/components/assets/AssetGraph/AssetGraphDetailsPane.svelte +++ b/frontend/src/lib/components/assets/AssetGraph/AssetGraphDetailsPane.svelte @@ -578,11 +578,9 @@ const orig = latest && latest.path === captured.path ? latest : origAtRegister if (!orig || orig.path !== captured.path) return if ((captured.content ?? '') === (orig.content ?? '')) return - // The effect can re-run mid-save — after createScript resolved - // but before the refetch lands — with `orig` still holding the - // pre-deploy version. The buffer isn't "unsaved edits" then, it - // IS the new deployed head; emitting would resurrect it as a - // phantom draft identical to what was just deployed. + // Mid-save re-runs (createScript resolved, refetch pending) see a + // pre-deploy `orig`; the buffer IS the new deployed head then, and + // emitting would resurrect it as a phantom draft. if ( deployedFromPane?.path === captured.path && (captured.content ?? '') === deployedFromPane.content @@ -730,11 +728,9 @@ } catch { sendUserToast(`Could not parse code, are you sure it is valid?`, true) } - // Pin the exact content this deploy ships: the editor stays live during - // the network round-trip, so `script.content` can advance past what was - // sent — `deployedFromPane` must record the shipped version, not the - // buffer at response time, or mid-deploy keystrokes match the guard and - // are never promoted to a draft. + // Pin the shipped content: the editor stays live during the round-trip, + // so recording the buffer at response time would make mid-deploy + // keystrokes match the phantom-draft guard and never promote to a draft. const contentAtDeploy = script.content ?? '' const newHash = await ScriptService.createScript({ workspace, diff --git a/frontend/src/lib/components/assets/AssetGraph/resolveGraph.ts b/frontend/src/lib/components/assets/AssetGraph/resolveGraph.ts index 8ee0ca53d7..c353494a00 100644 --- a/frontend/src/lib/components/assets/AssetGraph/resolveGraph.ts +++ b/frontend/src/lib/components/assets/AssetGraph/resolveGraph.ts @@ -411,12 +411,9 @@ function seedAccumulator(input: ResolveGraphInput, ctx: ResolveContext): Accumul } } -/** - * The write output(s) a `// materialize ` annotation declares: the - * target itself, plus — for a managed scd2 materialize — the `_current` - * companion view (mirrors the deploy path), so a consumer of only the view - * links back to this producer instead of orphaning. - */ +/** The write output(s) a `// materialize ` annotation declares: the + * target, plus the scd2 `_current` companion view (deploy-path mirror) + * so a consumer of only the view links back instead of orphaning. */ function materializeOuts( parsed: PipelineAnnotations ): Array<{ kind: AssetKind; path: string; derivedFrom?: string }> { @@ -626,11 +623,9 @@ function seedDraftOverlays(acc: Accumulator, input: ResolveGraphInput) { if (!hasTriggerAsset) assets.push({ kind: a.kind, path: a.path }) } // Auto-derived cascade edges (backend parity): a ducklake/s3 read wires - // the edge from the body alone. Reads reuse the tier above; writes come - // from the active draft's live inference, else the captured snapshot / - // session cache. The open buffer's derived edges are re-computed - // authoritatively in applyLiveBufferOverlay (which strips this path's - // seeded triggers first), same as the explicit `// on` triggers above. + // the edge from the body alone. Reads reuse the tier above; writes use + // live inference, else the captured snapshot / session cache. The open + // buffer's edges are recomputed authoritatively in applyLiveBufferOverlay. const draftWrites = liveForThisDraft ? extractWrites(liveBodyAssets.assets) : (d.outputAssets ?? inferredWritesByPath.get(path) ?? []) @@ -731,12 +726,10 @@ function applyLiveBufferOverlay(acc: Accumulator, input: ResolveGraphInput, ctx: } } } - // Lineage overlay for an open SAVED script. seedDraftOverlays owns drafts, - // but a deployed script's unsaved edits are only promoted to a draft on - // pane teardown — until then the buffer's lineage lives here. staleForOpen - // already dropped the base edges the buffer no longer references; this adds - // the ones it now does. Without it, retargeting `// materialize` (or a body - // write/read) shows no output edge until the user clicks away. + // Lineage overlay for an open SAVED script (drafts are seedDraftOverlays'). + // Unsaved edits only become a draft on pane teardown; until then this is + // the buffer's lineage source — staleForOpen dropped the no-longer-referenced + // base edges, and without this block the new refs show nothing until deselect. if (!ctx.draftedPaths.has(livePath)) { for (const out of materializeOuts(liveAnnotations.annotations)) { pushWriteOut(acc, livePath, out) @@ -808,11 +801,9 @@ function overlayInferredLineage(acc: Accumulator, input: ResolveGraphInput) { for (const [scriptPath, refs] of byPath) { if (drafts.has(scriptPath)) continue for (const a of refs) { - // Dedup against the ACCUMULATED edges, not just base: for the open - // script these same refs may already be overlaid by - // applyLiveBufferOverlay (which feeds the maps on the route page), - // and a duplicate would collide on the canvas's endpoint-derived - // edge ids. + // Dedup against the ACCUMULATED edges, not just base: the open + // script's refs may already be overlaid by applyLiveBufferOverlay, + // and a duplicate collides on the canvas's endpoint-derived edge ids. const hasEdge = edges.some( (e) => e.runnable_path === scriptPath &&