Calculation and CronTimer nodes (and any other node types not on an allowlist) showed no name label on the canvas even when the user had given them an explicit name. The name was present in node.name() but AnimatedNodeVisibility skipped the NamePill composable for those types. Demo/automation pipelines also had no stable way to open a specific node’s editor programmatically; a patched recording jar was required.
AnimatedNodeVisibility branched on a hardcoded allow-list of KrillApp types to decide whether to render the NamePill. The list was never updated as new node types (Calculation, CronTimer, etc.) were added. The else-branch rendered the icon with no label at all, regardless of whether the node had a user-supplied name. For the programmatic-editor gap, there was no production path from an external signal to ScreenCore.selectNode(id) + viewEditor().
AnimatedNodeVisibility (composeApp/src/commonMain/kotlin/krill/zone/app/NodeItem.kt). All node types now share one rendering path: the NamePill is shown unconditionally when node.name() is non-blank. The isNotBlank() guard was already present, so unnamed/default-titled nodes remain visually clean.KRILL_DEMO_CONTROL env-gated control file hook in composeApp/src/desktopMain/kotlin/krill/zone/main.kt. When set, a daemon thread polls the named file every 100 ms and executes select:<nodeId> (→ selectNode + viewEditor) or reset commands via the Koin-resolved ScreenCore. Production is unaffected when the env var is unset.KrillApp subtype, sweep NodeItem.kt (and IconManager.kt, NodeSummaryAndEditor.kt) for hardcoded type allow-lists. An allow-list that must be manually kept in sync with a sealed hierarchy is always a latent gap.