Ingest lanes
The producer-side channels every venue adapter holds — lossless where a missed message is a hole, latest-wins where only the freshest value matters — and why they live one crate below the core that drains them.
Everything that reaches the execution core arrives on one
ingest channel, and crates/vike-exec/src/lanes.rs owns the producer half of it: the sender
handles a venue adapter holds and the payload types they carry. The consumer — the single-writer
core thread — lives in vike-core. The header states why the split is where it is: venue bridges
depend on vike-exec but never on vike-core, so a bridge can push into the core without linking
the runtime that drains it.
One message type, several disciplines
Ingest is the one enum on the channel. Its variants sort into lanes by what losing a message
would mean:
Event— a canonical venue event, the hot-path variant. It rides unboxed on purpose: the comment beside the enum records that boxing it would trade a 240-byte move for a per-event heap allocation on exactly the path the p99 < 10 µs gate protects. Commands, which are rare, are boxed.Command— everything an outside thread may ask of the core, below.Market— a marker with no payload; the tick itself rides a conflation slot.BarSeed/BarClose— the bar lanes, lossless: a missed close is a hole in the series. Forming-bar updates conflate with the ticks instead.Quote/Trade/Book— the tick lanes, lossless and dispatched per update to a mounted strategy's tick handlers; they touch no parity-gated order-management fold path.Watchdog— the opt-in stuck-order sweep tick of the watchdog.StreamStatus/Flow— occasional control events: a feed-health transition delivered toStrategy::on_feed_status, and a per-side flow-toxicity update delivered toStrategy::on_flow. Both fire on a transition or at their own cadence, never per market message; neither is journaled.
Every lossless sender returns CoreGone when the core thread has exited, so a producer learns the
channel is closed rather than blocking on it. The wait-free market lane reports nothing —
MarketSender::publish returns no result at all, and a marker that cannot be queued is simply
retried on the next publish.
Lossless senders back-pressure the feed
EventSender is the lane every adapter pushes canonical events into — send from an async task,
blocking_send from a plain thread. Both back-pressure the producer and never drop. The handle
also carries an optional route_key, set by EventSender::routed at the mount: it stamps the key
onto the three venue-tagged payloads that carry no client-order-id — AccountState, Funding and
PositionLiquidated — so the core's router can fold them into the right engine when a venue runs
more than one account. Fill is deliberately left alone: it names its
order, which the router resolves exactly, and stamping it would put a second key on the one wire
shape the frozen parity fixtures pin. A key equal to the payload's own venue stamps nothing, which
keeps every single-account box's journal bytes identical. The stamp takes the event by &mut
because blocking_send sits inside the measured core hop — the
latency gate feeds Ingest::Event(Event::Fill) through exactly
this call.
BarSender (seed, close) and TickSender (quote, trade, book, stream_status, flow)
are blocking-lossless for the same reason: each quote, trade or book update is a distinct event a
strategy may act on. The book rides behind an Arc, not by value — the BookUpdate doc records
the audit finding that carrying it by value deep-cloned two whole BTreeMaps (up to a 1000-level
seed) on the pump thread and paid the matching drop on the fold thread; with an Arc the send
is a refcount bump, a pump mutates its own standing copy through Arc::make_mut, and the wire
bytes are pinned identical to the pre-Arc shape.
The market lane is latest-wins and wait-free
MarketSender is the exception, and the discipline inverts. A price tick for a (venue, symbol) is
written into a per-symbol slot — the newest overwrites, and an overwrite of a still-pending tick is
counted into conflated_market_drops — then at most one Ingest::Market marker is armed with
try_send. If the ingest queue is momentarily full the marker is not lost: marker_in_flight
stays false and the next publish retries it, and because ticks refresh continuously the slot can
never go stale while the feed is alive. The publish is wait-free and safe from tokio tasks and
plain threads alike. Three slot maps live under one lock — real venue marks, candle-close ticks and
forming bars — and marks and bar-closes are kept apart so a one-second mark stream can never
conflate away a kline feed's close for the same symbol; they fill different slots of the
price board downstream.
Commands, and the one write contract
Command is the session-control vocabulary: Order, UpdateParams, SetTradingState,
SetMargin, ApplySnapshot, ReconcileReports, ConfirmRecon, MountStrategy,
UnmountStrategy, Shutdown. These are control verbs rather than market messages, and
UpdateParams, SetMargin, ReconcileReports and the two mount verbs each say so in their own
doc — occasional, off the p99 event fold. The two mount verbs are deliberately not journaled,
because a mount-less replay core could never re-resolve a strategy. The
control boundary is the surface these arrive through.
Command::Order wraps OrderIntent — the one write contract. Every order-scoped instruction,
whether from the external command path or from a mounted strategy's broker drain, lowers into the
core's single apply_intent site, so minting a client-order-id and crossing the risk gate are
structural on every order path. The verbs: Submit, SubmitBatch, Cancel, CancelBatch,
Modify, Confirm, MassCancel, Flatten, MarketExit, Bracket, ArmConditional,
DisarmConditional and Combo (declared on the wire; its own doc marks the lowering as pending).
Arming an emulated conditional bypasses the gate — only its
fire crosses it — and so does disarming one.
The panic button works from a halted core, and it is not atomic
MarketExit is a compound verb: the runtime expands it at apply time into one MassCancel first,
then one Flatten per non-flat BOTH-side position — a hedge-mode long or short leg would resolve
a size of zero, so it is skipped — each lowered through the same apply_intent site. It has no
precondition — a position-covered reduce is admitted under halt, which is
exactly the shape a flatten mints, unless the position sits off the lot grid, where the rounded-up
size no longer covers it and that leg is denied under Halted. Its own doc records that this is
the reverse of the rule the verb carried for its whole earlier life, when an operator had to
un-halt in order to escape. It is also best-effort: against a real venue the mass-cancel is
fire-and-forget over the adapter's actor thread, its acknowledgements may land after the flatten
orders are already on the wire, and a resting order can still fill after a flatten leg. Re-issue
the exit if the board is not flat afterwards.
Two test-support constructors ship with the lanes: event_channel hands back a raw EventSender
plus the receiver with no core behind it, so an adapter test can observe exactly what a client
pushes, and market_data_channel is its bar/market twin.
The event bus
A defer-and-deliver FIFO whose delivery order is load-bearing, whose handler reports whether it actually folded an event, and whose drain guard salvages the event a panic was holding.
The account
Positions and realized PnL are a read model folded from the fill stream, with one writer, no equity cache, insertion-ordered sums pinned by the parity gate, and a fill-dedup ledger welded to the money it protects.