97: Configure separate TEST and PROD instances of EvelynPerpsService
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-10-22
|
||||
@@ -0,0 +1,22 @@
|
||||
# Design
|
||||
|
||||
## Context
|
||||
See proposal.md. The service currently creates two named sample wallets internally; EMC uses one shared service and snapshot for both tabs. Hub startup is explicitly ordered.
|
||||
|
||||
## Goals / Non-Goals
|
||||
Keep wallet configuration out of EMC and snapshots instance-owned. No real addresses, integrations, trading, new configuration framework or UI redesign are introduced.
|
||||
|
||||
## Decisions
|
||||
- Add an immutable wallet configuration record (stable ID and display name), supplied as a defensively copied list to the implementation constructor. The sample IDs are not Solana addresses. This avoids passing UI data or moving sample position definitions into Hub.
|
||||
- Hub owns one immutable list of the two existing sample wallet identities, supplied to both independently constructed processes.
|
||||
- Keep the existing two sample position sets in the service and assign them by configured wallet order, alternating for additional sample wallets. This is explicitly sample-only behavior, not an integration policy; empty configuration gives an empty snapshot. It avoids coupling sample data to wallet IDs or requiring exactly two wallets.
|
||||
- Inject PROD and TEST service views into EMC. Retain one off-thread scheduled loop, with separate reads and error handling for each tab. Preserve existing rendering and session guards.
|
||||
- Retire the default ID rather than aliasing it, following explicit process selection and fail-fast dependencies.
|
||||
|
||||
## Risks / Trade-offs
|
||||
- Identical fixtures conceal crossed wiring → verify routing by source inspection and an isolated session with distinct snapshots.
|
||||
- Private startup configuration is ignored by Git → update the local file and document the required deployment migration.
|
||||
- Sample assignment is ordinal → document this temporary fixture behavior; real integration remains a later task.
|
||||
|
||||
## Migration Plan
|
||||
Replace evelyn.perps.default with evelyn.perps.prod and evelyn.perps.test before EMC. Both must precede EMC. The minimal tracked bootstrap template stays unchanged. Rollback requires restoring both code and the old configuration entry. Do not start production processes during verification.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Proposal
|
||||
|
||||
## Why
|
||||
EMC currently shares one Perps service between TEST and PROD. Issue #97 requires separate service ownership and Hub-supplied wallet configuration before real integrations are introduced.
|
||||
|
||||
## What Changes
|
||||
- **BREAKING**: Replace `evelyn.perps.default` with `evelyn.perps.test` and `evelyn.perps.prod` in the process catalogue and startup configuration.
|
||||
- Pass the same hardcoded wallet configuration from NenjimHub to two independent service instances.
|
||||
- Poll each instance for its corresponding EMC tab every three seconds, preserving presentation and the parameterless snapshot API.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
None.
|
||||
|
||||
### Modified Capabilities
|
||||
- `evelyn-perps-service`: Hub-configured wallets and separate TEST/PROD lifecycles and snapshots.
|
||||
- `nenjim-hub-configuration`: Separate Perps process IDs and explicit EMC dependencies.
|
||||
- `evelyn-perps-overview`: Each environment tab polls its own service.
|
||||
|
||||
## Impact
|
||||
Perps service construction, EMC injection and polling, Hub process catalogue, local startup configuration and project documentation. No exchange integration, trading, advanced configuration or UI changes.
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Asynchronous polling follows window visibility
|
||||
EMC SHALL request the current Perps snapshot from each environment's own service immediately on opening and every three seconds while visible, without blocking the UI thread. UI updates SHALL occur only on the JavaFX thread. Hiding the window SHALL stop polling; reopening SHALL create only one active polling loop and ignore results belonging to an earlier window session. Poll failures SHALL preserve the current view and allow subsequent attempts.
|
||||
|
||||
#### Scenario: Read takes time or fails
|
||||
- **WHEN** a snapshot read is delayed or fails
|
||||
- **THEN** the UI remains responsive and the existing view is retained
|
||||
- **AND** later polling remains possible without overlapping scheduled reads
|
||||
|
||||
#### Scenario: Hide and reopen
|
||||
- **WHEN** the owner hides and reopens EMC repeatedly
|
||||
- **THEN** each visible session has only one polling loop and obsolete results cannot update its views
|
||||
|
||||
#### Scenario: Environment data stays separate
|
||||
- **WHEN** TEST and PROD return different snapshots
|
||||
- **THEN** each tab displays only its own service's data
|
||||
- **AND** a failure reading one service does not prevent attempting the other service
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### 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.
|
||||
|
||||
#### Scenario: Service starts
|
||||
- **WHEN** the Hub starts either registered Perps process
|
||||
- **THEN** its service view makes the complete sample snapshot available without starting a polling or integration worker
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Wallet configuration belongs to service construction
|
||||
The Hub SHALL supply the same hardcoded wallet configuration to TEST and PROD at construction. Each service SHALL retain an immutable copy and own a separate snapshot. EMC SHALL neither own nor pass wallet configuration; snapshot reads SHALL remain parameterless.
|
||||
|
||||
#### Scenario: Separate configured instances
|
||||
- **WHEN** the Hub constructs and starts both instances using the shared sample wallet configuration
|
||||
- **THEN** each snapshot contains the configured wallet identities and existing sample positions
|
||||
- **AND** the two instances own separate snapshots without defining the wallet list internally
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Selected processes are constructed and started lazily in exact order
|
||||
The Hub SHALL support the modern process IDs `nenjim.registry.service`, `nenjim.journal.service`, `assetaz.ticker.default`, `jupiter-perps-alarm.default`, `evelyn.status.prod`, `evelyn.status.test`, `evelyn.iou-burner.prod`, `evelyn.liquidity.prod`, `evelyn.perps.prod` and `evelyn.perps.test`, `nenjim.javafx-runtime.service`, `evelyn.mission-control.default`, and `nenjim.process-manager.default` through implementation-only construction capability that creates no process instance during validation. After passive composition, the Hub SHALL visit every configured entry after Registry in declared order, beginning with Journal. At each entry it SHALL construct only that process and any explicitly composed process-specific passive dependencies or administration view, register the process under the exact configured ID, resolve it through the canonical `NenjimProcess` contract where applicable, call `start()`, and record the ID only after successful return.
|
||||
|
||||
The production IOU burner SHALL receive the already constructed Production Evelyn status service, and SHALL require both Ticker and `evelyn.status.prod` to precede `evelyn.iou-burner.prod`. EMC SHALL receive the already started `evelyn.perps.prod` and `evelyn.perps.test` services, both of which SHALL precede EMC in the deployment autostart list. The configuration SHALL be the complete manually ordered process dependency closure. The Hub SHALL not discover, insert, recursively construct, reorder, or automatically start dependencies. A process omitted from `[AUTO_START]` SHALL not be constructed, registered, started, or recorded, even when its implementation is available. Legacy process prototypes outside the modern Hub graph SHALL not be selectable.
|
||||
|
||||
#### Scenario: Configured process starts successfully
|
||||
- **WHEN** a configured process entry is reached and its dependencies are already available
|
||||
- **THEN** that process is constructed, registered, started, and recorded before the next entry is reached
|
||||
|
||||
#### Scenario: Process is omitted
|
||||
- **WHEN** a known process ID does not appear in `[AUTO_START]`
|
||||
- **THEN** no instance of that process is constructed or registered and its lifecycle is never started or recorded
|
||||
|
||||
#### Scenario: Jupiter Perps Alarm is selected
|
||||
- **WHEN** `jupiter-perps-alarm.default` is explicitly listed after its required predecessors
|
||||
- **THEN** the otherwise inactive modern alarm process is constructed, registered, started and recorded at that exact position
|
||||
|
||||
#### Scenario: Dependency order is invalid
|
||||
- **WHEN** a selected process is reached before a process dependency required by its current constructor or startup behavior
|
||||
- **THEN** construction or startup fails clearly without implicit dependency construction, repair, or reordering
|
||||
|
||||
#### Scenario: JavaFX processes are omitted
|
||||
- **WHEN** a valid headless plan omits `nenjim.javafx-runtime.service`, `evelyn.mission-control.default`, and `nenjim.process-manager.default`
|
||||
- **THEN** none of those objects is constructed or registered and the JavaFX toolkit remains uninitialized by the Hub
|
||||
|
||||
#### Scenario: Renamed status services retain dependency wiring
|
||||
- **WHEN** `evelyn.status.prod` and `evelyn.status.test` are listed after Ticker and before Mission Control
|
||||
- **THEN** the Hub constructs separate Production/Test status services, registers the renamed IDs, and injects the corresponding typed service views into Mission Control in the configured order
|
||||
|
||||
#### Scenario: Deployment still contains an old status ID
|
||||
- **WHEN** a private deployment configuration contains `evelyn.service.prod` or `evelyn.service.test`
|
||||
- **THEN** validation rejects the unknown ID before startup; deployment migration replaces only that ID with `evelyn.status.prod` or `evelyn.status.test`, preserving selection and order
|
||||
|
||||
#### Scenario: Liquidity is explicitly selected
|
||||
- **WHEN** `evelyn.liquidity.prod` is reached in a valid startup plan
|
||||
- **THEN** the Hub loads its runtime configuration, binds the dedicated signer/wallet and Jupiter service to each other, constructs direct Raydium access and registers/starts the liquidity process without inserting a Ticker or status dependency or reordering the plan
|
||||
|
||||
#### Scenario: Production burner has its reference-price dependency
|
||||
- **WHEN** `evelyn.iou-burner.prod` is reached after Ticker and `evelyn.status.prod`
|
||||
- **THEN** the Hub injects the corresponding Production status service for buyback price decisions
|
||||
|
||||
#### Scenario: Production burner precedes its status dependency
|
||||
- **WHEN** the burner is reached without a previously constructed Production status service
|
||||
- **THEN** construction fails clearly without creating or starting the omitted dependency or the burner
|
||||
|
||||
#### Scenario: EMC has its Perps dependency
|
||||
- **WHEN** `evelyn.perps.prod` and `evelyn.perps.test` appear before EMC in the deployment's ordered autostart list
|
||||
- **THEN** the Hub registers and starts separate service instances and injects their corresponding service views into EMC
|
||||
|
||||
#### Scenario: EMC precedes Perps
|
||||
- **WHEN** EMC is selected without both earlier Perps processes
|
||||
- **THEN** construction fails clearly without inserting or starting that dependency
|
||||
|
||||
#### Scenario: Deployment contains the retired shared Perps ID
|
||||
- **WHEN** a deployment still selects `evelyn.perps.default`
|
||||
- **THEN** startup validation rejects the unknown ID before starting processes
|
||||
- **AND** migration replaces it with both new IDs before EMC
|
||||
@@ -0,0 +1,19 @@
|
||||
# Tasks
|
||||
|
||||
## 1. Service configuration and Hub ownership
|
||||
- [x] 1.1 Add immutable wallet configuration and separate TEST/PROD construction; inspect retained sample values, defensive copying and lifecycle wiring.
|
||||
- [x] 1.2 Update local startup configuration and service/startup documentation; verify both IDs precede EMC and the minimal tracked template is unchanged.
|
||||
|
||||
## 2. EMC routing
|
||||
- [x] 2.1 Inject both services and route independent reads to their respective tabs; verify three-second polling, error isolation and unchanged state-preserving renderer.
|
||||
|
||||
## 3. Integration verification
|
||||
- [x] 3.1 Run Gradle build, strict OpenSpec validation and isolated verification of service snapshots and distinct environment routing; review the diff and leave changes uncommitted.
|
||||
|
||||
## Verification results
|
||||
- Gradle build passed, including all 42 existing tests. No automated tests added to the repository.
|
||||
- Strict OpenSpec validation and `git diff --check HEAD` passed.
|
||||
- Isolated JavaFX verification used distinct PROD/TEST fixtures to verify routing, independent error handling, approximately 3.000-second poll gaps, unchanged row identities/selection/expansion, hide/reopen cancellation and obsolete-result rejection.
|
||||
- The actual local startup configuration parsed successfully; both Perps instances were constructed, registered and started through the Hub lifecycle in isolation, with separate but equal snapshots. No production Hub startup or exchange requests.
|
||||
- Local ignored `conf/NenjimHub.conf` now selects both IDs before EMC; tracked minimal bootstrap template is unchanged.
|
||||
- Changes left uncommitted for owner review; OpenSpec change remains active.
|
||||
@@ -37,7 +37,7 @@ The Perps view SHALL explicitly label its data as sample data and explain that P
|
||||
- **AND** displaying and interacting with the prototype uses only the service's local sample snapshot
|
||||
|
||||
### Requirement: Asynchronous polling follows window visibility
|
||||
EMC SHALL request the current Perps snapshot immediately on opening and every three seconds while visible, without blocking the UI thread. UI updates SHALL occur only on the JavaFX thread. Hiding the window SHALL stop polling; reopening SHALL create only one active polling loop and ignore results belonging to an earlier window session. Poll failures SHALL preserve the current view and allow subsequent attempts.
|
||||
EMC SHALL request the current Perps snapshot from each environment's own service immediately on opening and every three seconds while visible, without blocking the UI thread. UI updates SHALL occur only on the JavaFX thread. Hiding the window SHALL stop polling; reopening SHALL create only one active polling loop and ignore results belonging to an earlier window session. Poll failures SHALL preserve the current view and allow subsequent attempts.
|
||||
|
||||
#### Scenario: Read takes time or fails
|
||||
- **WHEN** a snapshot read is delayed or fails
|
||||
@@ -48,6 +48,11 @@ EMC SHALL request the current Perps snapshot immediately on opening and every th
|
||||
- **WHEN** the owner hides and reopens EMC repeatedly
|
||||
- **THEN** each visible session has only one polling loop and obsolete results cannot update its views
|
||||
|
||||
#### Scenario: Environment data stays separate
|
||||
- **WHEN** TEST and PROD return different snapshots
|
||||
- **THEN** each tab displays only its own service's data
|
||||
- **AND** a failure reading one service does not prevent attempting the other service
|
||||
|
||||
### Requirement: Polling preserves Perps view state
|
||||
The Perps table SHALL retain matching wallet, venue and position identities across snapshots. Repeated unchanged snapshots SHALL leave existing rows, expansion, selection and formatting untouched without flicker. New groups SHALL be expanded by default, and future added or removed positions SHALL be reconciled by identity without resetting retained groups.
|
||||
|
||||
|
||||
@@ -22,8 +22,16 @@ The service SHALL own the existing eight sample positions grouped under Sample w
|
||||
- **AND** wallet B contains Jupiter ETH Long 1875.25 and SOL Short 950.00, Phoenix BTC Long 21000.00 and SOL Short 640.50
|
||||
|
||||
### Requirement: Hub owns Perps startup
|
||||
The service SHALL run as a separate Hub-managed process registered as `evelyn.perps.default`. The service API SHALL expose no lifecycle operations. Snapshot reads before process startup SHALL fail clearly.
|
||||
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.
|
||||
|
||||
#### Scenario: Service starts
|
||||
- **WHEN** the Hub starts the registered Perps process
|
||||
- **WHEN** the Hub starts either registered Perps process
|
||||
- **THEN** its service view makes the complete sample snapshot available without starting a polling or integration worker
|
||||
|
||||
### Requirement: Wallet configuration belongs to service construction
|
||||
The Hub SHALL supply the same hardcoded wallet configuration to TEST and PROD at construction. Each service SHALL retain an immutable copy and own a separate snapshot. EMC SHALL neither own nor pass wallet configuration; snapshot reads SHALL remain parameterless.
|
||||
|
||||
#### Scenario: Separate configured instances
|
||||
- **WHEN** the Hub constructs and starts both instances using the shared sample wallet configuration
|
||||
- **THEN** each snapshot contains the configured wallet identities and existing sample positions
|
||||
- **AND** the two instances own separate snapshots without defining the wallet list internally
|
||||
|
||||
@@ -89,9 +89,9 @@ After validating the entire plan, the Hub SHALL construct the configured Registr
|
||||
- **THEN** its deployment configuration, dedicated signer/wallet, Jupiter service and direct Raydium service are neither loaded nor constructed nor registered
|
||||
|
||||
### Requirement: Selected processes are constructed and started lazily in exact order
|
||||
The Hub SHALL support the modern process IDs `nenjim.registry.service`, `nenjim.journal.service`, `assetaz.ticker.default`, `jupiter-perps-alarm.default`, `evelyn.status.prod`, `evelyn.status.test`, `evelyn.iou-burner.prod`, `evelyn.liquidity.prod`, `evelyn.perps.default`, `nenjim.javafx-runtime.service`, `evelyn.mission-control.default`, and `nenjim.process-manager.default` through implementation-only construction capability that creates no process instance during validation. After passive composition, the Hub SHALL visit every configured entry after Registry in declared order, beginning with Journal. At each entry it SHALL construct only that process and any explicitly composed process-specific passive dependencies or administration view, register the process under the exact configured ID, resolve it through the canonical `NenjimProcess` contract where applicable, call `start()`, and record the ID only after successful return.
|
||||
The Hub SHALL support the modern process IDs `nenjim.registry.service`, `nenjim.journal.service`, `assetaz.ticker.default`, `jupiter-perps-alarm.default`, `evelyn.status.prod`, `evelyn.status.test`, `evelyn.iou-burner.prod`, `evelyn.liquidity.prod`, `evelyn.perps.prod` and `evelyn.perps.test`, `nenjim.javafx-runtime.service`, `evelyn.mission-control.default`, and `nenjim.process-manager.default` through implementation-only construction capability that creates no process instance during validation. After passive composition, the Hub SHALL visit every configured entry after Registry in declared order, beginning with Journal. At each entry it SHALL construct only that process and any explicitly composed process-specific passive dependencies or administration view, register the process under the exact configured ID, resolve it through the canonical `NenjimProcess` contract where applicable, call `start()`, and record the ID only after successful return.
|
||||
|
||||
The production IOU burner SHALL receive the already constructed Production Evelyn status service, and SHALL require both Ticker and `evelyn.status.prod` to precede `evelyn.iou-burner.prod`. EMC SHALL receive the already started `evelyn.perps.default` service, which SHALL precede EMC in the deployment autostart list. The configuration SHALL be the complete manually ordered process dependency closure. The Hub SHALL not discover, insert, recursively construct, reorder, or automatically start dependencies. A process omitted from `[AUTO_START]` SHALL not be constructed, registered, started, or recorded, even when its implementation is available. Legacy process prototypes outside the modern Hub graph SHALL not be selectable.
|
||||
The production IOU burner SHALL receive the already constructed Production Evelyn status service, and SHALL require both Ticker and `evelyn.status.prod` to precede `evelyn.iou-burner.prod`. EMC SHALL receive the already started `evelyn.perps.prod` and `evelyn.perps.test` services, both of which SHALL precede EMC in the deployment autostart list. The configuration SHALL be the complete manually ordered process dependency closure. The Hub SHALL not discover, insert, recursively construct, reorder, or automatically start dependencies. A process omitted from `[AUTO_START]` SHALL not be constructed, registered, started, or recorded, even when its implementation is available. Legacy process prototypes outside the modern Hub graph SHALL not be selectable.
|
||||
|
||||
#### Scenario: Configured process starts successfully
|
||||
- **WHEN** a configured process entry is reached and its dependencies are already available
|
||||
@@ -134,13 +134,18 @@ The production IOU burner SHALL receive the already constructed Production Evely
|
||||
- **THEN** construction fails clearly without creating or starting the omitted dependency or the burner
|
||||
|
||||
#### Scenario: EMC has its Perps dependency
|
||||
- **WHEN** `evelyn.perps.default` appears before EMC in the deployment's ordered autostart list
|
||||
- **THEN** the Hub registers and starts that service and injects its service view into EMC
|
||||
- **WHEN** `evelyn.perps.prod` and `evelyn.perps.test` appear before EMC in the deployment's ordered autostart list
|
||||
- **THEN** the Hub registers and starts separate service instances and injects their corresponding service views into EMC
|
||||
|
||||
#### Scenario: EMC precedes Perps
|
||||
- **WHEN** EMC is selected without an earlier Perps process
|
||||
- **WHEN** EMC is selected without both earlier Perps processes
|
||||
- **THEN** construction fails clearly without inserting or starting that dependency
|
||||
|
||||
#### Scenario: Deployment contains the retired shared Perps ID
|
||||
- **WHEN** a deployment still selects `evelyn.perps.default`
|
||||
- **THEN** startup validation rejects the unknown ID before starting processes
|
||||
- **AND** migration replaces it with both new IDs before EMC
|
||||
|
||||
### Requirement: Configured startup is fail-fast and reports actual milestones
|
||||
Registry and every selected process SHALL be registered before its `start()` call and appended to the Hub's immutable ordered startup snapshot only after `start()` returns successfully. Construction failure SHALL leave the selected process unregistered. Registration or startup failure SHALL stop the plan before any later entry is constructed or started; a startup failure MAY leave that process registered but SHALL not record it. Earlier successful processes SHALL remain in snapshots, no rollback or retry SHALL occur, and the Hub SHALL announce its existing online point and enter its blocking runtime wait only after every configured process succeeds.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user