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 compiled pipeline, so a node that failed to load still appears — a
broken neuron is exactly what someone comes to this view to find. 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 # What validation found, by the node it names, plus what is down right
# in it, so all of them are marked rather than an arbitrary one. # 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] = {} troubled: dict[str, str] = {}
for issue in self.issues: for issue in self.issues + self._health_issues():
if issue.code in ADVISORY_ISSUES: if issue.code in ADVISORY_ISSUES:
continue continue
for member in (*issue.nodes, *filter(None, [issue.node])): for member in (*issue.nodes, *filter(None, [issue.node])):
+21 -1
View File
@@ -9,7 +9,7 @@ from pathlib import Path
import pytest 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.messages import DType, MessageSpec
from fluksio.flow.nodes import MqttNode from fluksio.flow.nodes import MqttNode
from fluksio.flow.pipeline import ValidationIssue 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): def test_an_advisory_issue_leaves_the_graph_clean(controller: FlowController):
controller.issues = [ controller.issues = [
ValidationIssue( ValidationIssue(