Let a node's failure outlive the run that followed it
A node's error cleared the moment it ran again, so a failure that genuinely fired an alert could leave no trace on the canvas by the time anyone looked. The engine records it now — on the node's status, so it survives a reload and every client agrees — and reading the traceback is what clears it. The seam is the event bus, which is where every failing path already meets: a queued live run, an explicit run, a preview, and a single triggered node all publish `node_error`, while the controller's own observer would have seen only one of them. That was half the confusion. The other half: clicking a failed neuron on Home often landed on a flow where everything looked fine. Nodes merge into one neuron by instance key — every InfluxDB node pointing at the same bucket is one neuron — and the click went to whichever flow contributed a member first, not the one that failed. It now goes to the failing member and selects it, and the canvas marks a failing node rather than leaving it to the dot alone. The inject node emitted one payload to every port it declared, whatever their types, so an inject on a bool port carrying the text "true" raised at publish time. Each port gets its own field now, typed and parsed by that port's dtype, and remembers what it last sent. A port that is renamed carries its value with it; one that is removed takes its value with it. An inject written before this keeps emitting exactly what it did. The derived-cron chip also appeared on the delay node, where `interval` is a rate limit and a schedule derived from it means nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uq8mtNb97A7praJLyeEYgs
This commit is contained in:
@@ -211,6 +211,15 @@
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* A keyboard has to see where it is. The outline is off above by design, so
|
||||
* focus is answered the way a neuron answers it — by recolouring the node's own
|
||||
* rim rather than by adding a ring around it. `--ring` equals `--primary`.
|
||||
*/
|
||||
.react-flow__node:focus-visible .flow-node-card {
|
||||
border-color: var(--ring);
|
||||
}
|
||||
|
||||
/*
|
||||
* Brain graph. A neuron meets its connections all round its rim, so these two
|
||||
* handles are only there to make React Flow treat the node as wired at all —
|
||||
@@ -418,4 +427,44 @@
|
||||
.brain-wire.brain-hot .brain-dot {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* A value passing lights the line for the pulse and then decays; the dots sit
|
||||
* on the same signal, so they flash with it instead of only following the
|
||||
* falloff — same duration and easing as `edge-pulse`, and the same plain
|
||||
* `--edge-rest` at the far end rather than the `color-mix()` the group rests
|
||||
* in, which is what turned an interpolated pulse fluorescent.
|
||||
*
|
||||
* Two keyframe sets, because an animation beats a normal declaration whatever
|
||||
* its specificity: animating `fill` for every dot would fill the hollow
|
||||
* arriving end for the length of the pulse, and that hole is what tells the
|
||||
* two ends apart.
|
||||
*/
|
||||
.brain-wire.brain-hot .brain-dot {
|
||||
animation: brain-dot-pulse var(--duration-pulse) var(--ease-emphasized);
|
||||
}
|
||||
|
||||
.brain-wire.brain-hot .brain-dot.brain-dot-out {
|
||||
animation: brain-dot-out-pulse var(--duration-pulse) var(--ease-emphasized);
|
||||
}
|
||||
|
||||
@keyframes brain-dot-pulse {
|
||||
from {
|
||||
stroke: var(--primary);
|
||||
}
|
||||
to {
|
||||
stroke: var(--edge-rest);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes brain-dot-out-pulse {
|
||||
from {
|
||||
stroke: var(--primary);
|
||||
fill: var(--primary);
|
||||
}
|
||||
to {
|
||||
stroke: var(--edge-rest);
|
||||
fill: var(--edge-rest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user