Skip to content

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/marketKlineEvent (subject market.klines.{venue}.{market}.{symbol_lc}.{tf})
  • bus/intentsOrderIntentEvent (subject intents.executor)
  • bus/riskRiskCommandEvent (subject risk.commands), BreakerEvent (subject risk.events.{breaker_lowercase})
  • bus/tradingFillEvent, TRADING_FILLS_SUBJECT_PREFIX (subject trading.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 legacy gordon-contracts-schemas name to avoid breaking gordon-console's import path.

Schema versioning rules (non-negotiable)

  1. schema_version: u16 is the first field of every payload.
  2. Every other field carries #[serde(default)].
  3. Additive only — never rename, never remove.
  4. Adding a field bumps gordon-protocol minor.
  5. 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 patternProducerConsumer(s)
market.klines.binance.{spot|perp}.{symbol_lc}.{tf}gordon-datagordon-bot
intents.executorgordon-botgordon-executor (durable executor-default)
risk.commandsgordon-riskgordon-executor (durable executor-risk)
risk.events.{breaker_lowercase}gordon-riskgordon-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 FillEventgordon_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) — TraceId embedded in EventEnvelope for W3C trace propagation.
  • gordon-domain — domain primitive types referenced in payload structs.
  • serde — all payloads are Serialize + 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

Gordon — keep compounding without blowing up