Symptom

On pi-krill: a CronTimer (every 5 s) → Calculation (“Counter + 1”) → DataPoint “Counter” wired with the Calculation as its source. In the ClientScreen node graph the Cron pulsed, the Counter pulsed and incremented correctly, but the Calculation node never showed the activity color pulse — every cycle, deterministically. The functional chain worked; only the Calc’s visual was missing. Survived the Phase 3 “centralized pulse” work, which was supposed to make every source-invoked node pulse.

Root cause

Two independent server→client SSE streams exist:

The ClientScreen graph renders activity only from /events (EventClientEventType.STATE_CHANGEClientNodeManager.updatepostshowActivity). No client consumes /sse at all (UI uses /events; the peer connector uses /trust; the peer-/sse claim in PEER_TRUST_ARCHITECTURE.md is stale doc unmatched by code).

broadcastActivityPulse (added in the uniform-source-invocation work) emitted the PROCESSING pulse only into _nodeUpdates//sse — a stream nothing reads — and never called EventFlowContainer. Cron and DataPoint masked the gap because their own state/snapshot changes flow through ServerNodeManager.update(), which does post a STATE_CHANGE Event (but only when state != NONE && origin.state != state && Δt > 1s). A Calculation’s compute path is updateMetaData()update(state = NONE), so that guard is false → it emits zero /events events per cycle. Net: the Calc’s only possible activity signal went to a dead stream.

Fix

broadcastActivityPulse now also posts the pulse onto EventFlowContainer via tryPostEvent(Event(id, STATE_CHANGE, StateChangeEventPayload(PROCESSING))) — the loss-tolerant API explicitly documented for cosmetic pulses — so it travels the /events stream the graph actually consumes. The dead _nodeUpdates.emit is retained for now (the /sse stream is unconsumed dead infrastructure pending a separate audit/removal, kept out of this fix’s scope). Regression test in UniformSourcePulseTest asserts executeSources produces a STATE_CHANGE(PROCESSING) Event on EventFlowContainer.events for the subscriber (the real dispatch path), not just on nodeUpdates.

Prevention

Same class as feedback-verify-dispatch-entry-point: a refactor that changes how/where a signal is delivered must be verified against the stream the consumer actually reads, end-to-end — not just asserted at the producer. The Phase 3 test (executeSources emits a PROCESSING pulse) collected nodeUpdates, a stream with no consumer, so it passed while the feature was non-functional. Rule: a “client-visible” assertion must target the same stream/endpoint the client subscribes to. When a codebase has parallel broadcast channels (/sse Node stream vs /events Event stream), a feature touching one must state which the client reads and test against that one. Bonus signal that was missed: EventFlowContainer already had a tryPostEvent documented “for PROCESSING pulses” — an unused, purpose-built API is evidence the producer is wired to the wrong channel.