# Event contracts ## Envelope All bus messages use this envelope: ```json { "event_id": "string", "event_type": "string", "venue": "string", "source": "string|null", "schema_version": 1, "observed_at": "ISO-8601|null", "ingested_at": "ISO-8601", "payload": {}, "raw": {} } ``` ## Topics Current canonical topic set: - `raw.near_intents.quote` - `norm.swap_demand` - `cmd.execute_trade` - `exec.trade_result` In Kubernetes bootstrap, Redpanda topic creation is currently handled by the repo-managed bootstrap job applied with the manifest set. ## `raw.near_intents.quote` - `event_type`: `near_intents_quote_raw` - `payload.message`: original venue-native payload - `raw`: original venue-native payload ## `norm.swap_demand` - `event_type`: `swap_demand` - payload: - `quote_id` - `asset_in` - `asset_out` - `amount_in` - `amount_out` - `ttl_ms` ## `cmd.execute_trade` - `event_type`: `execute_trade` - payload: - `command_id` - `idempotency_key` - `execution_key` - `quote_id` - `asset_in` - `asset_out` - `amount_in` - `amount_out` - `reason` ## `exec.trade_result` - `event_type`: `trade_result` - payload: - `command_id` - `idempotency_key` - `execution_key` - `quote_id` - `status` - `result_code` - `note` ## Executor idempotency model - `command_id` is unique per trade command and currently deterministic as `cmd-${quote_id}` - `idempotency_key` is stable for semantic duplicate detection and currently `${venue}:${quote_id}` - `execution_key` is the stable partition key and currently `${venue}:${asset_in}->${asset_out}` - executor persists command state on durable storage before publishing a result - already-completed `command_id`s are skipped on replay or restart - if a command is seen again after a persisted `processing` state, the executor emits a recovered result path instead of blindly duplicating work ## Deployment and persistence implications These contracts are tied to deployment behavior: - executor duplicate suppression depends on durable persistence at `EXECUTOR_STATE_DIR` - local Compose mounts that path for development/runtime testing - the Hetzner single-node k3s path mounts persistent storage for the executor at `/var/lib/unrip/executor-state` - in the current single-node target, that persistence is node-backed and should be treated as required operational state Operational consequence: - deleting the executor PVC or losing the node without migration discards idempotency history - that can allow already-seen commands to be treated as new after recovery