Draw a node that is down as a troubled neuron

`brain_graph` read `self.issues` alone, which is what a build found — so a
node that loaded and then lost its device was a well neuron on Home, and
that is what someone comes to this view to find.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KYM38KSb4V4v2T71eifnZv
This commit is contained in:
2026-08-30 17:25:14 +02:00
co-authored by Claude Opus 5
parent 8b65e1ecfd
commit e4428efb8d
2 changed files with 26 additions and 4 deletions
+5 -3
View File
@@ -1497,10 +1497,12 @@ class FlowController:
compiled pipeline, so a node that failed to load still appears — a
broken neuron is exactly what someone comes to this view to find.
"""
# What validation found, by the node it names. A cycle names every node
# in it, so all of them are marked rather than an arbitrary one.
# What validation found, by the node it names, plus what is down right
# now — a neuron someone comes here to find is as often a node that
# stopped working as one that never built. A cycle names every node in
# it, so all of them are marked rather than an arbitrary one.
troubled: dict[str, str] = {}
for issue in self.issues:
for issue in self.issues + self._health_issues():
if issue.code in ADVISORY_ISSUES:
continue
for member in (*issue.nodes, *filter(None, [issue.node])):
+21 -1
View File
@@ -9,7 +9,7 @@ from pathlib import Path
import pytest
from fluksio.flow.controller import FlowController
from fluksio.flow.controller import FlowController, LoadedNode
from fluksio.flow.messages import DType, MessageSpec
from fluksio.flow.nodes import MqttNode
from fluksio.flow.pipeline import ValidationIssue
@@ -105,6 +105,26 @@ def test_a_neuron_carries_what_stops_it_running(controller: FlowController):
}
def test_a_node_that_is_down_is_a_troubled_neuron(controller: FlowController):
"""A node that stopped working is what someone comes to this view to find.
`self.issues` is what a build found; being down happens afterwards, so the
graph has to read the health issues too or a dead node draws as a well one.
"""
controller.loaded["house.scale"] = LoadedNode(
id="house.scale",
flow="house",
health="down",
health_detail="broker unreachable",
)
marked = {
node.id: node.issue for node in controller.brain_graph().nodes if node.issue
}
assert list(marked) == ["house.scale"]
assert "broker unreachable" in marked["house.scale"]
def test_an_advisory_issue_leaves_the_graph_clean(controller: FlowController):
controller.issues = [
ValidationIssue(