Shared node changes rebuild the flows whose published copy uses them, not their drafts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
This commit is contained in:
2026-10-14 23:34:47 +02:00
co-authored by Claude Opus 5.5
parent f8d14be8e6
commit 1735a3651e
3 changed files with 35 additions and 4 deletions
+2 -1
View File
@@ -837,7 +837,8 @@ class FlowController:
async def reload_lib_users(self, ref: str) -> list[str]:
"""Rebuild the flows running a shared node whose source has changed."""
flows = sorted({usage.split(".", 1)[0] for usage in self.store.usages(ref)})
usages = self.store.usages(ref, draft=False)
flows = sorted({usage.split(".", 1)[0] for usage in usages})
for flow in flows:
await self.reload_flow(flow)
return flows
+7 -3
View File
@@ -355,12 +355,16 @@ class FlowStore:
self._set_source_ref(flow, node_id, None)
self._commit(f"Unshare node '{flow}.{node_id}'")
def usages(self, lib_name: str) -> list[str]:
"""Every ``flow.node`` pointing at this shared source."""
def usages(self, lib_name: str, draft: bool = True) -> list[str]:
"""Every ``flow.node`` pointing at this shared source.
Read from the drafts the editor shows, or with ``draft`` off from the
published flows the engine runs.
"""
used = []
for name in self.list_flows():
try:
definition = self.read_flow(name, draft=True)
definition = self.read_flow(name, draft=draft)
except FlowNotFound:
continue
used += [
+26
View File
@@ -1,9 +1,11 @@
"""Nodes shared across flows: one source, many instances."""
import asyncio
from pathlib import Path
import pytest
from fluksio.flow.controller import FlowController
from fluksio.flow.messages import MessageSpec
from fluksio.flow.schemas import FlowDef, NodeDef
from fluksio.flow.store import FlowStore, LibExists, LibNotFound
@@ -67,6 +69,30 @@ def test_a_second_flow_can_use_the_same_source(store: FlowStore):
assert store.usages("read_temp") == ["cooling.sensor", "heating.sensor"]
def test_a_shared_source_change_rebuilds_only_what_is_published(store: FlowStore):
store.write_flow(a_flow())
store.write_node_source("heating", "sensor", SOURCE)
store.share_node("heating", "sensor", "read_temp")
# Published with the shared node, which the draft has since dropped.
store.publish_flow("heating", store.read_flow("heating", draft=True).version)
store.unshare_node("heating", "sensor")
# Shared in a draft that was never published.
cooling = a_flow("cooling")
cooling.nodes[0].source_ref = "read_temp"
store.write_draft(cooling, 0)
controller = FlowController(store)
rebuilt: list[str] = []
async def reload_flow(name: str) -> None:
rebuilt.append(name)
controller.reload_flow = reload_flow # type: ignore[method-assign]
asyncio.run(controller.reload_lib_users("read_temp"))
assert rebuilt == ["heating"]
def test_a_shared_name_is_not_taken_twice(store: FlowStore):
store.write_flow(a_flow())
store.write_node_source("heating", "sensor", SOURCE)