prototype: flows:started + diff distinguishes dashboardAPI subtree #32
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type: spike / prototype
Depends on: none
Estimate: S (½ day)
Slice — layers touched
Node-RED runtime → dashboardAPI adapter → throwaway test harness.
Context
PRD Open Question O-1 (prd). The
flows:startedruntime event is undocumented but readable in Node-RED source; the payload's{type, diff}shape needs verifying with real deploys before F-1 can be implemented.Scope
RED.events.on('flows:started')and logstypeanddiff.added/changed/removed.diffcleanly identify "this subtree changed" vs. "an unrelated flow changed.".prototypes/and is gitignored. Findings written back as a comment on this issue.Out of scope
nodes-started(deprecated per research).Acceptance criteria
diff.<field>.includes(<our nodeId>) || diff.<field>.includes(<any child id>)" — or, if the diff doesn't carry enough info, the fallback predicate.Notes
Node-RED source:
packages/.../runtime/lib/flows/index.js(~lines 483–640). Run via/prototypeskill.Spike findings: confirmed — use
flows:started+diffas designedVerdict: confirmed.
What I did
Installed a throwaway custom Node-RED node (
.prototypes/spike-flows-started/, gitignored) into the runningevolv-noderedcontainer that subscribes toflows:starting/started/stopping/stoppedand appends each event to/data/spike-events.logwith the fulldiffcontent. Then drove 5 deploys via the admin API (POST /flowswithNode-RED-API-Version: v2andNode-RED-Deployment-Type: full|nodes|flows) and inspected the resulting payloads.diff payload shape
payload.diffis always present (on deploys; empty on cold startup) with exactly these keys:All six are arrays of node ids (tab nodes included). On startup-from-cold the whole
diffobject is empty (no keys).Per-deploy-type evidence
Two test tabs (Spike A, Spike B) each with a
debugnode. Ran 5 deploys:diff.addeddiff.changed[tab_a, tab_b, dbg_a, dbg_b][tab_a, tab_b]dbg_bonly[][dbg_b, tab_b]dbg_bagain[][dbg_b, tab_b]dbg_a(different tab)[][dbg_a, tab_a][][]removed,rewired,linked,flowChangedwere[]in every step of this test.Key observations
payload.type ∈ {"full","nodes","flows"}.diffon Step 2 (nodes) and Step 3 (flows). The deploy type controls what Node-RED restarts, not whatdiffreports.diff.changed. Tabs land in the diff when any of their nodes change. So tab-id-based predicates over-trigger if dashboardAPI shares a tab with unrelated work.diffarrays — a legitimateoutcome: "no-diff"for the F-1 log line.linkedandflowChangedwere never populated in these tests — likely fire for cross-tablinknodes or whole-flow imports. Not load-bearing for the predicate.Predicate for "did my subtree change"
Use the dashboardAPI's node id + the ids of all registered children (not tab ids — avoid the tab false-positive):
Known edge case (for #36 to handle)
When a brand-new child is wired to a registered parent (e.g. a new
measurementconnected to an existingpumpingStationalready registered to a dashboardAPI), the new node lands indiff.addedbut is not yet inChildRegistrationUtils.registeredChildrenat the momentflows:startedfires — registration happens on child node init, which is concurrent with the event.Two acceptable mitigations:
Recommendation for issue #36
Implement the predicate above; pick mitigation (b) initially and revisit if it manifests as user-visible lag.
Prototype location (do not import)
.prototypes/spike-flows-started/