Files
com_r35157_nenjim-hubd-impl…/openspec/specs/evelyn-perps-service/spec.md
T

9.3 KiB

evelyn-perps-service Specification

Purpose

Provide a view-only source of current Evelyn perpetual positions independently of Mission Control presentation and refresh timing.

Requirements

Requirement: Read-only current positions snapshot

The Perps service SHALL expose only a read operation returning its complete current in-memory snapshot. Wallets, venues within wallets, and positions within venues SHALL have stable identifiers across reads. Responses SHALL be immutable domain data without UI components, colors or formatting. Reading the snapshot SHALL make no Jupiter or Phoenix requests.

Scenario: Repeated reads

  • WHEN clients repeatedly retrieve the started service's snapshot
  • THEN they receive the latest published positions with stable identifiers and cannot mutate service-owned collections
  • AND the reads trigger no exchange requests or position-management operations

Requirement: Hub owns Perps startup

The service SHALL run as two separate Hub-managed processes registered as evelyn.perps.test and evelyn.perps.prod. The service API SHALL expose no lifecycle operations. Snapshot reads before process startup SHALL fail clearly. Startup SHALL schedule asynchronous retrieval without waiting for integration I/O.

Scenario: Service starts

  • WHEN the Hub starts either registered Perps process
  • THEN its service view is available without waiting for retrieval, initially empty until data arrives
  • AND no placeholder positions are generated before successful retrieval

Requirement: Wallet configuration belongs to service construction

The Hub SHALL supply the six PROD wallet addresses and one TEST wallet address specified in issue #98, a read-only Jupiter overview reader and a read-only Phoenix integration at construction. Each service SHALL retain immutable configuration and own its snapshot. Wallet addresses SHALL be used as stable identities and display labels. EMC SHALL neither own nor pass wallet configuration; reads SHALL remain parameterless. Existing Jupiter trading/alarm services SHALL retain their behavior.

Scenario: Separate configured instances

  • WHEN the Hub constructs and starts both instances
  • THEN each instance queries only its configured wallets through its injected integrations
  • AND the implementation does not define the wallet list internally

Requirement: Background Jupiter refresh

The service SHALL refresh immediately after startup and wait 60 seconds after completed cycles without overlap or dependence on EMC visibility. It SHALL use a dedicated read-only Jupiter overview and the Phoenix account reader. Snapshot reads SHALL make no integration calls. No signing or position-management operation SHALL occur; existing transaction/alarm reads SHALL retain their behavior.

Scenario: Background update while EMC is hidden

  • WHEN EMC is hidden and the next refresh is due
  • THEN the service refreshes configured wallets and publishes immutable snapshots
  • AND all UI snapshot reads remain in-memory

Requirement: Position mapping is stable and complete

The service SHALL preserve Jupiter position-account identities and its existing USD position-size basis. Phoenix SHALL preserve PDA/subaccount/symbol identities and absolute current notional. Isolated positions SHALL remain directly under venues; Cross accounts SHALL own their positions and shared balances separately. Wallet and position ordering SHALL be deterministic. No account membership SHALL be inferred from instrument labels.

Scenario: Same-market cross and isolated positions

  • WHEN a Phoenix wallet holds SOL in Cross and an isolated subaccount
  • THEN both positions retain distinct IDs and their actual account membership

Scenario: Changed and unknown positions

  • WHEN a successful read returns newly opened positions including an unknown token mint
  • THEN all returned positions appear with stable IDs and exact USD sizes, and the unknown mint is displayed rather than dropped

Requirement: Refresh failures are isolated per wallet

A failed read or mapping SHALL retain the last successful data for that wallet and venue, log the failure and allow other wallets and venues to refresh. Successful empty results SHALL remove only that wallet/venue's previous positions. Interruption SHALL stop the current cycle. Failed first reads SHALL not invent positions.

Scenario: Failure followed by recovery

  • WHEN one wallet fails while another succeeds
  • THEN only the successful wallet/venue's data is replaced
  • AND a later successful empty read clears the recovered wallet/venue's previous positions

Scenario: One venue fails

  • WHEN Phoenix fails for a wallet while Jupiter succeeds, or vice versa
  • THEN only the successful venue is updated and the failed venue retains its previous data
  • AND subsequent wallets are still attempted

Requirement: Complete gross and account-aware totals

Exposure and dollar price PnL SHALL sum through all levels. Exposure SHALL be gross, with positive absolute notionals. Capital and closing Value SHALL count isolated positions and shared Cross accounts once. Missing required components SHALL make only the affected total unavailable. Successfully read empty scopes SHALL total zero. Leverage and PnL percentages SHALL NOT be aggregated.

Scenario: Opposite directions and shared collateral

  • WHEN two Cross positions have notionals 100 USD Long and 100 USD Short, shared collateral 80 USD, combined PnL 5 USD and closing fees 1 USD
  • THEN exposure totals 200 USD, collateral 80 USD and Value 84 USD at account, venue, wallet and root levels
  • AND collapsing any UI group does not change totals

Scenario: First read fails

  • WHEN one configured venue has never been read successfully
  • THEN it remains unknown and cannot silently produce complete portfolio totals

Requirement: Retained observations communicate status

Each venue SHALL carry its last-success time and whether the latest attempt failed. Failure SHALL preserve positions and account balances independently per wallet/venue. A valid funded empty Cross account SHALL remain visible. Retained data SHALL NOT be described as fresh.

Scenario: Last Cross position closes

  • WHEN a successful refresh returns a Cross account with nonzero collateral and no positions
  • THEN its capital and Value remain included without synthetic positions

Scenario: Retained last success

  • WHEN a subsequent read fails
  • THEN its previous observations remain available with their original success time and failure indication

Requirement: TWAP observations belong to existing filled positions

The service SHALL publish immutable TWAP observations on matching existing Phoenix positions whose order has a positive actual fill and remaining executions, and account-owned warnings for eligible unresolved orders. It SHALL preserve counters, quantities, nullable price and observation/estimated times without UI formatting. No new position SHALL be synthesized. TWAP errors SHALL retain the complete prior venue observation with failure status. Polling frequency SHALL remain unchanged.

Scenario: Unfilled order or no position

  • WHEN an active TWAP has no actual fills or no matching open position
  • THEN a zero-fill order is absent from every overview row and cannot create a visible venue
  • AND an eligible filled outstanding order without a position is preserved as a warning on its actual account scope

Scenario: TWAP read fails

  • WHEN the TWAP read fails after a successful venue observation
  • THEN prior positions, TWAP observations and original timestamps remain with failed venue status
  • AND other venues and wallets continue refreshing

Scenario: Filled order without position

  • WHEN a filled outstanding order cannot match an open position
  • THEN its warning retains the real account identity and Cross accounts remain present even without capital or positions
  • AND warning-only data does not synthesize positions or valuations

Scenario: Warning recovery and retention

  • WHEN a successful observation resolves or removes a warned order
  • THEN its warning is cleared while unrelated warnings remain
  • AND failed reads instead retain warnings and their original times

Requirement: Risk observations preserve scope and exact meaning

Snapshots SHALL preserve isolated risk prices and Cross account tiers/thresholds with original observation times. Signed price distance SHALL use the current venue reference as denominator and preserve boundary crossing. Cross MM utilization SHALL use effective collateral, with nonpositive denominators unavailable. Group risk SHALL count each isolated position and shared account once and retain worst known severity plus unknown/stale counts without averaging.

Scenario: Shared positions and incomplete data

  • WHEN a Cross account owns multiple positions and another scope has unknown risk
  • THEN account risk contributes once and the aggregate exposes the unknown count
  • AND its closing Value is not substituted for effective collateral

Scenario: Boundary and zero denominator

  • WHEN isolated distance reaches/crosses zero or effective collateral is nonpositive
  • THEN the signed boundary is preserved or MM percentage is unavailable respectively
  • AND display rounding does not determine risk classification