Separate hot runtime value propagation from UI/parameter observation. Keep Parameters and Combine for authored/editor state, but let graph execution move port values through direct internal storage without publishing every per-frame update.
Key Changes
-
Add internal runtime storage on ports:
- Keep existing public value / parameter sync behavior for UI/editor paths.
- Add internal fast-path assignment for execution, e.g. setRuntimeValue(_:force:), that updates value state without Combine/UI notification.
-
Split send paths:
- Existing send(..., force:) remains the observable/editor-safe path.
- New runtime send path directly assigns connected inlet runtime values and updates valueDidChange/dirty state.
-
Keep parameters authoritative for authored inputs:
- UI edits update Parameters.
- Parameters seed/update inlet runtime values.
- Nodes mark dirty normally.
-
Treat computed outlet values as runtime data:
- Node execute writes outlet runtime values.
- Connected inlet runtime values update directly.
- UI does not receive per-port Combine events every execution iteration.
-
Add a live inspection strategy later:
- Visible node views can sample current runtime values on demand, or
- GraphRenderer can emit one throttled “runtime values changed” tick for visible/debug UI only.
Migration Approach
- Start with a narrow internal API on NodePort.
- Convert only execution hot spots first, especially outlet-to-inlet propagation from node execute.
- Leave parameter editing, connection changes, publishing, serialization, and UI-visible port metadata unchanged.
- Add assertions/tests to ensure observable send still works for editor paths.
Test Plan
-
Functional:
- Parameter edits still update connected graph execution.
- Published inputs/outputs still serialize and restore.
- Node UI still reflects authored parameter values.
- Live/debug value display either remains unchanged or is explicitly marked as sampled/throttled.
-
Performance:
- Profile iterator String Queue before/after.
- Confirm NodePort.send, _send, ParameterPort.value.didSet, and GenericParameter.value.didSet drop from per-iteration hot paths.
-
Regression:
- Feedback cache still snapshots the correct outlet runtime values.
- Type-agnostic nodes using snapshotValue() / sendBoxed() still work.
- Connected parameter ports still receive user-authored values correctly.
Assumptions
- Combine remains for UI/editor observation, not graph execution.
- Runtime values may change every frame without forcing SwiftUI redraws.
- Live port value UI should be sampled or throttled rather than synchronously published per value write.
- Public API changes should be avoided until the internal model proves itself.
Separate hot runtime value propagation from UI/parameter observation. Keep Parameters and Combine for authored/editor state, but let graph execution move port values through direct internal storage without publishing every per-frame update.
Key Changes
Add internal runtime storage on ports:
Split send paths:
Keep parameters authoritative for authored inputs:
Treat computed outlet values as runtime data:
Add a live inspection strategy later:
Migration Approach
Test Plan
Functional:
Performance:
Regression:
Assumptions