All checks were successful
deploy / deploy (push) Successful in 48s
Instead of fetching up to 50k inventory snapshots (~442MB), scope the query to only the time range of the current submission batch with a 15-minute buffer. For a typical 1-hour batch this drops from 50k rows to ~300 rows, well within the 1280Mi pod memory limit. The coalesced_at_idx on intent_inventory_snapshots covers the BETWEEN clause so this remains efficient. Proof: history-writer OOM kills from refreshQuoteOutcomes inventory fetch Assumptions: 15min buffer covers the attribution window for all submissions Still fake: heuristic gap outcomes may attribute trades imprecisely
154 lines
11 KiB
Markdown
154 lines
11 KiB
Markdown
# Implementation Proof: Pair-native trade semantics and multi-asset outcome truth
|
|
|
|
Status: open
|
|
Opened: 2026-05-18
|
|
|
|
## Target outcome
|
|
The repository must stop using BTC/EURe as the hidden shape of shared trading behavior.
|
|
|
|
Runtime services may still support only the currently implemented price-route adapters, but decisions, commands, taker request preflights, settlement attribution, dashboard surfaces, valuation visibility, and alerts must use DB asset and pair metadata as their canonical model. A configured nBTC/USDC pair must not be silently ignored, mislabeled as EUR notional, or made impossible to explain because a shared path expects EURe and BTC.
|
|
|
|
## Why this is the next architecture test
|
|
The previous turn moved asset catalogs, pair modes, edges, and limits into Postgres and added dashboard controls. That made it possible to configure more than the original nBTC/EURe pair, but it also exposed narrower shared paths:
|
|
|
|
- repo-created request preflight still speaks `amount_eure` and `eure_per_btc`
|
|
- outcome attribution still builds inventory deltas from one BTC asset and one EURe asset
|
|
- portfolio valuation now handles tracked USDC, but only as a special case
|
|
- dashboard copy, notional labels, and lifecycle text still assume BTC/EURe
|
|
- alert and health code still centers on a single active pair
|
|
|
|
This turn succeeds only if the canonical event and operator surfaces are pair-native enough that adding an enabled pair from the DB does not collapse back to the original BTC/EURe path.
|
|
|
|
## Scope
|
|
- Replace canonical `amount_eure`, `eure_notional`, and `max_notional_eure` usage in active runtime paths with pair-native fields:
|
|
- `source_amount`, `source_amount_units`, `source_asset_id`
|
|
- `destination_amount`, `destination_amount_units`, `destination_asset_id`
|
|
- `notional`, `notional_asset_id`, `notional_symbol`
|
|
- `max_notional`, `min_notional`
|
|
- Keep legacy aliases only where needed for old stored rows or backward-compatible API bodies; new logic must not depend on them.
|
|
- Make strategy price-route evaluation generic over `base_asset_id`, `quote_asset_id`, `quote_per_base`, and `base_per_quote` while preserving current BTC/EUR and BTC/USDC adapters.
|
|
- Make taker request preflight pair-native:
|
|
- accept `pair_id` or explicit `asset_in`/`asset_out`
|
|
- accept `source_amount` or `amount`
|
|
- resolve asset decimals, edge, limits, freshness policy, and route from DB pair config
|
|
- compute expected and minimum destination amount from the configured route
|
|
- fail closed when the pair, route, price, signer, inventory, or decimals are missing
|
|
- Make settlement attribution derive the required asset set and expected deltas from commands or preflights, not from fixed BTC/EURe parameters.
|
|
- Make dashboard labels, request forms, lifecycle rows, notional displays, and settlement text use DB asset symbols and pair config.
|
|
- Make portfolio and funds views list every tracked asset with either a computed valuation or an explicit unvalued reason.
|
|
- Make alert and health summaries use active pair/route sets rather than a single hardcoded `activePair` where the service is pair-scoped.
|
|
- Preserve existing nBTC/EURe behavior and the current 49 bps edge through migration.
|
|
- Preserve nBTC/Ethereum USDC maker trade capability when the DB pair has strategy config, inventory, and a fresh BTC/USDC price route.
|
|
|
|
## Assumptions
|
|
- Postgres remains the source of truth for assets, pairs, pair modes, strategy configs, and price routes.
|
|
- NEAR Intents remains the only live execution venue in this turn, but canonical records must carry venue and pair metadata so they are not NEAR/BTC/EURe shaped internally.
|
|
- Supported price-route adapters remain limited to current implemented sources: BTC/EUR and BTC/USDC reference routes.
|
|
- Broad arbitrary-asset pricing requires a later price graph or route-source turn.
|
|
- Live fund movement remains behind existing arming and explicit operator controls.
|
|
- Imported supported assets remain observe-only or inactive unless explicitly enabled by operator pair config.
|
|
|
|
## Turn-shaping rules
|
|
- Do not introduce new env vars for active assets, pairs, edges, or valuation behavior.
|
|
- Do not make every imported asset tradeable or valued by default.
|
|
- Do not silently drop tracked assets from portfolio, funding, dashboard, or attribution views because they lack a valuation route.
|
|
- Do not claim realized PnL or completed settlement without durable evidence.
|
|
- Do not widen live-funds risk while replacing field names and runtime semantics.
|
|
- Do not remove old-row compatibility unless the migration and tests prove no operator-visible history is lost.
|
|
|
|
## Non-goals
|
|
- No new execution venue.
|
|
- No arbitrary multi-hop price graph.
|
|
- No automatic pair discovery or automatic live trading enablement.
|
|
- No solver-liquidity guarantee for every supported token pair.
|
|
- No fee-complete realized PnL.
|
|
- No autonomous rebalancer or optimizer.
|
|
- No manual production fixes outside repo workflow.
|
|
|
|
## Required Operator Behavior
|
|
|
|
### Pair-native request truth
|
|
The operator must be able to create a preflight for a directed taker pair using DB pair config. The UI/API must show:
|
|
- selected pair id and mode
|
|
- source asset, destination asset, symbols, decimals, and venue
|
|
- source amount and source units
|
|
- configured price route, route freshness, and reference price id
|
|
- expected destination amount and minimum destination amount
|
|
- slippage bps, deadline, signer, verifier contract, and inventory check
|
|
- pair config id, pair config version, and edge bps used
|
|
- decisive blocked reason when the pair cannot safely create a request
|
|
|
|
### Pair-native decision and command truth
|
|
Every new decision and command must persist:
|
|
- pair id and venue
|
|
- pair config id and version
|
|
- edge bps
|
|
- source and destination asset ids
|
|
- asset decimals used
|
|
- price route id and reference price id
|
|
- direction relative to the configured route, not BTC/EURe-specific labels
|
|
- generic notional value and notional asset
|
|
- legacy notional aliases only as compatibility fields where needed
|
|
|
|
### Pair-native settlement truth
|
|
Completed settlement must be based on the expected source decrease and destination increase for the actual pair. The dashboard must show asset deltas using DB labels, for example `-100 USDC, +0.0012 BTC`, not hardcoded EURe decrease and BTC increase text.
|
|
|
|
### Portfolio and valuation truth
|
|
The dashboard must list every tracked asset. If an asset can be valued through the currently supported route set, it shows the value and valuation source. If not, it shows an explicit unvalued reason such as `valuation_route_missing` rather than disappearing from totals without explanation.
|
|
|
|
## Semantic Invariants
|
|
- Active runtime behavior must not require `tradingBtc` and `tradingEure` as the only asset roles.
|
|
- New decisions and commands must carry generic `notional`, `notional_asset_id`, and `max_notional`.
|
|
- Taker preflight must work from `pair_id` plus `source_amount`; `amount_eure` may be accepted only as a legacy alias.
|
|
- Outcome attribution must include assets from the expected pair deltas, including USDC, instead of a fixed BTC/EURe active-asset set.
|
|
- Dashboard request and lifecycle labels must come from DB asset metadata.
|
|
- Existing nBTC/EURe maker behavior must remain compatible.
|
|
- nBTC/USDC maker decisions must keep working from the DB BTC/USDC price route.
|
|
- Missing price route, stale price, unknown decimals, or missing inventory must fail closed.
|
|
- Tracked but unvalued assets must remain visible.
|
|
|
|
## Definition of Done
|
|
- Strategy uses a generic route-rate model for currently supported BTC/EUR and BTC/USDC routes.
|
|
- Decisions and commands persist generic notional fields and pair-native asset metadata.
|
|
- Taker preflight accepts pair-native inputs and no longer requires EURe/BTC-specific price fields.
|
|
- Settlement attribution derives inventory delta assets from commands/preflights and handles at least a BTC/USDC regression case.
|
|
- Portfolio/dashboard surfaces expose every tracked asset with value or explicit unvalued reason.
|
|
- Dashboard request creation, lifecycle, pair config, status, and settlement text no longer assume EURe-to-BTC.
|
|
- Runtime health and alerts are pair/route-aware enough not to describe the whole system as one active BTC/EURe pair.
|
|
- Deployment config remains free of trading asset/pair/edge env vars.
|
|
- Tests cover the generic path and current-pair compatibility.
|
|
- The result is deployed through repo workflow and validated against live service state.
|
|
|
|
## Validation Evidence Required
|
|
- Unit tests for generic exact-in route math using BTC/EUR and BTC/USDC fixtures.
|
|
- Strategy tests proving nBTC/EURe compatibility and nBTC/USDC generic notional fields.
|
|
- Taker preflight tests for pair-native request creation, route missing, stale route, insufficient source inventory, and legacy `amount_eure` alias handling.
|
|
- Outcome attribution tests proving a BTC/USDC command/request can be completed from inventory deltas.
|
|
- Portfolio tests proving tracked unvalued assets remain visible with `valuation_route_missing`.
|
|
- Dashboard tests proving request labels, lifecycle text, notional labels, and balance rows come from asset metadata.
|
|
- Alert/runtime-health tests proving pair-scoped stale route and active pair set handling.
|
|
- Static deployment test proving pair/asset/edge env vars remain absent.
|
|
- Live dashboard/bootstrap evidence after deploy showing nBTC/EURe and nBTC/USDC pair config without EURe-only request labeling.
|
|
|
|
## Failure Conditions
|
|
- A non-EURe pair cannot be preflighted because request code requires `amount_eure` or `eure_per_btc`.
|
|
- A BTC/USDC submission cannot be attributed because only BTC/EURe inventory deltas are considered.
|
|
- Dashboard labels a USDC notional as EUR or hides a tracked USDC balance.
|
|
- A tracked asset is omitted from funds/portfolio because it lacks valuation.
|
|
- A service still needs asset, pair, or edge env vars for trading behavior.
|
|
- Missing DB pair config, price route, or decimals leads to trading instead of a blocked state.
|
|
- nBTC/EURe behavior or 49 bps compatibility regresses.
|
|
|
|
## Current Real Before This Turn
|
|
- DB-backed assets, import runs, pair modes, strategy configs, and pair controls exist.
|
|
- The 1Click token catalog import has been run and contains 163 known assets.
|
|
- Current nBTC/EURe behavior and 49 bps DB config have been preserved.
|
|
- nBTC/Ethereum USDC can be configured with a BTC/USDC reference route, but several shared paths still use BTC/EURe assumptions.
|
|
- Dashboard can show known assets, tracked balances, pair config, and deposit addresses.
|
|
|
|
## Deliberately Not Built By This Proof
|
|
- New venue integration beyond NEAR Intents.
|
|
- General price graph for arbitrary supported assets.
|
|
- Fee-complete realized PnL.
|
|
- Venue-native terminal fill ingestion beyond existing evidence paths.
|
|
- Autonomous portfolio optimization or rebalancing.
|