The Standard Library as Architecture
Most of Aikido’s important runtime structure is expressed with ordinary Rust types rather than framework machinery.
HashMap: dynamic identity and owned state
HashMap<String, ContractRuntimeState> means a deployment executor can discover
contracts dynamically while retaining exactly one owned state record per
normalized contract ID. HashMap::entry performs initialize-if-absent without
duplicating lookup logic.
Source: ensure_contract_runtime
The same collection expresses different invariants elsewhere:
- synthetic positions keyed by strategy, deployment, instrument, and lane;
- router accounts and open positions keyed by normalized identity;
- recently seen intent IDs keyed to time buckets for deduplication.
The key type is part of the architecture: it states what the system considers the same thing.
Arc: shared lifetime, not shared mutation
Arc<T> lets independently spawned tasks own the same long-lived service or
shutdown flag. It does not make T mutable or thread-safe by itself.
Examples include Arc<AtomicBool> for shutdown and Arc<FleetGuardrails> for
a shared service. The inner type still determines the mutation protocol.
Mutex and RwLock: snapshots with short critical sections
Arc<Mutex<StrategyRunner>>permits hot-reloadable strategy state while one engine evaluates it exclusively.Arc<RwLock<RoutingSnapshot>>permits frequent read snapshots with rarer publication updates.- UI state uses
Arc<Mutex<DeploymentState>>because it is shared display and operator state, not the account’s primary execution owner.
Poisoning is sometimes treated as fatal with expect or unwrap, and sometimes
converted into anyhow::Error. That choice reveals whether corrupted shared
state is considered recoverable at that boundary.
Atomics: independent facts
AtomicBool represents the monotonic request to shut down. Engine statistics
use atomic counters because each metric is independently observable and does
not require a consistent multi-field transaction.
An atomic would be a poor replacement for positions or a routing plan: those values have relationships that must change together.
Enums: closed command protocols
ExecutorCommand models every request the account owner understands, including
signals, reconcile, flatten, converge, manual operations and shutdown.
ExecutorStateUpdate models the smaller feedback protocol.
The compiler forces each exhaustive match to confront new variants. This is
stronger than passing strings or loosely shaped JSON between in-process tasks.
Option and Result: absence versus failure
Option<&mut BrokerClient>means dry/deferred execution may legitimately have no active broker reference.Result<T>means an attempted operation failed.Option<oneshot::Sender<Result<(), String>>>means a command may optionally request a direct completion response.
Keeping these cases distinct prevents “not applicable,” “not yet connected,” and “failed” from collapsing into one ambiguous null or boolean.