The README's install line failed: the package was never published, and nothing told npm where the @extant2000 scope lives. A tag like v1.2.3 now publishes to this project's registry with CI_JOB_TOKEN, and the README sets the scope's registry before installing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SlowLane
Check signatures, ordering and duplicates on a link that is slow, intermittent and out of order.
SlowLane assesses a batch of received messages and tells you which ones to
apply, in which order, and which to reject. It is pure, with no clock and no
network. now is never read: every decision comes from the timestamps
carried on the messages, so the same trace always produces the same verdicts.
What it checks and why
Security checks written for a fast, ordered, exactly-once link break on a link that is none of those things. Worse, they fail in a direction that looks correct. Three cases:
- Expiry checked at the wrong end of the flight. A message signed with a key
that was valid when it was sent can arrive after the key expired. Checking
the key at arrival rejects legitimate traffic, and on a link with hours of
transit that is most of it. Checking only at origin accepts a message
whose key is no longer trusted. Each check is wrong on its own, so
keyVerdict()checks both ends and returnsexpired-in-flightas its own verdict. Such a message is accepted and recorded. Revocation is different and ignores origin time entirely, because a key is usually compromised before anyone notices. - Ordering by arrival. Arrival order is a property of the link, not of the
sender. Applying updates in receipt order overwrites newer state with
older and looks like it worked. The per-sender
sequenceis the only ordering authority, andapplycomes back sorted by it. A caller that loops over the input array instead has brought the bug back. - At-least-once delivery meeting a handler that is not idempotent. On this kind of link a duplicate is the delivery guarantee working. It is a finding only when the receiver has not declared itself idempotent. The duplicate is not the anomaly; the assumption of exactly-once is.
Also:
- Too old to act on. Past
maxTransitSeconds, a message is rejected but worth recording. The world it described has moved on. - Received before sent. NOT ASSESSED. The clocks disagree.
- No recognised key. NOT ASSESSED and rejected, since nothing establishes who sent it.
Usage
import { assessStream, formatStream, keyVerdict, type Message } from '@extant2000/slow-lane'
const messages: Message[] = [
{ id: 'm3', sender: 'probe-a', sequence: 3, originAt: '2026-09-28T10:05:00Z', receivedAt: '2026-09-28T10:25:00Z', keyId: 'k1', where: 'downlink.log' },
{ id: 'm1', sender: 'probe-a', sequence: 1, originAt: '2026-09-28T09:00:00Z', receivedAt: '2026-09-28T10:30:00Z', keyId: 'k1', where: 'downlink.log' },
{ id: 'm2', sender: 'probe-a', sequence: 2, originAt: '2026-09-28T10:00:00Z', receivedAt: '2026-09-28T10:20:00Z', keyId: 'k1', where: 'downlink.log' },
{ id: 'm2b', sender: 'probe-a', sequence: 2, originAt: '2026-09-28T10:00:00Z', receivedAt: '2026-09-28T10:40:00Z', keyId: 'k1', where: 'downlink.log' },
]
const { apply, reject, report } = assessStream(messages, {
keys: [{ id: 'k1', notAfter: '2026-09-28T10:10:00Z' }],
maxTransitSeconds: 3600,
receiverIsIdempotent: false,
})
for (const m of apply) {
// sender order, not arrival order
}
report is an evidence-record CapabilityReport. Print it with
formatStream().
Sample output
Produced by running the example above and printing apply, reject and
each finding's determination and summary:
apply: m2, m3
reject: m1, m2b
not-applicable probe-a#1 was signed with a key that expired while in flight
fail probe-a#1 spent 90 minutes in transit
not-applicable probe-a#2 was signed with a key that expired while in flight
pass probe-a#2 accepted, 1200s in transit
not-applicable probe-a#2 was signed with a key that expired while in flight
fail probe-a#2 was delivered more than once
not-applicable probe-a#3 was signed with a key that expired while in flight
pass probe-a#3 accepted, 1200s in transit
Install
The package is published to the GitLab package registry, so point the
@extant2000 scope there first:
npm config set @extant2000:registry https://gitlab.com/api/v4/packages/npm/
npm install @extant2000/slow-lane
License
MIT. Copyright (c) 2026 Extant 2000 LLC. See LICENSE.