gordon-protocol
Purpose
Published-language crate for the Gordon platform. Owns every event type that flows over the gordon-bus JetStream spine — NATS subjects, payload structs, and the AsyncAPI 3.0 schema fragments consumed by the console's TypeScript client. Renamed from gordon-contracts at the 7.0 split (2026-05-15); the pre-split crate held five different responsibilities (errors, trace, domain types, bus wire, execution trait) and rebuilt every consumer on any change. The split isolates each role along its churn rate: errors + trace in gordon-kernel, business types in gordon-domain, bus wire payloads here.
Version + status
7.2.1 — stable bus topology, additive-only evolution. Minor bumps add fields or new event types; major bumps coordinate across every consumer (rare).
Public surface
All types under gordon_protocol::bus::*:
bus/market—KlineEvent(subjectmarket.klines.{venue}.{market}.{symbol_lc}.{tf})bus/intents—OrderIntentEvent(subjectintents.executor)bus/risk—RiskCommandEvent(subjectrisk.commands),BreakerEvent(subjectrisk.events.{breaker_lowercase})bus/trading—FillEvent,TRADING_FILLS_SUBJECT_PREFIX(subjecttrading.fills.{bot_id})
AsyncAPI artifacts:
asyncapi/schemas.yaml— AsyncAPI 3.0 fragments dual-published to npm as@dlepaux/gordon-contracts-schemas. The npm package keeps the legacygordon-contracts-schemasname to avoid breaking gordon-console's import path.
Schema versioning rules (non-negotiable)
schema_version: u16is the first field of every payload.- Every other field carries
#[serde(default)]. - Additive only — never rename, never remove.
- Adding a field bumps gordon-protocol minor.
- A contract test is required per type under
tests/it_bus_*_schema.rs.
The 24h NATS retention window is the reason: a rolling deploy can have new producers and old consumers (or vice-versa) decoding each other's payloads for hours.
NATS subjects
Single JetStream stream gordon-bus, 168h retention, 768 MiB.
| Subject pattern | Producer | Consumer(s) |
|---|---|---|
market.klines.binance.{spot|perp}.{symbol_lc}.{tf} | gordon-data | gordon-bot |
intents.executor | gordon-bot | gordon-executor (durable executor-default) |
risk.commands | gordon-risk | gordon-executor (durable executor-risk) |
risk.events.{breaker_lowercase} | gordon-risk | gordon-manager (durable manager-risk) |
trading.fills.{bot_id} | gordon-executor | (consumers TBD) |
Mirror discipline
OrderIntentEvent here mirrors gordon_domain::types::intents::OrderIntent but is a separate type. The in-process type is free to gain non-serialisable fields; the wire type evolves additive-only and decodes across deploy versions. Same pattern for FillEvent — gordon_domain::execution::FillEvent is the lifecycle type; gordon_protocol::bus::trading::FillEvent is the bus mirror.
Publication
Dual-published — one version bump ships both:
- Rust crate → kellnr (
publish = ["gordon"]) - npm package → GitHub npm registry,
@dlepaux/gordon-contracts-schemas
Both version tracks move together (e.g., gordon-protocol 7.x = @dlepaux/gordon-contracts-schemas 7.x).
Dependencies of note
gordon-kernel(^2) —TraceIdembedded inEventEnvelopefor W3C trace propagation.gordon-domain— domain primitive types referenced in payload structs.serde— all payloads areSerialize + Deserialize.
Invariants
- Bus payloads only. No domain math, no error taxonomy, no HTTP.
- Additive-only minors. Renames, type changes, and removals are major bumps and require a coordinated rollout.
- Contract test per type.
- Zero
#[allow(...)].
Where it lives
- Repo:
gordon-protocol/ - kellnr:
https://kellnr.lepaux.com/crates/gordon-protocol(LAN-only) - npm:
@dlepaux/gordon-contracts-schemas
Related
- gordon-bus — the transport layer that ferries these payloads.
- gordon-domain — in-process mirrors of the bus types.
- gordon-kernel —
TraceIdwire scalar. - Architecture: Event Bus Topology