Overview
Until this version NTL offered exactly one delivery behaviour: emit and hope. A signal belowmin_propagation_weight was silently absorbed, and the
sender was never told. That is defensible for analytics and discovery. It is
disqualifying for anything transactional — no one will settle a payment
on a protocol where the failure mode is silence.
This document defines two delivery classes so that both use cases are
served, and so that an application can tell which one it is getting.
Delivery Classes
Every signal carries exactly one delivery class. It is part of the signed signal body, so an intermediate node cannot downgrade it.best-effort MUST be the default, so that existing behaviour is unchanged
and the expensive class is opt-in.
1. Best-Effort Delivery
Current behaviour, now named. A node MAY drop abest-effort signal when:
- weight falls below
min_propagation_weightafter attenuation - TTL reaches zero
- no candidate synapse passes scope filtering
- the activation queue is full and this signal is the lowest-weight occupant
2. Acknowledged Delivery
2.1 The Guarantee
For anacknowledged signal, the sender MUST eventually observe exactly one
of:
- A positive receipt — a node handled the signal.
- A negative receipt — a node determined it cannot be delivered, with a reason.
- A timeout — no receipt within the retry budget.
2.2 Silent Absorption Is Prohibited
A node that would drop anacknowledged signal MUST instead emit a negative
receipt toward signal.origin, with a reason:
In particular,
min_propagation_weight MUST NOT silently absorb an
acknowledged signal. This is the single most important rule in this
document: it is what makes the class usable, and the exception that the
weight threshold now carries.
A node that cannot emit a negative receipt — no return path — MUST NOT
silently drop the signal. It MUST attempt to return it along the recorded
trace, and if that fails, log the drop as an error condition. Applications
then fall back on sender-side timeout.
2.3 Attenuation Floor
Anacknowledged signal’s weight MUST NOT be attenuated below
min_propagation_weight while TTL remains. A node MUST clamp:
below_threshold rejection at
some hop regardless of routing quality, making the class unusable over more
than a few hops.
3. Retry
The sender retries; intermediate nodes do not. Hop-by-hop retry multiplies traffic combinatorially and makes idempotency the whole network’s problem instead of the endpoints’. Default policy: exponential backoff with full jitter.
Rules:
- A retry MUST reuse the same signal ID. This is what makes the retry recognisable as a duplicate rather than a new request (§4).
- A retry MUST NOT reuse the recorded trace: the point of retrying is to let stochastic selection find a different path.
- Retrying MUST stop at the first terminal receipt — positive, or negative
with a reason other than a transient one.
no_route,transport_failureandqueue_fullare transient;unsupported_typeandrefusedare terminal, and retrying them is pure waste. - On exhausting the budget the sender MUST surface a delivery failure to the application. It MUST NOT report success.
4. Idempotency
At-least-once means duplicates. Handlers must tolerate them. Signal ID is the idempotency key. A retry carries the same ID as the original, so any node — intermediate or terminal — recognises it through the deduplication cache. Requirements:- A node MUST deduplicate on signal ID for at least
dedup_cache_seconds(default 300 s), which MUST be at least the sender’stotal_deadline. A dedup window shorter than the retry budget means a late retry is processed as new — the one configuration that silently breaks exactly-once handling. - A terminal node that receives a duplicate of a signal it already handled MUST NOT handle it again, and MUST re-emit the original receipt. Dropping the duplicate silently strands a sender whose first receipt was lost.
- Applications MUST treat handling as idempotent. NTL provides at-least-once; it does not provide exactly-once, and no transport can.
5. Ordering
Neither class provides ordering. Signals may arrive in any order, and stochastic path selection makes reordering likely rather than merely possible. Applications requiring order MUST sequence at the application layer. Signal IDs are ULIDs, so they are lexicographically time-ordered by emission and usable as a sequencing hint — but not as a guarantee, since clocks across nodes are not synchronised.6. Interaction With Other Mechanisms
Note the last row. Because
acknowledged signals always resolve to a
definite outcome, they are the highest-quality training data the routing
model receives: their rewards are never pending for long. A node carrying
acknowledged traffic learns faster and more accurately than one carrying
only best-effort traffic.
7. Cost
acknowledged is not free. Per signal it adds a return-path receipt,
sender-side retry state until resolution, a journal entry, and dedup
retention for the full retry budget.
Applications SHOULD use best-effort for anything that can tolerate loss,
and reserve acknowledged for signals with side effects. Marking all
traffic acknowledged roughly doubles signal volume and is the single
easiest way to make an NTL deployment slow.
8. Conformance
An implementation claimingacknowledged support MUST:
- Accept and preserve the
deliveryfield through propagation, unmodified - Emit negative receipts for every condition in §2.2
- Clamp attenuation per §2.3
- Deduplicate on signal ID for at least the sender’s
total_deadline - Re-emit the original receipt for a duplicate of an already-handled signal
- Never report success on an unresolved signal
best-effort MUST reject acknowledged
signals with a negative receipt of reason unsupported_type, rather than
accepting them and degrading silently. A silent downgrade is worse than a
refusal, because the sender believes it has a guarantee it does not have.