unrip/IMPLEMENTATION.md
philipp 54dc05a94c Archive first live trade loop and open funding visibility turn
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.
2026-04-03 01:07:02 +02:00

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."