doran/docs/contracts.md
2026-03-28 20:53:29 +01:00

85 lines
2.5 KiB
Markdown

# 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