Config Activity API
An internal component that monitors activity (event throughput) of a group or app component. This component is automatically injected by the Kelp service; do not add it to the app config.
Event Collection
The component subscribes to all events passing through its parent group or app component via the coordinator's register-group-pulse-subscription API. Every event that flows through the parent container is counted, regardless of source or destination.
Event Handling Workflow
Subscription Lifecycle
-
Registration: When the component initializes, it automatically registers a subscription with the coordinator for its parent group via
register-group-pulse-subscriptionAPI. -
Activation: Subscriptions are activated when:
- Wire connected: A wire is plugged to the component's
pulseoutput port (detected viastreamsActivatedhook) - Editor mode: The debugger/editor activates all subscriptions by calling
activate-group-pulse-subscriptionwithgroupId: null
- Wire connected: A wire is plugged to the component's
-
Event Collection: Once activated, the coordinator collects all events passing through the parent group:
- Events are intercepted in the
transforms-loaderduring wire transformation - Each event is emitted to the group's activity aggregator (stored in
groupPulseSubscriptionsRegistered) - Events from all parent groups in the hierarchy are collected
- Events are intercepted in the
-
Aggregation: The coordinator aggregates events using EWMA:
- Raw events are fed into
createGroupActivityAggregator - Aggregator calculates smoothed rate and state transitions
- Aggregated metrics are emitted back to the component
- Raw events are fed into
-
Delivery: The component receives aggregated metrics and:
- Emits them to the
pulseoutput port - Reports them back to coordinator via
send-group-activity-infoAPI — BS, remove
- Emits them to the
Activation States
- Inactive: Subscription registered but not activated. No events are collected, aggregator exists but receives no events.
- Active (per-group): Wire connected to
pulseport. Only this specific group's subscription is activated. Events are collected and aggregated. - Active (all groups): Editor/debugger mode. All subscriptions are activated simultaneously (
groupId: nullingroupPulseSubscriptionsActivatedset). Used when editor needs visibility into all group activities.
Metrics Aggregation
Rate Calculation (EWMA)
The component uses Exponentially Weighted Moving Average (EWMA) for smooth rate calculation:
rate_ewma = α × instant_rate + (1 - α) × previous_rate_ewma
Where:
instant_rate= events in current tick × (1000 / tickMs)α(ewmaAlpha) = smoothing constant (default: 0.3)
EWMA provides smooth transitions without sudden jumps when event rate changes.
Activity State Machine
The component maintains a state machine with three states:
┌──────┐ rate >= onRate ┌────────┐ rate >= busyRate ┌──────┐
│ idle │ ──────────────────▶ │ active │ ──────────────────▶ │ busy │
└──────┘ for onHoldMs └────────┘ (immediate) └──────┘
▲ │ ▲ │
│ rate <= offRate │ │ rate < busyRate │
└──────────────────────────────┘ └───────────────────────────┘
for offHoldMs (immediate)
Note: There is no direct transition between busy and idle. The busy state always transitions to active first, then active can transition to idle after hysteresis.
Hysteresis is applied to prevent flickering:
- Transition to
activerequires rate ≥onRatesustained foronHoldMs - Transition to
idlerequires rate ≤offRatesustained foroffHoldMs - Single events decay before hysteresis completes, avoiding spurious state changes
Configuration Parameters
| Parameter | Default | Description |
|---|---|---|
| EWMA Settings | ||
tickMs | 250 | Tick interval for EWMA sampling (ms) |
emitIntervalMs | 1000 | Minimum interval between emissions (ms) |
ewmaAlpha | 0.3 | Smoothing constant (0-1, higher = more responsive) |
rateDecimalPlaces | 2 | Number of decimal places for rate_ewma output |
| State Thresholds | ||
busyRate | 50 | Rate threshold to enter busy state (events/sec) |
| Hysteresis | ||
onRate | 1.0 | Rate threshold to flip idle → active |
offRate | 0.5 | Rate threshold to flip active → idle |
onHoldMs | 750 | How long onRate must be sustained |
offHoldMs | 750 | How long off-conditions must be sustained |
tickMs vs emitIntervalMs
tickMs: Controls EWMA sampling frequency. Smaller values = more accurate rate calculation and faster state transitions, but higher CPU usage.emitIntervalMs: Controls maximum emission frequency. Use this to throttle output without affecting rate accuracy.
Example: tickMs: 100, emitIntervalMs: 1000 samples EWMA every 100ms for accurate rate tracking, but only emits updates every 1 second to avoid flooding downstream consumers.
Note: State changes always emit immediately regardless of emitIntervalMs.
Output (pulse port)
Data Structure
{
"ts": "2025-11-28T12:34:56.789Z",
"state": "active",
"rate_ewma": 3.45,
"hadEvents": true
}
| Field | Type | Description |
|---|---|---|
ts | string | ISO 8601 timestamp of the measurement |
state | string | Activity state: idle, active, or busy |
rate_ewma | number | Smoothed event rate (events/sec), rounded per rateDecimalPlaces |
hadEvents | boolean | Whether events occurred since last emission |
Emission Rules
The component emits based on state and activity:
| State | Emission Behavior |
|---|---|
active/busy | Emits periodic updates, throttled by emitIntervalMs |
idle | Emits only when new events occur, throttled by emitIntervalMs |
| State change | Always emits immediately (bypasses throttling) |
| Rate → 0 | Emits once when rate becomes zero, then stops |
Important Behavior Notes
-
No continuous reporting when idle: If the group has no activity (rate = 0), the component emits once when settled and then stops. It will not continuously report "still idle".
-
Delayed state transitions: Due to hysteresis and EWMA smoothing, state changes may be delayed:
- Single events may not trigger
activestate (rate decays before hysteresis completes) - Transition to
idleis delayed byoffHoldMsafter conditions are met
- Single events may not trigger
-
Active state reporting: While in
activeorbusystate, the component reports periodic updates atemitIntervalMsintervals. -
Idle state efficiency: While idle, emissions only occur when new events arrive, preventing unnecessary output when the system is quiet.
Example Output Sequence
// Initial state (no events yet)
{ "ts": "...", "state": "idle", "rate_ewma": 0, "hadEvents": false }
// Single event arrives
{ "ts": "...", "state": "idle", "rate_ewma": 2.4, "hadEvents": true }
// Rate settles back to zero
{ "ts": "...", "state": "idle", "rate_ewma": 0, "hadEvents": false }
// Sustained events (3-4/sec) - becomes active after hysteresis
{ "ts": "...", "state": "active", "rate_ewma": 3.2, "hadEvents": true }
// Periodic updates while active
{ "ts": "...", "state": "active", "rate_ewma": 3.5, "hadEvents": true }
{ "ts": "...", "state": "active", "rate_ewma": 3.4, "hadEvents": true }
// Events stop - becomes idle after hysteresis
{ "ts": "...", "state": "idle", "rate_ewma": 0.3, "hadEvents": false }
// Rate settles to zero
{ "ts": "...", "state": "idle", "rate_ewma": 0, "hadEvents": false }
// ... silence (no emissions until next activity)