""" Fester backend — core API facade. This module exposes a single `bus`, `registry`, `observability`, `ws_stream`, plus thin wrapper functions for the API layer. It used to be broken (referenced `bus` before creation, imported nonexistent `_endpoint` symbols, duplicated CauseGraphEngine setup). It now wires everything cleanly. """ from backend.events.bus import EventBus from backend.metrics.observability import ObservabilityHub from backend.metrics.node_state import NodeStateRegistry from backend.analysis.cause_graph import CauseGraphEngine # ========================================================= # GLOBAL CORE SYSTEM INITIALIZATION (SINGLETON LAYER) # ========================================================= bus = EventBus() registry = NodeStateRegistry() observability = ObservabilityHub(registry, bus) observability.attach_bus() # Cause graph — subscribes ONCE, no recursion (ingest only) cause_graph = CauseGraphEngine() cause_graph.attach_bus(bus) bus.subscribe(cause_graph.ingest) # WebSocket stream — attached lazily by main.py when FastAPI starts, # because the WS layer needs the running app's connection registry. ws_stream = None # set by backend.main when app boots def attach_ws_stream(stream): """Called by backend.main during startup to bind a WebSocketStream.""" global ws_stream ws_stream = stream ws_stream.attach_bus(bus) # ========================================================= # API REGISTRATION LAYER # Thin wrappers so Cockpit / external callers can bind cleanly. # ========================================================= # These imports are deliberately placed AFTER the singletons above are # initialized, because some api/* modules may want to import `bus` etc. from backend.api import build as build_api from backend.api import nodes as nodes_api from backend.api import replay as replay_api from backend.api import debugger as debugger_api from backend.api import timeline as timeline_api from backend.api import metrics as metrics_api from backend.api import autopsy as autopsy_api from backend.api import pipeline_control as pipeline_control_api from backend.api import cause as cause_api def build(spec, nodes, cluster=None, intelligence=None): return build_api.build_endpoint(spec, nodes, cluster, intelligence) def replay(session_id): return replay_api.replay_endpoint(session_id, registry) def debugger(session_id): return debugger_api.debugger_endpoint(session_id, registry, bus) def timeline(session_id): return timeline_api.timeline_endpoint(session_id) def nodes(): return nodes_api.nodes_endpoint(registry) def metrics(): return metrics_api.metrics_endpoint(registry) def autopsy(session_id): return autopsy_api.autopsy_endpoint(session_id) def pipeline_control(action, payload=None): return pipeline_control_api.pipeline_control_endpoint(action, payload, bus) __all__ = [ "bus", "registry", "observability", "ws_stream", "cause_graph", "attach_ws_stream", "build", "replay", "debugger", "timeline", "nodes", "metrics", "autopsy", "pipeline_control", ]