Proof: Preserve the completed first live BTC/EURe trade loop and establish the next approved implementation proof around pre-credit funding visibility and operator alerts. Assumptions: The live-trade loop is sufficiently proven by the recorded deposits, withdrawals, durable command/result chain, and successful mainnet quote responses; the next highest-value slice is operational visibility rather than new execution breadth. Still fake: The newly opened funding-visibility and alert turn is planning only; no pre-credit watcher or durable alert evaluator is implemented yet.
235 lines
7.1 KiB
Markdown
235 lines
7.1 KiB
Markdown
# Implementation Turn: pre-credit funding visibility and operator alerts
|
|
|
|
Status: open
|
|
Opened: 2026-04-02
|
|
|
|
## Goal
|
|
Make the already-live BTC/EURe loop operationally understandable between external funding and spendable credit, and make critical stale or failed states queryable as durable alert records instead of transient logs.
|
|
|
|
## Selected backlog items
|
|
- [O003] Alerts for stale reference prices, stale inventory state, stuck funding actions, and failed executor submissions.
|
|
- [O004] Pre-credit funding visibility for slow chains: watch configured deposit addresses at chain level, track inbound transfers through mempool and on-chain confirmation before bridge credit, persist that state separately from spendable inventory, and alert operators when funding is seen, delayed, or stuck.
|
|
|
|
## Design rule
|
|
Keep the already-proven execution and inventory truth path intact:
|
|
- verifier and bridge credit remain the only spendable truth
|
|
- pre-credit visibility is additive observability
|
|
- alerts are additive operability
|
|
|
|
## Event backbone
|
|
Retain Kafka as the backbone. Add only the minimal new topics required:
|
|
|
|
- `ops.funding_observation`
|
|
- `ops.alert`
|
|
|
|
These topics are append-only evidence streams, not control planes.
|
|
|
|
## Durable store
|
|
Extend PostgreSQL with new append-only families:
|
|
- `funding_observations`
|
|
- `ops_alerts`
|
|
|
|
If a current-state materialization is needed, derive it from append-only records or keep it as a clearly named snapshot table. Do not replace the append-only record.
|
|
|
|
## Service changes
|
|
|
|
### 1. `liquidity-manager`
|
|
Extend the existing treasury owner instead of inventing a broad new funding stack.
|
|
|
|
New responsibilities:
|
|
- retain active funding handles by chain and asset
|
|
- poll configured chain observers for those handles
|
|
- emit `ops.funding_observation`
|
|
- correlate chain observations with bridge `recent_deposits`
|
|
- expose latest observations and credit-correlation state through `/state`
|
|
|
|
Expected state shape additions:
|
|
- `funding_observations_by_handle`
|
|
- `latest_funding_observation_at`
|
|
- `uncredited_funding_total_by_asset`
|
|
- `credit_correlation`
|
|
|
|
Control additions:
|
|
- `POST /refresh-funding-observations`
|
|
- optional `POST /pause-funding-observer`
|
|
- optional `POST /resume-funding-observer`
|
|
|
|
Important implementation constraints:
|
|
- do not change withdrawal behavior
|
|
- do not reuse spendable inventory fields for pre-credit state
|
|
- keep BTC and EURe observation records in one shared schema
|
|
|
|
### 2. `inventory-sync`
|
|
Keep current spendable accounting intact.
|
|
|
|
Possible additions:
|
|
- read the latest funding observations
|
|
- expose a separate `pre_credit_inbound` or `funding_visibility` field in `/state`
|
|
|
|
Hard rule:
|
|
- `spendable`, `pending_inbound`, and strategy-facing credited truth must not become looser
|
|
|
|
### 3. `history-writer`
|
|
Consume and persist the new topics:
|
|
- `ops.funding_observation`
|
|
- `ops.alert`
|
|
|
|
Expose through `/state`:
|
|
- latest funding-observation write time
|
|
- latest alert write time
|
|
- counts or offsets for the new topics
|
|
|
|
Add query-friendly indexes for:
|
|
- `tx_hash`
|
|
- `funding_handle`
|
|
- `alert_code`
|
|
- `ingested_at`
|
|
|
|
### 4. `ops-sentinel` or equivalent alert evaluator
|
|
Add one small service only if needed to keep alert logic separate and testable.
|
|
|
|
Responsibilities:
|
|
- consume:
|
|
- `ref.market_price`
|
|
- `state.intent_inventory`
|
|
- `ops.liquidity_action`
|
|
- `ops.funding_observation`
|
|
- `exec.trade_result`
|
|
- evaluate policy windows for stale and stuck conditions
|
|
- emit `ops.alert` raise/clear transitions
|
|
- expose current alert state
|
|
|
|
Preferred alert model:
|
|
- stable `alert_code`
|
|
- `status`: `raised` or `cleared`
|
|
- `severity`
|
|
- `reason`
|
|
- `first_raised_at`
|
|
- `last_evaluated_at`
|
|
- correlation IDs when available
|
|
|
|
Minimal alert set for this turn:
|
|
- `reference_price_stale`
|
|
- `inventory_snapshot_stale`
|
|
- `funding_seen_unconfirmed`
|
|
- `funding_confirmed_credit_pending`
|
|
- `funding_stuck`
|
|
- `executor_submission_failed`
|
|
|
|
Do not add Slack, email, or paging integrations in this turn unless required to prove the path. Durable alert records plus HTTP state are sufficient.
|
|
|
|
## Chain observer plan
|
|
|
|
### BTC
|
|
Must be the first-class proof path.
|
|
|
|
Implementation expectations:
|
|
- configurable observer endpoint
|
|
- look up the configured BTC deposit address
|
|
- detect:
|
|
- mempool appearance when available
|
|
- confirmation count
|
|
- credited transition once bridge/verifier catches up
|
|
|
|
Assumption to keep explicit in code:
|
|
- a chain observer can disappear or lag independently of the bridge
|
|
|
|
### Gnosis / EURe
|
|
Nice-to-have within the same schema, but BTC is the proof-critical path.
|
|
|
|
If included this turn:
|
|
- watch the configured deposit address for EURe token transfers
|
|
- represent observation state in the same event model
|
|
|
|
## Record shapes
|
|
|
|
### `ops.funding_observation`
|
|
Required fields:
|
|
- `funding_observation_id`
|
|
- `account_id`
|
|
- `asset_id`
|
|
- `chain`
|
|
- `funding_handle`
|
|
- `source`
|
|
- `tx_hash`
|
|
- `status`
|
|
- `amount`
|
|
- `confirmations`
|
|
- `first_seen_at`
|
|
- `last_seen_at`
|
|
- `credited_at` when known
|
|
- `bridge_deposit_tx_hash` when correlated
|
|
|
|
### `ops.alert`
|
|
Required fields:
|
|
- `alert_event_id`
|
|
- `alert_code`
|
|
- `status`
|
|
- `severity`
|
|
- `reason`
|
|
- `service_scope`
|
|
- `pair` when relevant
|
|
- `asset_id` when relevant
|
|
- `tx_hash` when relevant
|
|
- `raised_at`
|
|
- `cleared_at`
|
|
- `details`
|
|
|
|
## Control surface expectations
|
|
|
|
### `liquidity-manager`
|
|
Must expose:
|
|
- active deposit handles
|
|
- latest pre-credit funding observations
|
|
- latest credit correlation
|
|
- whether the funding observer is healthy or paused
|
|
|
|
### alert evaluator
|
|
Must expose:
|
|
- current active alerts
|
|
- latest cleared alerts
|
|
- per-alert evaluation timestamps
|
|
- pause state
|
|
|
|
### `history-writer`
|
|
Must expose the new topic offsets and write status for funding observations and alerts.
|
|
|
|
## Tests
|
|
Required automated coverage:
|
|
- BTC funding observation remains non-spendable before credit
|
|
- alert transitions raise then clear on recovered stale state
|
|
- funding observation correlates to a later credited deposit without losing the original tx hash
|
|
- executor failure produces an alert event
|
|
|
|
If a meaningful automated test cannot be written for a subpath, stop and record why instead of hand-waving.
|
|
|
|
## Validation plan
|
|
- Safe induced stale-price alert:
|
|
- pause `market-reference-ingest`
|
|
- wait past freshness window
|
|
- observe `reference_price_stale`
|
|
- resume and observe clear
|
|
- Safe induced stale-inventory alert:
|
|
- pause `inventory-sync`
|
|
- wait past freshness window
|
|
- observe `inventory_snapshot_stale`
|
|
- resume and observe clear
|
|
- Funding visibility proof:
|
|
- use a real deposit address
|
|
- observe pre-credit chain state before bridge credit where timing allows
|
|
- later observe credit correlation
|
|
- Executor failure alert proof:
|
|
- use a controlled non-destructive failure mode such as temporary relay endpoint override in a safe environment or a replayable failure fixture
|
|
- verify `executor_submission_failed`
|
|
|
|
## Out of scope on purpose
|
|
- No new trading strategy
|
|
- No historical backtest engine
|
|
- No broad observability stack
|
|
- No polished dashboard frontend
|
|
- No automated treasury refills
|
|
|
|
## Still fake at turn open
|
|
- Pre-credit funding visibility is still missing from the live cluster.
|
|
- Alert state is still mostly implicit in service logs and manual inspection.
|
|
- There is no durable operator-facing record yet for "funds are on the way but not spendable."
|