Overview
The activation model defines how nodes decide whether to process incoming signals. It replaces traditional rate limiting with a biologically-inspired threshold system.Activation State
Each node MUST maintain an activation state:Activation Sequence
- Signal arrives at node via synapse.
- Signal contribution is calculated:
contribution = signal.weight * synapse.weight - Contribution is added to the node’s potential:
potential += min(potential + contribution, max_potential) - The signal is appended to the pending queue (see Queue Management).
- If
potential >= thresholdAND the node is not in its refractory period: a. The node fires, draining a batch from the queue (What Firing Processes). b. Potential resets to0.0. c. The node enters its refractory period. - Otherwise no processing occurs; the signal waits in the queue.
What Firing Processes
Earlier drafts said potential accumulates across all signals and then “the node fires (processes the signal)”, without saying which signal. When potential is the sum of many contributions, “the signal” is ambiguous, and implementations diverged: some processed only the signal that crossed the threshold, leaking the rest. This version resolves it. On firing, a node MUST drain a batch from the pending queue:- Order the pending queue by signal weight descending. Where weights tie, order by signal ID ascending, so the order is total and reproducible.
- Process up to
fire_batch_sizesignals from the front of that order. - Reset
potentialto0.0after the batch, not per signal. - Enter the refractory period.
fire_batch_size − 1 signals per fire,
silently, with no receipt for their senders. The batch is the unit of work, so
a node MUST route each member of it and MUST NOT assume a member’s route was
planned when it was queued: the route is chosen at release, because the
topology may have changed while it waited.
The same applies to a signal released by the latency guard below: releasing it
means processing it, which includes forwarding it. A node that emits a positive
receipt for a released signal it did not then route has reported a delivery
that did not happen.
fire_batch_size defaults to 16. A node MUST NOT set it to zero. Setting
it to 1 yields the strictest interpretation of the earlier text — one
signal per fire — at the cost of throughput, and is permitted.
Potential resets once per fire, not once per signal. A batch of sixteen
signals costs the same one refractory period as a batch of one, which is
what makes batching worth doing under load.
Dynamic Threshold
The threshold SHOULD adjust dynamically based on node load:load_factor = current_queue_depth / max_queue_depth.
This ensures that overloaded nodes become more selective, providing natural backpressure.
Refractory Period
After firing, a node MUST enter a refractory period during which it cannot fire again. During it:- Incoming signals still accumulate potential
- No processing occurs
- Signals queue, subject to the bounded-queue policy below
Refractory Period Is a Node-Class Parameter
A single global default cannot serve both a solar-powered sensor and a datacentre node. 10 ms on server-class hardware caps the node at 100 fires per second, which is a throughput ceiling far below what the hardware can sustain — and a self-inflicted one. The refractory period MUST therefore be configured per node class:
A value of
0 disables the refractory period. This is legitimate on
server-class nodes: the dynamic threshold and the bounded queue already
provide backpressure, and the refractory period is the crudest of the three.
A node MUST report its class and effective refractory period, so that an
operator diagnosing a throughput ceiling can see it.
Queue Management
load_factor = current_queue_depth / max_queue_depth implies a bounded
queue. Earlier drafts also stated that during the refractory period “no
signals are dropped (they queue)”. Both cannot hold: a bounded queue
necessarily rejects something once full. This version specifies what.
Bounded Queue
A node MUST maintain a bounded pending queue ofmax_queue_depth signals
(defaults in Configuration). load_factor is defined
against this bound, and is therefore always in [0, 1].
Overflow Policy
When a signal arrives at a full queue, the node MUST apply its configuredoverflow_policy:
drop_lowest_weight is the default because it preserves the protocol’s own
priority semantics: weight already means importance everywhere else, and
under load is exactly when honouring it matters.
Overflow and Delivery Class
A dropped signal’s delivery class governs whether the drop is reported:best-effort— dropped silently. No receipt.acknowledged— the node MUST emit a negative receipt with reasonqueue_fulltoward the signal’s origin. Dropping it silently is prohibited; see delivery-semantics §2.2.
acknowledged signal without emitting a receipt,
even under overflow. Overload is not an exemption from the delivery
guarantee — it is the case the guarantee exists for.
A refused arrival does not refuse the batch. Admission enqueues before it
evaluates, so an arrival’s own contribution can fire the gate on its way in and
the overflow policy can then choose that same arrival as the drop. It can also
fire a batch it is not itself part of, since the drain takes the top
fire_batch_size by weight. Either way the batch is other senders’ traffic and
has nothing to do with why this signal was turned away: a node MUST process it
and MUST NOT report the refused signal as also handled — those are
contradictory outcomes for one signal.
This holds for the displaced signal as much as the refused arrival. Under
drop_lowest_weight and drop_oldest the signal dropped is usually not
the one that just arrived, and it came from a different peer — so the receipt
goes to a different origin, over a different synapse, and cannot be inferred
from the arrival. An implementation MUST therefore report which signal was
displaced, not merely that a drop occurred. Reporting only the arrival’s fate
is the shape this omission takes in practice, and it silently breaks the
guarantee for exactly the signals the policy chose to sacrifice.
Interaction With the Dynamic Threshold
Overflow should be rare, because the rising threshold throttles admission before the queue fills. A node whose queue overflows regularly is misconfigured: eithermax_queue_depth is too small for its traffic, or
dynamic_threshold is disabled. Implementations SHOULD expose an overflow
counter so this is visible rather than inferred.
Activation Functions
Implementations MUST support thestep activation function. Implementations SHOULD support sigmoid and leaky functions.
Configuration
Persistence
Activation state MAY be memory-only on edge nodes, and SHOULD be persisted on other classes. A node that discards its activation state on restart offers an attacker a free reset of backpressure: flood it, let it restart, and it comes back ready to be flooded again. See storage-interface §4.Related
- delivery-semantics — what overflow owes the sender
- learning-model — how outcomes update weights
- threat-model §5 — resource exhaustion