SENTO-000 Managed Component Runtime
| Version | Date | Description of change | Did nsaspy approve it |
|---|---|---|---|
| 0.1.0 | 2026-07-19 | Full managed-component runtime after source-level Sento audit | Pending |
| 0.2.0 | 2026-07-19 | Add the complete ZeroMQ transport, reactor, security, and routing model | Pending |
TODO Design File System
Purpose
Extend Sento1 into a complete actor runtime2 for composing independently managed gservers3 inside one actor system4 and across Sento nodes5.
The extension supplies generic runtime facilities. It must not contain StarIntel6 domains, intelligence collection rules, document schemas, case logic, or application-specific policy.
Primary consumer:
Research basis:
Source baseline
The design is based on source review of:
- repository:
mdbergmann/cl-gserver - branch:
master - commit:
a889b8375709ca9396bba5d06b6e460689a23716 - Sento version:
3.4.3 - Sento remoting7 version:
0.1.0 - ZeroMQ8 engine:
libzmq9 - review date:
2026-07-19
Every implementation record must identify the exact Sento, libzmq, Common Lisp binding, and operating-system package versions being used.
Current Sento capabilities
Sento already provides:
- actors10
- actor systems
- nested actor contexts11
- hierarchical actor paths12
- custom actor classes13
- actor lifecycle hooks14
- actor watching15
- shared and pinned dispatchers16
- bounded and unbounded mailboxes17
- bounded and unbounded queues18
- random and round-robin routers19
- event streams20
- futures21
- tasks22
- finite-state-machine actors23
- stashing actors24
- wheel timers25
- local actor references26
- remote actor references
- TCP transport27
- TLS support28
- a serializer protocol29
The extension must use these facilities rather than replace them.
Source-audit findings that change the design
Actor failures are not actor termination
Sento currently catches a serious-condition30 raised by an actor handler, logs it, and returns (:handler-error . condition). The actor normally remains alive.
A supervisor cannot infer that a child failed merely because user code raised an error. Watching currently reports only that an actor stopped.
A correct supervision system therefore requires a core Sento failure-policy hook. A companion library alone cannot reliably implement restart semantics while the core converts every handler failure into a normal result.
Stop notifications have no reason
A watcher currently receives:
(cons :stopped actor)
The notification does not distinguish normal shutdown, explicit stop, handler failure, initialization failure, forced thread termination, mailbox failure, parent shutdown, or remote disconnection.
Supervision requires a structured termination record31.
Parent stop recursively stops children
Stopping an actor recursively stops all actors in its actor context before stopping the parent. This provides a useful tree boundary, but it does not provide declarative startup order, restart strategies, restart limits, readiness, or reason-aware recovery.
The current router is intentionally small
The current router:
- is a normal Common Lisp object rather than an actor
- delegates
tell,ask-s, andask - supports random and round-robin selection
- accepts a custom selection function that receives only routee count
- supports routee addition
- has no public routee removal
- cannot be watched
- does not own restart policy
- does not inspect the message when selecting a routee
A managed router must extend this model.
Shared dispatchers are already router pools
A Sento shared dispatcher is implemented as a router over pinned worker actors. Each worker owns one thread.
An actor using a shared dispatcher has its own mailbox and lock. Dispatcher workers execute mailbox work while preserving one-message-at-a-time access to that actor's state.
Sento documentation warns that message execution order is not guaranteed for dispatcher mailboxes when submissions arrive from multiple threads.
Bounded mailboxes signal queue-full errors
A bounded queue signals queue-full-error when full. Normal tell calls may therefore signal to the sender unless the sender handles the condition.
There is no configurable overload policy32 such as reject, drop, block, shed, or reply-busy.
Stop discards queued messages
Stopping an actor finishes the currently executing message, rejects new messages, and discards queued messages. There is no drain mode33 for controlled shutdown.
Runtime metrics mostly require internal access
Queue depth is available at the queue protocol level, but actor mailbox queues and processed-message counters are not exposed through a complete public observability API34.
Event streams can be scoped below the actor system
Sento creates one system event stream by default. The event-stream constructor can also create an event stream inside another actor context.
Domain-local event buses therefore do not require separate actor systems. The managed-component runtime should create a scoped event stream under each component supervisor when requested.
The current event stream keeps subscribers in a list and does not automatically remove stopped subscribers. The extension must make subscriptions lifecycle-aware.
Actor systems are runtime roots
A Sento actor system owns user and internal actor contexts, dispatchers, a system event stream, a timeout timer, and an optional scheduler.
The default actor system creates four shared dispatcher workers. Six default actor systems would create twenty-four shared workers before custom dispatchers or pinned actors.
The actor system is therefore a runtime and deployment root, not the normal logical boundary for every domain.
Shutdown order needs a managed layer
Sento actor-system shutdown currently stops timeout and scheduler wheels before stopping user and internal actors.
Managed components must not assume timers remain available during actor destroy hooks. The extension must define its own component shutdown sequence before final actor-system shutdown.
Remoting already exists
Sento remoting already provides TCP framing, optional TLS, connection pooling, a two-megabyte default frame limit, local and remote references, tell, ask-s, and ask across actor systems, correlation identifiers35, and nested actor-path routing.
The design must integrate and harden this existing subsystem rather than invent another Sento-to-Sento transport.
Remoting requires hardening before deployment
The source audit found these issues:
- The default S-expression serializer36 calls
read-from-stringwithout binding*read-eval*tonil. - TLS configuration is optional.
- Incoming messages may target arbitrary local actor paths.
- There is no exported-actor registry37 or per-peer access policy.
- Remote inbound asks use a fixed five-second local timeout.
- The caller's deadline is not carried in the network envelope.
- The declared error-envelope type is not integrated into not-found and handler-error responses.
- A missing target for
tellis logged and dropped. - A missing target for
askis logged without returning a structured remote error. - Each remote reference creates an internal sender actor.
- Correlation lookup scans registered remote references.
- Delivery guarantees38 are not explicitly documented in the public API.
- Peer identity is not mapped to actor-path or message capabilities.
- There is no peer quota39 for concurrent asks, queued tells, or target paths.
These findings create a required remoting-hardening workstream.
Final architecture decision
Use one Sento actor system per operating-system process40 by default.
Inside the actor system, compose managed components41 under supervisor actors42.
Every application domain receives:
- one root supervisor
- one dedicated control dispatcher
- one default domain dispatcher
- zero or more subdomain dispatchers
- one optional scoped event stream
- one component registry entry
- one or more ingress actors43
- zero or more managed router pools
- zero or more optional ZeroMQ reactor components44
- lifecycle, readiness, health, overload, and metrics state
Use another process when the requirement is actual process isolation45, independent scaling, independent deployment, privilege separation, or crash containment.
Use multiple actor systems inside one process only for tests, compatibility bridges, staged migration, or a measured runtime-isolation requirement.
TODO Core Sento Changes
The following changes belong in Sento core because a companion library cannot implement them correctly through the current public API.
Failure policy
Add an actor failure policy46 selected when an actor is created.
Proposed values:
:resume: preserve current behavior; return a handler-error result and keep processing:stop: stop the actor and publish a failed termination record:escalate: stop the actor and mark the failure for its supervisor or watcher:custom: call a user-supplied failure-directive function
Proposed creation options:
(ac:actor-of context :receive receiver :failure-policy :escalate :failure-classifier classifier)
A failure classifier receives the actor reference, message, sender, condition, actor state, and mailbox metadata. It returns a failure directive47.
The default remains :resume for backward compatibility48.
Structured termination records
Replace reason-free stop notifications with a structured value while retaining a compatibility notification.
(defstruct termination-record actor actor-path actor-name actor-generation reason condition failed-message-summary started-at stopped-at parent-path metadata)
Proposed reasons:
:normal:explicit-stop:parent-stop:handler-failure:initialization-failure:mailbox-failure:dispatcher-failure:transport-failure:forced-stop:shutdown-timeout
Watchers receive:
(list :terminated termination-record)
The old (:stopped . actor) notification may remain behind a compatibility option during migration.
Actor generation
Mailbox status API
Expose public read-only operations:
(mailbox-depth actor) (mailbox-capacity actor) (mailbox-bounded-p actor) (mailbox-processed-count actor) (mailbox-rejected-count actor) (mailbox-running-p actor)
Mailbox overload policies
Add configurable bounded-mailbox policies:
:signal: signal queue-full as today:reject: return a structured rejected result:drop-new: discard the arriving message and record it:drop-old: discard the oldest queued message and record it:reply-busy: send a structured busy response when a sender exists:block: wait for capacity with a mandatory deadline:custom: call an overload-policy function
Blocking without a deadline is forbidden because actor-to-actor blocking can deadlock51 the runtime.
Every rejected or dropped message increments metrics and emits an overload event.
Controlled mailbox shutdown
Add stop modes:
:discard: current behavior:drain: finish queued messages before stopping:deadline: drain until a deadline, then discard remaining messages:handoff: return or transfer queued messages to a replacement actor
Router protocol extension
Extend routing with a message-aware strategy protocol:
(defgeneric select-routee (strategy message routees routing-context))
Add public routee operations:
(add-routee router routee) (remove-routee router routee) (replace-routees router routees) (routees router)
Built-in strategies:
- random
- round robin
- least mailbox depth
- consistent hash52
- rendezvous hash53
- explicit key function
- broadcast54
The existing count-only custom strategy remains supported as a compatibility adapter.
Dispatcher observability and control
Expose:
(dispatcher-worker-count dispatcher) (dispatcher-running-worker-count dispatcher) (dispatcher-queue-depth dispatcher) (dispatcher-processed-count dispatcher) (dispatcher-rejected-count dispatcher) (dispatcher-status dispatcher)
Dynamic dispatcher resizing is a later capability. Initial implementations may require restart to change worker count.
Actor-system identity
Add a stable actor-system identifier55 for component handles, remoting, ZeroMQ envelopes, metrics, termination records, stale-reference detection, and multi-system tests.
Public timeout scheduling access
Remove extension dependence on private asys::timeout-timer access. Export a supported timeout scheduling protocol or route all component timers through the public scheduler.
TODO Companion Sento Runtime Modules
The following facilities can be implemented as separate ASDF systems56 after the core hooks exist.
Proposed systems:
sento-supervision sento-managed-router sento-components sento-observability sento-remoting-policy sento-zmq
They may live in the Sento fork and be proposed upstream independently.
Child specification
Define a child specification57 containing:
- logical identifier
- actor name
- start function
- initialization arguments
- dispatcher identifier
- mailbox type
- queue capacity
- overload policy
- failure policy
- restart class
- shutdown mode
- shutdown deadline
- dependencies
- readiness probe
- health probe
- metadata
Restart classes:
:permanent: restart after normal or abnormal termination:transient: restart only after abnormal termination:temporary: never restart
Child types:
:worker:supervisor:router-pool:transport-reactor:component
Supervisor actor
A supervisor owns child specifications and current child instances.
Required restart strategies58:
:one-for-one: restart only the failed child:one-for-all: stop and restart every child:rest-for-one: restart the failed child and every child started after it
Required controls:
Supervisor state machine
Supervisor states:
:defined:starting:ready:degraded:restarting:stopping:stopped:failed
The supervisor may use Sento FSM facilities, but the child table, restart window, and lifecycle events must remain explicit and testable.
Dependency startup
A component may declare child dependencies as a directed acyclic graph61.
Startup rules:
- Validate that dependency identifiers exist.
- Reject cycles.
- Start dependencies before dependents.
- Wait for declared readiness before starting dependents.
- Shut down dependents before dependencies.
Readiness and health
Managed component
A managed component is a supervisor-owned actor subtree with stable logical identity, root supervisor, declared children, domain dispatcher tree, optional scoped event stream, ingress references, capability metadata, lifecycle state, health and readiness state, metrics namespace, and local or remote location.
Public operations:
(define-component ...)
(start-component runtime component-spec)
(stop-component runtime component-id &key mode deadline)
(restart-component runtime component-id)
(component-ref runtime component-id)
(component-status runtime component-id)
(component-health runtime component-id)
(component-ready-p runtime component-id)
Component handle
A component handle64 hides whether a component is local in the current actor system, local in another actor system, remote through Sento remoting, or remote through a ZeroMQ transport adapter.
Minimum fields:
- component identifier
- actor-system identifier
- node identifier
- process identifier
- ingress reference or transport route
- component generation
- capability set
- transport kind
- metadata
Application code routes through handles rather than arbitrary actor-path discovery.
Component registry
The component registry indexes component identifier, capability, accepted message type, actor-system identifier, node identifier, lifecycle state, readiness state, generation, and transport kind.
The registry supports register, replace, unregister, lookup by identifier, lookup by capability, subscribe to changes, and resolve local or remote handle.
Scoped event bus
A component may create a private event stream beneath its supervisor actor context.
The managed event bus must watch subscribers, remove terminated subscribers, use typed event envelopes, report subscriber count, report delivery failures, support explicit close, and stop with the component.
The system event stream remains available for runtime-wide events.
Managed router pool
A managed router pool65 is a supervisor-owned group of equivalent routee actors66.
Required operations:
(start-router-pool supervisor pool-spec)
(scale-router-pool pool-ref new-size)
(router-pool-status pool-ref)
(router-pool-routees pool-ref)
(router-pool-metrics pool-ref)
(stop-router-pool pool-ref &key mode deadline)
Required behavior:
- create routees from one child template
- watch every routee
- replace failed routees according to policy
- scale up and down
- drain a routee before planned removal
- reject or buffer work when no routee is ready
- emit lifecycle and overload events
- expose membership generation
- expose routee health and mailbox pressure
Keyed router
A keyed router67 maps messages with the same key to the same routee while membership is stable.
Supported key examples include target, account, case, sensor, program, dataset, and tenant.
When membership changes, the pool must define which keys move, how in-flight work finishes, whether state is transferred, whether a key is temporarily paused, and how stale-route messages are handled.
Stateful keyed actors must not be scaled with random routing.
TODO Dispatcher Tree
Primary rule
Dispatchers are per domain by default.
A domain owns a dispatcher namespace and may define subdomains inside the same process.
Workload-class dispatchers are optional shared infrastructure. They are not the primary ownership boundary.
Naming
Recommended identifier form:
:domain/humint/control :domain/humint/default :domain/humint/source-management :domain/humint/interviews :domain/socmint/control :domain/socmint/default :domain/socmint/platform-x :domain/socmint/platform-telegram :domain/socmint/media :domain/sigint/control :domain/sigint/default :domain/sigint/ingest :domain/sigint/decode :domain/sigint/correlation :domain/cyber/control :domain/cyber/default :domain/cyber/discovery :domain/cyber/scanning :domain/cyber/analysis :domain/bbp/control :domain/bbp/default :domain/bbp/programs :domain/bbp/enumeration :domain/bbp/findings :domain/threat-intel/control :domain/threat-intel/default :domain/threat-intel/feeds :domain/threat-intel/enrichment :domain/threat-intel/correlation
These are examples. A domain manifest defines the actual subdomains.
Required domain dispatchers
Every domain receives at least:
- a small control dispatcher for supervisors, registries, health, routing control, and transport control
- a default dispatcher for normal domain actors
A domain may add subdomain dispatchers when one area can saturate the domain, blocks on external I/O70, is CPU-heavy71, requires different queue limits, requires independent scaling, or requires dedicated latency targets.
Control-dispatcher rule
Application work must never run on the domain control dispatcher.
The control dispatcher is reserved for supervisor messages, routee lifecycle, transport lifecycle, readiness and health, registry changes, overload decisions, shutdown coordination, and metrics snapshots.
Subdomain ownership
A subdomain is a named workload or organizational area inside a domain process.
A subdomain may contain its own dispatcher, supervisor, routee pools, queue policies, event bus, ZeroMQ reactor, and metrics prefix.
A subdomain is not automatically a separate process or actor system.
Platform dispatchers
The runtime may define platform-owned dispatchers:
:platform/control:platform/remoting:platform/zeromq:platform/registry:platform/storage
Domain actors use platform services through declared handles. Platform dispatchers do not replace domain dispatchers.
Thread-budget validation
Before startup, the runtime computes total shared dispatcher workers, total pinned actors, ZeroMQ reactor threads, libzmq I/O threads72, timer threads, remoting transport threads, and configured maximum process thread count.
Startup fails or warns when the declared dispatcher and transport tree exceeds the configured thread budget73.
TODO Overload and Backpressure
Backpressure74 must be explicit at every asynchronous boundary.
Required boundaries:
- actor mailbox
- router pool
- dispatcher
- component ingress
- ZeroMQ command queue
- ZeroMQ socket high-water mark75
- remote sender actor
- remoting connection
- task pool
Structured overload result:
(defstruct overload-result boundary component-id actor-path endpoint queue-depth queue-capacity policy retry-after trace-id timestamp)
A component ingress may reject work before creating deeper messages when the component is not ready, is stopping, its default dispatcher is saturated, a required subdomain is unavailable, a transport is unavailable, a tenant quota is exhausted, or a message deadline is already expired.
Admission control76 prevents overload from spreading through the actor tree.
TODO Observability
Expose metrics for actor count, actor generations, mailbox depth and capacity, processed, rejected, and dropped messages, handler duration, dispatcher worker count, dispatcher queue depth, router membership, router key movement, supervisor restart count, component lifecycle state, readiness and health, event subscribers, remoting connections, pending remote asks, ZeroMQ socket state, ZeroMQ peer state, ZeroMQ high-water events, ZeroMQ pending requests, serializer failures, and frame-size rejections.
Define typed runtime events:
- actor started
- actor terminated
- actor restarted
- child restart suppressed
- supervisor escalated
- component starting
- component ready
- component degraded
- component stopping
- component stopped
- mailbox overloaded
- routee added
- routee removed
- routee replaced
- dispatcher saturated
- remote peer connected
- remote peer rejected
- remote target denied
- ZeroMQ socket bound
- ZeroMQ socket connected
- ZeroMQ socket disconnected
- ZeroMQ handshake succeeded
- ZeroMQ handshake failed
- ZeroMQ route unavailable
- ZeroMQ send rejected
- ZeroMQ reactor restarted
Every application envelope may carry a trace identifier77, parent span identifier78, deadline, sender component, target component, and message type.
TODO Secure Sento Remoting
Boundary decision
Use Sento remoting for direct Sento-to-Sento actor communication when location-transparent actor references are required.
Use ZeroMQ for explicit component, service, work, and event transport patterns where brokerless asynchronous messaging or non-Sento peers are useful.
Use Star Router79 for client-facing routing, heterogeneous services80, and application-level cross-process routing where the destination is not a raw Sento actor reference.
The three paths are adapters behind the same component-handle protocol. Application actors do not select raw sockets directly.
Safe serializer
Immediately change the default S-expression deserializer to bind:
(let ((*read-eval* nil))
(read-from-string string))
This removes reader evaluation81 but does not make arbitrary S-expressions a complete untrusted-data format.
Add a production serializer using an explicit schema82, bounded nesting, bounded collection sizes, and a type allowlist.
Explicit actor export
Remote peers must not address every local actor path.
Add an export registry containing exported logical name, local actor reference, allowed message types, allowed peers or peer capabilities, maximum payload size, maximum concurrent asks, queue policy, and audit hook.
Remote references resolve exported names rather than arbitrary internal paths unless an explicit development-only option enables path routing.
Peer identity and policy
Network envelope additions
Extend the envelope with protocol version, source actor-system identifier, source component identifier, destination export name, message identifier, correlation identifier, trace identifier, deadline, attempt number, content type, and principal metadata supplied by the transport.
Deadlines and errors
Carry the caller deadline over the network. Reject expired requests before dispatching them.
Use structured error envelopes for target not found, target not exported, access denied, unsupported message type, serializer failure, message too large, receiver overloaded, actor stopped, handler failure, timeout, and protocol mismatch.
Delivery semantics
Document the default semantics:
- remote
tell: at-most-once85 - remote
ask-s: at-most-once request attempt with one correlated response - remote
ask: at-most-once request attempt with one future result
Automatic retries are disabled by default.
A caller that enables retries must provide an idempotency key86 or explicitly accept duplicate processing.
TODO ZeroMQ Integration
Architectural role
ZeroMQ is an optional transport backend and process bridge.
ZeroMQ does not replace:
- local Sento actor mailboxes
- per-domain dispatchers
- Sento supervision
- the component registry
- local managed routers
- the Star Router client boundary
ZeroMQ transports messages between processes, languages, or runtime components after a component handle selects the ZeroMQ adapter.
Why an adapter is required
A ZeroMQ context87 may be shared between threads, but most classic ZeroMQ sockets are not thread-safe88. A socket must be created, used, and closed by its owning thread.
Sento actors on shared dispatchers may execute on different worker threads. They must never call a classic ZeroMQ socket directly.
The runtime therefore introduces a ZeroMQ reactor component that owns all socket calls on one dedicated thread.
Process topology
Each process contains:
Sento actor system
└── /internal/transports/zeromq
├── context-supervisor
├── zap-handler
├── monitor-collector
└── domain reactors
├── humint
├── socmint
├── sigint
├── cyber
├── bbp
└── threat-intel
One process-wide ZeroMQ context is the default.
A domain may create one reactor for the whole domain or separate reactors for subdomains when isolation, socket count, endpoint ownership, or measured load justifies it.
Multiple contexts require an explicit reason because every context owns its own internal ZeroMQ I/O threads and socket set.
Reactor component
A ZeroMQ reactor component contains:
- one supervisor actor on the domain control dispatcher
- one bounded outbound command queue89
- one dedicated reactor thread
- one or more sockets owned only by that reactor thread
- one poll loop90
- one pending-request table
- one endpoint registry
- one connection-monitor collector
- one serializer
- one policy adapter
- metrics and lifecycle state
The supervisor actor owns the reactor lifecycle. The reactor thread owns the sockets.
The supervisor and ordinary domain actors never call zmq_send, zmq_recv, zmq_close, zmq_bind, or zmq_connect directly.
Actor-to-reactor path
- A domain actor sends a normal Sento message to the ZeroMQ bridge actor.
- The bridge validates the component handle, schema, deadline, payload limit, and policy.
- The bridge places a transport command into the bounded outbound command queue.
- The reactor thread drains commands and performs socket operations.
- A send result or overload result is returned through the original Sento sender or correlation map.
Reactor-to-actor path
- The reactor poll loop receives a ZeroMQ message.
- The reactor validates frame count and hard size limits before allocation or decoding.
- The reactor decodes only the fixed transport header.
- The reactor submits the envelope to a domain ingress actor.
- The ingress actor performs schema validation, authorization, deadline checks, and target resolution.
- The ingress actor sends the payload to the destination component.
- Replies travel through the same reactor using the stored routing envelope and correlation identifier.
Polling model
The first implementation uses a dedicated reactor thread with a bounded command queue and a finite ZeroMQ poll timeout.
The loop alternates between:
- polling owned ZeroMQ sockets
- draining a bounded number of outbound commands
- expiring timed-out pending requests
- publishing metrics snapshots
- checking the stop flag
A later implementation may add a platform wakeup descriptor91 to interrupt the poll immediately when a new outbound command arrives.
A normal Sento pinned actor receive function must not block forever in zmq_poll because that would prevent its Sento mailbox from processing lifecycle commands.
Socket pattern map
ROUTER and DEALER
Use ROUTER92 and DEALER93 for asynchronous request, reply, command, and component messaging.
Default cross-process component topology:
Process A DEALER ───────► Process B ROUTER ingress Process A ROUTER ingress ◄─────── Process B DEALER
A process may maintain one DEALER per remote node or per policy class. One ROUTER ingress may serve many peers.
Do not use REQ and REP94 for the main runtime because their strict send-then-receive state machine makes concurrent requests, cancellation, and out-of-order replies harder.
REQ and REP remain permitted where an external protocol requires them, including the ZeroMQ Authentication Protocol handler.
XPUB and XSUB
Use XPUB95 and XSUB96 with a steerable proxy97 for selected cross-process event streams.
Suitable data:
- telemetry
- cache invalidation hints
- discovery announcements
- non-authoritative status events
- high-volume observation notifications whose loss is acceptable
Do not use PUB/SUB98 as the only channel for commands, authoritative lifecycle transitions, required replies, or any message that must be recovered after subscriber downtime.
The proxy control socket uses an internal inproc:// endpoint and supports pause, resume, and terminate.
PUSH and PULL
Use PUSH and PULL99 only for stateless, idempotent, one-way work distribution where no direct reply or keyed affinity is required.
Use ROUTER and DEALER when work needs a result, cancellation, deadlines, target selection, or key affinity.
PAIR
Use PAIR100 only for fixed one-to-one internal control channels, socket monitors, or proxy control. Do not use PAIR as a general service topology.
CLIENT and SERVER
Do not depend on CLIENT and SERVER101 in the initial implementation. Their availability and multipart limitations vary with libzmq build features and API maturity.
The stable initial implementation uses classic ROUTER and DEALER sockets with strict single-thread ownership.
Transport selection
inproc://: internal ZeroMQ control, ZAP, proxy control, and socket-monitor channels inside one processipc://: same-host cross-process communication when the operating system supports Unix-domain-style endpoints102tcp://: communication across hosts or containers
Normal same-process Sento actors use Sento messages, not inproc:// ZeroMQ, unless the message must cross into a ZeroMQ-owned reactor or external library.
Message framing
The ROUTER routing identity stays outside the application envelope.
Application multipart frame layout:
Frame 0: protocol magic and version Frame 1: message kind Frame 2: message identifier Frame 3: correlation identifier or empty Frame 4: trace identifier or empty Frame 5: source node and component Frame 6: target component export Frame 7: operation or event topic Frame 8: deadline Frame 9: content type and schema identifier Frame 10: flags Frame 11: payload
The transport layer rejects unexpected frame counts, oversized frames, unsupported versions, and malformed fixed-width fields before payload deserialization.
Supported message kinds:
tellaskreplyerroreventworkcancelheartbeat
Serialization
ZeroMQ is a transport, not a serializer.
The ZeroMQ adapter uses the same safe schema serializer defined for Sento remoting.
Never pass an untrusted network frame directly to Common Lisp read or read-from-string with reader evaluation enabled.
Binding decision
Create sento-zmq as a small ASDF system using CFFI103 against a pinned stable libzmq package.
The binding exposes only the reviewed functions and options used by this design.
The existing orivej/pzmq project may be used as a bootstrap reference or fork, but it must not be accepted without a compatibility layer and complete tests for the used surface. Its latest reviewed commit is from 2021, and its README states that functions outside examples and tests may be untested.
Required binding surface:
- context create, configure, shutdown, and terminate
- socket create and close
- bind, unbind, connect, and disconnect
- multipart message send and receive
- poll
- socket options
- socket monitor
- CURVE key and authentication options
- error-number and error-string access
- version query
The binding must represent byte vectors without converting binary payloads through strings.
Socket configuration defaults
Every socket specification declares:
- socket type
- bind or connect endpoints
- routing identifier
- send high-water mark
- receive high-water mark
- send timeout
- receive timeout
- immediate-connect behavior
- router-mandatory behavior
- linger deadline
- heartbeat settings
- reconnect settings
- maximum frame size
- security mechanism
- monitor events
Recommended runtime defaults:
- finite
ZMQ_LINGERrather than infinite linger - non-zero
ZMQ_SNDHWMandZMQ_RCVHWM ZMQ_IMMEDIATEenabled for outbound sockets where queuing before a connection would hide unavailabilityZMQ_ROUTER_MANDATORYenabled on ROUTER sockets so unroutable messages return an error rather than disappearing silently- non-blocking sends or finite
ZMQ_SNDTIMEO - finite receive polling intervals
- explicit heartbeat and reconnect policy
An EAGAIN104 result maps to a structured overload result. An EHOSTUNREACH105 result maps to a route-unavailable result.
Security
For tcp:// production endpoints, use CurveZMQ106 and ZAP107.
Each process runs one ZAP handler bound to:
inproc://zeromq.zap.01
The ZAP handler maps a client public key to:
- principal
- node identifier
- allowed component exports
- allowed operations
- tenant or organization
- quota class
- audit metadata
The ZAP handler starts before any accepting ZeroMQ socket.
For ipc:// endpoints, also apply file ownership and permission controls. IPC permissions do not replace application-level target and operation policy.
Do not use the PLAIN mechanism108 on an untrusted network because it does not provide confidentiality.
Backpressure
ZeroMQ backpressure is coordinated with Sento backpressure.
The path contains at least:
- Sento sender mailbox
- component ingress mailbox
- bridge command queue
- ZeroMQ per-peer send queue
- remote receive queue
- remote ingress mailbox
Every layer is bounded and has a declared policy.
High-water marks limit queued ZeroMQ messages per peer. Reaching a high-water mark may block, return EAGAIN, or drop messages depending on socket type and options.
The adapter must never assume that a successful local enqueue means the remote component processed the message.
Delivery semantics
ZeroMQ queues are memory-based and are not a durable message log109.
Default semantics:
- ROUTER/DEALER tell: at-most-once transport attempt
- ROUTER/DEALER ask: at-most-once transport attempt with application correlation
- PUSH/PULL work: at-most-once transport attempt
- PUB/SUB event: best-effort110 and may be missed by disconnected or late subscribers
Automatic retries are disabled by default.
A retry requires an idempotency key and a declared duplicate-handling policy.
A component that needs durable replay uses a database, event log, RabbitMQ111, or another declared durable broker rather than pretending ZeroMQ is durable.
Monitoring
Enable zmq_socket_monitor for connection-oriented sockets.
A dedicated monitor collector receives monitor events over an internal PAIR socket and converts them into typed Sento runtime events.
Monitor at least:
- connected
- connect delayed
- connect retried
- listening
- bind failed
- accepted
- accept failed
- closed
- close failed
- disconnected
- handshake succeeded
- handshake protocol failure
- handshake authentication failure
Do not expose native file descriptors from monitor events as stable actor state.
Proxy components
A steerable proxy may be used for:
- XPUB/XSUB event distribution
- ROUTER/DEALER broker topologies
- traffic capture for metrics or testing
Every proxy runs in a dedicated thread or process and has:
- frontend socket
- backend socket
- optional capture socket
- control socket
- supervisor child specification
- finite shutdown deadline
The control channel supports pause, resume, and terminate.
Supervision and restart
The ZeroMQ reactor supervisor treats these as failures:
- reactor thread exit
- context termination outside shutdown
- socket bind failure
- repeated authentication failure above policy threshold
- repeated poll failure
- unrecoverable serializer failure
- command queue corruption
- monitor channel failure
Restart rules:
- Stop component admission.
- Mark transport not ready.
- Fail or cancel pending requests with structured transport errors.
- Close sockets on the owning reactor thread.
- Join the reactor thread.
- Increase transport generation.
- Recreate sockets and endpoints.
- Wait for bind, connect, and authentication readiness.
- Reopen admission.
Replies carrying an old transport or component generation are rejected as stale.
Shutdown order
- Reject new transport work.
- Stop subscriptions and external admission.
- Drain the bridge command queue until the deadline.
- Resolve or cancel pending asks.
- Pause and terminate proxies.
- Close sockets on their owner threads using finite linger.
- Join reactor and monitor threads.
- Stop the ZAP handler after accepting sockets are closed.
- Shut down and terminate the process-wide ZeroMQ context.
- Continue normal Sento component and actor-system shutdown.
The context must never terminate while live sockets remain.
ZeroMQ public API sketch
(defpackage #:sento.zmq (:use #:cl) (:export #:define-zmq-transport #:define-zmq-endpoint #:start-zmq-runtime #:stop-zmq-runtime #:start-zmq-reactor #:stop-zmq-reactor #:bind-zmq-endpoint #:connect-zmq-endpoint #:disconnect-zmq-endpoint #:send-zmq #:ask-zmq #:cancel-zmq-request #:subscribe-zmq-topic #:unsubscribe-zmq-topic #:zmq-runtime-status #:zmq-reactor-status #:zmq-endpoint-status #:zmq-metrics))
Component-handle integration
A ZeroMQ component handle contains:
- transport kind
:zeromq - local reactor identifier
- remote node identifier
- remote component export
- endpoint identifier
- security policy identifier
- serializer identifier
- current component generation
- current transport generation
Sending through the handle resolves to the local domain reactor. The application actor never receives a raw socket pointer.
ZeroMQ validation requirements
- no classic ZeroMQ socket is called from more than one thread
- all socket creation and closure occur on the owner reactor thread
- one domain reactor failure does not stop sibling domains
- one subdomain reactor may restart without restarting the whole domain
- ROUTER mandatory mode returns structured route-unavailable errors
- high-water saturation returns structured overload results
- finite linger prevents shutdown from blocking forever
- malformed multipart messages are rejected before payload decoding
- old-generation replies are rejected
- expired deadlines are rejected before actor dispatch
- unauthorized CURVE keys are denied by ZAP
- allowed CURVE keys map to the correct principal and capabilities
- socket monitor events become typed runtime events
- proxy pause, resume, and terminate work under load
- disconnected PUB/SUB subscribers are documented as missing events
- process restart leaves no socket, context, or reactor thread leak
- component handles behave consistently across local, Sento-remoting, ZeroMQ, and Star Router adapters
TODO Public API Sketch
(defpackage #:sento.supervision (:use #:cl) (:export #:define-child #:define-supervisor #:start-supervisor #:stop-supervisor #:supervisor-status #:child-status)) (defpackage #:sento.components (:use #:cl) (:export #:define-component #:start-component #:stop-component #:restart-component #:component-ref #:component-status #:component-health #:component-ready-p #:register-component #:resolve-component)) (defpackage #:sento.managed-router (:use #:cl) (:export #:define-router-pool #:start-router-pool #:scale-router-pool #:stop-router-pool #:router-pool-status #:router-pool-metrics))
TODO Implementation Phases
Phase 0: pin and reproduce
- pin the reviewed Sento commit
- pin a stable libzmq package
- run Sento core tests
- run Sento remoting tests
- build a minimal CFFI ZeroMQ probe
- record thread counts and benchmark baseline
- add regression fixtures for discovered behavior
Phase 1: failure and termination core
- add failure-policy hook
- add failure classifier
- add structured termination record
- add actor generation
- update watching
- preserve compatibility mode
- test handler failure on shared and pinned dispatchers
Phase 2: mailbox control
- expose mailbox metrics
- add overload policies
- add drain and deadline stop modes
- add structured overload events
- test bounded queues under shutdown and restart
Phase 3: supervision
- implement child specifications
- implement supervisor actor
- implement restart classes
- implement one-for-one, one-for-all, and rest-for-one
- implement restart windows and backoff
- implement dependency startup and reverse shutdown
Phase 4: dispatcher trees
- implement domain dispatcher declaration
- implement subdomain dispatcher declaration
- implement thread-budget validation
- expose dispatcher metrics
- test domain saturation isolation
Phase 5: managed routers
- add routee removal and replacement
- add message-aware strategy protocol
- implement pool manager
- implement keyed routing
- implement draining scale-down
- implement routee failure replacement
Phase 6: components
- implement component definition
- implement component handles
- implement registry
- implement scoped event buses
- implement readiness and health
Phase 7: observability
- expose typed lifecycle events
- expose metrics snapshots
- add trace-context propagation
- add benchmark instrumentation
Phase 8: remoting hardening
- disable reader evaluation
- add schema serializer
- add actor export registry
- add peer policy
- require TLS in production mode
- add deadlines and structured errors
- document delivery semantics
- add quotas and cancellation
Phase 9: ZeroMQ binding and reactor
- create
sento-zmq - bind the required libzmq API through CFFI
- implement process context supervisor
- implement domain reactor and bounded command queue
- implement poll loop and socket ownership assertions
- implement ROUTER/DEALER component transport
- implement socket monitoring
- implement structured overload and route errors
Phase 10: ZeroMQ security and patterns
- implement CURVE key loading
- implement ZAP handler and principal mapping
- implement explicit component export policy
- implement XPUB/XSUB event bridge
- implement steerable proxy supervision
- implement optional PUSH/PULL work bridge
- implement IPC endpoint permissions
Phase 11: StarIntel integration
- consume component definitions from actor manifests
- create per-domain dispatcher trees
- start six domain components
- start selected domain or subdomain ZeroMQ reactors
- expose domain ingress handles
- select local, Sento remoting, ZeroMQ, or Star Router through component handles
TODO Validation Matrix
| Area | Required validation |
|---|---|
| Failure | A handler condition terminates only actors configured to stop or escalate |
| Compatibility | Existing actors keep resume behavior unless configured otherwise |
| Watching | Watchers receive termination reason and generation |
| Supervision | Every restart strategy matches declared child ordering |
| Restart limits | A crash loop stops after the configured restart intensity |
| Mailbox | Every overload policy is deterministic and measured |
| Shutdown | Drain, discard, deadline, and handoff modes behave as declared |
| Domain dispatchers | Saturating one domain does not starve another domain control plane |
| Subdomains | Saturating one subdomain does not block sibling subdomain control messages |
| Router | Routee failures are replaced without losing membership consistency |
| Keyed routing | Stable keys remain on one routee until a declared membership change |
| Event bus | Stopped subscribers are removed automatically |
| Metrics | Public APIs require no internal slot access |
| Remoting serializer | Reader evaluation input cannot execute code |
| Remoting export | Unexported actor paths cannot be reached remotely |
| Remoting policy | Unauthorized peers receive a structured denial |
| ZeroMQ ownership | Every socket is used by exactly one owner thread |
| ZeroMQ routing | Unroutable peers return errors rather than silent loss |
| ZeroMQ overload | High-water saturation maps to structured overload results |
| ZeroMQ security | CURVE and ZAP map authenticated keys to declared principals |
| ZeroMQ lifecycle | Reactor and proxy restart preserve generation and reject stale replies |
| Deadlines | Expired requests never enter actor mailboxes |
| Delivery | Retry behavior matches documented semantics |
| Shutdown | Complete runtime shutdown leaves no actor, dispatcher, timer, transport, proxy, socket, or reactor thread |
TODO Benchmark Plan
Measure:
- actor startup and shutdown time
- component startup and shutdown time
- thread count
- resident memory112
- messages per second
- p50, p95, and p99 latency113
- mailbox depth
- overload count
- restart time
- routee replacement time
- keyed-router movement
- domain saturation impact on other domains
- subdomain saturation impact on sibling subdomains
- local versus Sento-remoting versus ZeroMQ handle overhead
- ZeroMQ command-queue latency
- ZeroMQ ROUTER/DEALER throughput
- ZeroMQ multipart serialization cost
- ZeroMQ connection and authentication time
- proxy throughput
- serializer throughput
- connection reuse
Compare:
- one actor system with six domain dispatcher trees
- one actor system with six flat domain dispatchers
- six actor systems in one process
- six processes connected through Sento remoting
- six processes connected through ZeroMQ ROUTER/DEALER
- mixed Sento-remoting and ZeroMQ adapters selected by component handle
The default remains one actor system with per-domain dispatcher trees unless measurements show a concrete reason to change it.
TODO Open Decisions
- Whether core failure policy is implemented as actor slots, generic functions, or both
- Whether termination records replace or supplement old stop notifications by default
- Whether managed router wraps the current router or becomes a new actor type
- Whether dispatcher resizing belongs in the first release
- Which production serializer becomes the default
- Whether component handles implement the actor protocol directly
- Whether the ZeroMQ reactor uses one thread per domain or one thread per subdomain by default
- Whether the first reactor wakeup uses finite polling or a platform wakeup descriptor
- Whether
orivej/pzmqis forked or only used as a reference for a new narrow binding - Whether XPUB/XSUB proxies run inside each domain process or as separate broker processes
- Which messages are allowed on lossy PUB/SUB event bridges
- Whether Sento remoting and ZeroMQ share one schema envelope or use transport-specific outer envelopes with the same inner message
Footnotes and Glossary
TODO Citations
- Sento actor system: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/actor-system.lisp
- Sento actor context: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/actor-context.lisp
- Sento actor handling: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/actor.lisp
- Sento actor-cell failure handling: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/actor-cell.lisp
- Sento message boxes: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/mbox/message-box.lisp
- Sento queues: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/queue/queue.lisp
- Sento dispatchers: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/dispatcher.lisp
- Sento routers: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/router.lisp
- Sento event streams: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/eventstream.lisp
- Sento remoting state: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/specs/remoting-state.md
- Sento remoting integration: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/remoting/remoting.lisp
- Sento remote references: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/remoting/remote-ref.lisp
- Sento serializer: https://github.com/mdbergmann/cl-gserver/blob/a889b8375709ca9396bba5d06b6e460689a23716/src/remoting/serialization.lisp
- ZeroMQ core engine: https://github.com/zeromq/libzmq
- ZeroMQ socket API and thread-safety rules: https://libzmq.readthedocs.io/en/latest/zmq_socket.html
- ZeroMQ socket options: https://libzmq.readthedocs.io/en/latest/zmq_setsockopt.html
- ZeroMQ socket monitoring: https://libzmq.readthedocs.io/en/latest/zmq_socket_monitor.html
- ZeroMQ steerable proxy: https://libzmq.readthedocs.io/en/latest/zmq_proxy_steerable.html
- ZeroMQ Authentication Protocol: https://rfc.zeromq.org/spec/27/
- CurveZMQ: https://rfc.zeromq.org/spec/26/
- ZMTP CURVE mechanism: https://rfc.zeromq.org/spec/25/
- PZMQ Common Lisp binding: https://github.com/orivej/pzmq
- Erlang supervision principles: https://www.erlang.org/doc/system/sup_princ.html
Footnotes:
Sento: The Common Lisp actor framework implemented by the mdbergmann/cl-gserver repository. It supplies actors, mailboxes, dispatchers, routers, timers, event streams, and remoting.
Actor runtime: Software that creates actors, delivers their messages, schedules their work, tracks their lifecycle, and shuts them down.
Gserver: A managed service built from one or more actors. In this design it means a component with a supervisor, ingress, dispatchers, workers, lifecycle state, and metrics.
Actor system: The top-level Sento container that owns actor contexts, dispatchers, timers, the default event stream, and system-wide runtime resources.
Node: One running Sento endpoint with its own actor-system identity and optional network address.
StarIntel: The larger document-driven intelligence search and analysis platform that consumes Sento as its in-process actor runtime.
Remoting: Sending actor messages between separate actor systems over a network connection.
ZeroMQ: A brokerless messaging library that provides asynchronous message sockets, message queues, routing patterns, and several transport types.
libzmq: The C and C++ core engine that implements ZeroMQ sockets and the ZeroMQ Message Transport Protocol.
Actor: A small independent software unit that owns private state and processes messages one at a time.
Actor context: The container attached to an actor or actor system that owns its immediate child actors.
Actor path: A hierarchical name such as /user/domains/cyber/ingress that identifies an actor's position in an actor tree.
Class: A Common Lisp Object System definition describing the data and behavior of object instances.
Lifecycle hook: A function called automatically at a specific point such as actor startup or actor shutdown.
Watching: Registering one actor or context to receive a notification when another actor stops.
Dispatcher: A named pool of worker actors and threads that executes work taken from actor mailboxes.
Mailbox: The per-actor queue that stores messages waiting to be processed.
Queue: A data structure that stores items until they are removed for processing, normally in first-in, first-out order.
Router: A software object that chooses one or more worker actors, called routees, to receive a message.
Event stream: A publish-and-subscribe message bus where publishers send events and subscribed actors receive matching events.
Future: An object representing a result that may become available later.
Task: A short-lived actor-backed operation used to execute a function asynchronously or on a selected dispatcher.
FSM: Finite-State Machine. A model whose behavior is organized as named states and transitions caused by events.
Stash: Temporary storage for actor messages that cannot be processed yet and will be put back into the mailbox later.
Wheel timer: A timer implementation that groups future deadlines into rotating time slots for efficient scheduling.
Actor reference: A value used to send messages to an actor without directly calling its implementation.
TCP: Transmission Control Protocol. A reliable ordered byte-stream protocol used for network connections.
TLS: Transport Layer Security. A protocol that encrypts network traffic and can authenticate the systems at both ends.
Serializer: Code that converts a message object into bytes for storage or network transfer and reconstructs the object later.
Serious condition: A Common Lisp condition representing an error or other event serious enough to interrupt normal processing.
Termination record: A structured description of why, when, and how an actor stopped.
Overload policy: A declared rule for what happens when a queue or worker pool cannot accept more work.
Drain mode: A shutdown behavior that finishes queued work before stopping instead of discarding it immediately.
Observability: Runtime information such as metrics, events, traces, and status that lets operators understand what the system is doing.
Correlation identifier: A unique value attached to a request and its response so the caller can match them.
S-expression: The parenthesized data notation used by Lisp, such as (task :id 1).
Export registry: A list of explicitly approved local actors or logical services that remote peers are allowed to address.
Delivery guarantee: The documented promise about whether a message may be lost, duplicated, reordered, or retried.
Quota: A limit assigned to a caller or peer, such as maximum queued messages or concurrent requests.
Process: One operating-system instance of a running program with its own memory space and threads.
Managed component: A named actor subtree controlled by a supervisor and exposed through a stable handle.
Supervisor: An actor that starts child actors, watches them, restarts them according to policy, and shuts them down in order.
Ingress actor: The declared entry actor through which outside components submit work to a component.
ZeroMQ reactor: A supervised component with a dedicated thread that owns ZeroMQ sockets, polls them, sends outbound messages, and forwards inbound messages to Sento actors.
Process isolation: Separation created by running software in different operating-system processes so one process cannot directly access another process's memory.
Failure policy: The configured action taken when an actor handler raises a condition.
Failure directive: The specific decision returned by a failure policy, such as resume, stop, or escalate.
Backward compatibility: Preserving existing behavior so older code continues to work after the runtime changes.
Generation: A number increased each time a logical actor, component, or transport is recreated.
Incarnation: One specific running instance of a logical actor name across possible restarts.
Deadlock: A state where two or more operations wait on each other forever and none can continue.
Consistent hash: A routing method that moves only part of the key space when workers are added or removed.
Rendezvous hash: A routing method that scores every worker for a key and chooses the highest-scoring worker, giving stable assignment with limited movement.
Broadcast: Sending the same message to every routee instead of selecting one.
Actor-system identifier: A stable unique name for one actor-system instance.
ASDF: Another System Definition Facility. The standard Common Lisp tool used to define systems, source files, dependencies, and test operations.
Child specification: A declarative record describing how a supervisor starts, monitors, restarts, and stops one child.
Restart strategy: A rule defining which children restart when one child fails.
Exponential backoff: Increasing the delay between repeated retries, commonly doubling the wait after each failure.
Jitter: A small random change added to retry delays so many failing workers do not all retry at the same instant.
DAG: Directed Acyclic Graph. A one-way dependency graph that contains no path leading back to its starting point.
Readiness: Whether a component is prepared to accept new work.
Health: Whether a component is operating correctly within its declared limits.
Component handle: A stable reference used to send work to a component without exposing whether it is local or remote.
Router pool: A managed set of equivalent worker actors selected by a router.
Routee: One worker actor that may be selected by a router.
Keyed routing: Selecting a worker from a value in the message so related messages reach the same worker.
Control plane: Actors and messages that manage lifecycle, routing, policy, and status rather than performing the main application work.
Data plane: Actors and messages that perform the main application workload.
I/O: Input and Output. Work that waits on files, networks, devices, databases, or other external systems.
CPU: Central Processing Unit. The hardware that executes program instructions; CPU-heavy work spends most of its time computing rather than waiting on external systems.
ZeroMQ I/O thread: An internal thread created by libzmq to move network data between application sockets and operating-system transports.
Thread budget: The maximum number of operating-system threads the process is allowed or expected to create.
Backpressure: A method for slowing or rejecting new work when downstream workers cannot keep up.
High-water mark: A configured maximum number of queued messages for a ZeroMQ peer connection.
Admission control: A decision at the system entrance that accepts or rejects work before it consumes deeper resources.
Trace identifier: A value shared by all operations belonging to one end-to-end request.
Span: One timed operation inside a larger distributed trace.
Star Router: StarIntel's client-facing and application-level cross-process routing layer.
Heterogeneous service: A service implemented with a different runtime, programming language, or communication model from Sento actors.
Reader evaluation: Common Lisp reader behavior where special syntax can execute Lisp code while reading data.
Schema: A formal definition of allowed fields, types, limits, and structure for a message or document.
Certificate identity: The authenticated name or attributes read from a peer's TLS certificate.
Principal: The verified identity used by an authorization decision, such as a service, user, or node.
At-most-once: A delivery rule where a message is attempted zero or one times, so it may be lost but is not automatically duplicated by retries.
Idempotency key: A unique request value that lets a receiver recognize and safely ignore a duplicate operation.
ZeroMQ context: The process-level libzmq object that owns ZeroMQ sockets and internal I/O threads.
Thread-safe: Safe for multiple threads to use at the same time without corrupting state or causing races.
MPSC queue: Multiple-Producer, Single-Consumer queue. Many actor threads may add commands while one reactor thread removes and processes them.
Poll loop: A repeated loop that waits for activity on one or more sockets and then processes the ready sockets.
Wakeup descriptor: An operating-system pipe, event descriptor, or socket used to interrupt a blocked poll loop when control work arrives.
ROUTER socket: A ZeroMQ socket that receives a routing identity with each incoming message and can send a reply to a selected peer identity.
DEALER socket: An asynchronous ZeroMQ request socket that can send multiple requests without waiting for each reply in strict order.
REQ and REP: ZeroMQ request and reply sockets with a strict alternating send and receive state machine.
XPUB: Extended publish socket. It sends published messages and also reports subscription and unsubscription activity from peers.
XSUB: Extended subscribe socket. It receives published messages and forwards subscription commands, commonly as the backend of a proxy.
Steerable proxy: A built-in ZeroMQ message proxy that can be paused, resumed, or terminated through a control socket.
PUB/SUB: Publish and Subscribe. A one-to-many messaging pattern where subscribers receive topics they selected while connected.
PUSH/PULL: A ZeroMQ pipeline pattern where PUSH distributes one-way work and PULL receives it.
PAIR socket: A ZeroMQ socket intended for one fixed peer, commonly used for internal control or monitoring channels.
CLIENT and SERVER sockets: A newer thread-safe ZeroMQ request and service pattern with different framing rules from classic ROUTER and DEALER sockets.
IPC endpoint: An Inter-Process Communication endpoint used by processes on the same host, commonly represented by a filesystem path.
CFFI: Common Foreign Function Interface. A Common Lisp library for calling functions and using data types from C libraries.
EAGAIN: An operating-system-style error meaning the operation cannot complete immediately and may succeed later.
EHOSTUNREACH: An operating-system-style error meaning the selected destination cannot currently be routed to.
CurveZMQ: ZeroMQ's public-key encryption and authentication protocol based on Curve25519 cryptography.
ZAP: ZeroMQ Authentication Protocol. An in-process request and reply protocol used by ZeroMQ servers to ask an authentication handler whether a peer is allowed.
PLAIN mechanism: A ZeroMQ username-and-password authentication method that does not itself encrypt the credentials or message traffic.
Durable message log: Storage that persists messages so they survive process failure and can be replayed later.
Best-effort: A delivery model that attempts to send data but does not guarantee that every receiver obtains it.
RabbitMQ: A message broker that stores and routes messages through queues and exchanges and can provide durable delivery features.
Resident memory: The portion of a process's memory currently held in physical memory.
Percentile latency: A response-time measurement such as p95, meaning ninety-five percent of measured operations finished at or below that time.