mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-23 03:33:53 +00:00
94bfd48a9d
Third slice on the agent-paradigm pivot, closing the substrate triangle (discovery + bundled reads + push). Agents subscribe once to a long-lived SSE connection and receive real-time events instead of polling: finding.created when a new finding is raised, heartbeat every 15 seconds for keepalive. Each event carries a monotonic ID so agents can dedupe and reason about ordering across reconnects. The broadcaster fan-outs to multiple subscribers and drops events for slow consumers rather than blocking the publish path — publishers cannot stall on consumer slowness. The findings-runtime hook in router.go publishes finding.created when the finding is new AND not auto-dismissed by operator-state suppression (operator already said to stay quiet about that resource); patrol-cycle re-detection of existing findings doesn't fire the event. Capabilities manifest declares the stream under subscribe_events so external agents discover it through the same channel as the REST surface. SSE chosen over WebSocket because it's simpler, works through every HTTP proxy without special-casing, and matches the existing deploy_handlers pattern; agents that need bidirectional comms call REST endpoints in parallel. Tests pin the broadcaster's pub/sub semantics (fan-out, unsubscribe, slow-consumer drop, monotonic IDs), the SSE handler's stream contract (text/event-stream, no-cache, X-Accel-Buffering=no), and the connected/published-event delivery via httptest.NewServer. A contract test pins the publish-gate semantics so operator-state suppression and stream notifications stay aligned.