diff --git a/docs/Evelyn.md b/docs/Evelyn.md index 1aa29a6..09fa7e7 100644 --- a/docs/Evelyn.md +++ b/docs/Evelyn.md @@ -461,7 +461,10 @@ EMC viser **Position | Direction | Margin | Collateral | Leverage | Exposure | V under den synlige rod **Perpetual Contracts**. Isolerede positioner har wallet → venue → position; Phoenix Cross har wallet → venue → Cross → position. Positionens konto-ID bestemmer identitet og tilhørsforhold, aldrig instrumentteksten. Wallets følger den -hidtidige konfiguration med Jupiter før Phoenix. Eksisterende foldestatus, markering og +hidtidige konfiguration med Jupiter før Phoenix. En venue uden positioner eller Cross-konti +skjules og vises igen, når der kommer indhold. Skjulte venues indgår fortsat i snapshot +og totaler; deres læsestatus findes på wallet-rækkens tooltip. En Cross-konto med kapital +holder derfor Phoenix synlig, selv uden åbne positioner. Eksisterende foldestatus, markering og rækkeobjekter bevares; uændrede snapshots opdaterer ikke træet. Vinduesstart er 1100 × 600, og smallere vinduer kan scrolle vandret, når kolonnernes minimumsbredder kræver det. @@ -493,7 +496,8 @@ Beløb har tusindtalsseparator og to decimaler, leverage × og pris-uPnL et synl Positiv uPnL er grøn, negativ rød, afrundet nul neutral uden negativt nul. De svage Long/Short-baggrunde bevares; grupper har tydeligere skrift og ingen retningsfarve. Tooltips forklarer definitioner, manglende værdier og sidste succesfulde læsetidspunkt. -Ved fejl markeres venue som retained eller unavailable; gamle tal beskrives ikke som nye. +Efter fejl markeres en synlig venue som retained; læsestatus for skjulte venues findes +på wallet-rækkens tooltip. Gamle tal beskrives ikke som nye. EMC spørger hver miljøservice straks ved åbning og hvert tredje sekund uden at blokere JavaFX-tråden. Skjul/luk stopper kun EMC-polling. Der er ingen sample-data, Refresh-knap, diff --git a/docs/PhoenixPerps.md b/docs/PhoenixPerps.md index a9b1eb5..e3702ef 100644 --- a/docs/PhoenixPerps.md +++ b/docs/PhoenixPerps.md @@ -79,7 +79,9 @@ Each Evelyn process performs an initial background refresh, then waits 60 second following each completed cycle. Jupiter and Phoenix are attempted independently for each configured wallet. Successful results replace only that wallet/venue; failures log wallet and venue and retain its last successful result. A valid empty result -replaces that venue's positions and account balances, preserving its group. +replaces that venue's positions and account balances. EMC hides the venue heading +when it has neither position rows nor Cross accounts; its read status remains in +the wallet tooltip and the scope still contributes to snapshot totals. Funded Cross accounts remain visible when they no longer hold positions. Snapshot reads never fetch external data; EMC's three-second polling remains unchanged. @@ -87,10 +89,10 @@ Positions and prices are separate REST reads and can belong to different slots. This is a periodic current-notional estimate, not an atomic exchange valuation. A cycle's duration includes all sequential reads and request pacing before the 60-second pause (32 active markets need at least about 33 seconds for their reads). Failed -reads can leave old data visible indefinitely. The venue now shows `(retained)` after -a failed refresh, or `(unavailable)` before any successful read; cell tooltips include -the last-success time. Initial not-yet-read scopes show `(loading)` and cannot contribute -fabricated zero totals. +reads can leave old data visible indefinitely. A visible venue shows `(retained)` after +a failed refresh; cell tooltips include the last-success time. Childless venues are hidden, +with failed or pending first-read status available in their wallet's tooltip. Such unknown +scopes cannot contribute fabricated zero totals. Trader PDA indices other than 0, streaming and position management are out of scope. diff --git a/openspec/changes/hide-empty-perps-venues/.openspec.yaml b/openspec/changes/hide-empty-perps-venues/.openspec.yaml new file mode 100644 index 0000000..1f5d280 --- /dev/null +++ b/openspec/changes/hide-empty-perps-venues/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-10-24 diff --git a/openspec/changes/hide-empty-perps-venues/design.md b/openspec/changes/hide-empty-perps-venues/design.md new file mode 100644 index 0000000..299dde1 --- /dev/null +++ b/openspec/changes/hide-empty-perps-venues/design.md @@ -0,0 +1,22 @@ +# Design + +## Context + +See proposal.md. Venue snapshots include successful-empty, not-yet-read and failed scopes. Cross accounts hold capital independently of positions, so position count alone cannot determine visibility. + +## Goals / Non-Goals + +**Goals:** Remove childless headings while preserving capital totals and failure visibility. + +**Non-Goals:** Changing integration reads, snapshot data, wallet visibility or refresh scheduling. + +## Decisions + +- Skip a venue during tree reconciliation only when both its positions and Cross-account lists are empty. Filtering the service snapshot instead would lose unknown scopes and could produce misleading totals. +- Include childless venues' read status in wallet tooltip notes so hiding their headings does not hide the reason for unavailable totals. Keep the existing venue tooltips when rows exist. +- Reconcile surviving items with the existing IDs; a venue returning after removal is a new expanded group. Its wallet and other venue rows remain retained. + +## Risks / Trade-offs + +- Hidden failed/initial reads can resemble a successfully empty portfolio → preserve unavailable totals and expose the exact status on the wallet row. +- A Phoenix account may have capital without positions → treat the Cross account itself as a child. diff --git a/openspec/changes/hide-empty-perps-venues/proposal.md b/openspec/changes/hide-empty-perps-venues/proposal.md new file mode 100644 index 0000000..60f79c8 --- /dev/null +++ b/openspec/changes/hide-empty-perps-venues/proposal.md @@ -0,0 +1,26 @@ +# Proposal + +## Why + +Empty Jupiter and Phoenix headings add clutter to Evelyn's Perps capital/risk overview. The owner wants a venue shown only when it has something beneath it. + +## What Changes + +- Hide venue rows with neither isolated positions nor Cross accounts; show them again when data supplies children. +- Retain Phoenix groups containing funded Cross accounts without open positions. +- Keep hidden scopes in the service snapshot and totals; expose their read status through wallet tooltips. +- Replace documentation that says empty venue headings remain visible. + +## Capabilities + +### New Capabilities + +None. + +### Modified Capabilities + +- `evelyn-perps-overview`: Suppress childless venues without discarding valuation or read-status information. + +## Impact + +Local `.tjava` presentation code, the overview specification, and relevant project/shared documentation only. No integration, refresh, wallet configuration, signing or trading changes. No commits, pushes or live Hub restart. diff --git a/openspec/changes/hide-empty-perps-venues/specs/evelyn-perps-overview/spec.md b/openspec/changes/hide-empty-perps-venues/specs/evelyn-perps-overview/spec.md new file mode 100644 index 0000000..8d01a9d --- /dev/null +++ b/openspec/changes/hide-empty-perps-venues/specs/evelyn-perps-overview/spec.md @@ -0,0 +1,23 @@ +## ADDED Requirements + +### Requirement: Venue visibility follows available child rows +EMC SHALL hide venue rows with neither positions nor Cross accounts and show them when children reappear. Funded empty Cross accounts SHALL keep their venue visible. Hidden venues SHALL remain in snapshots and totals, with read status available in wallet tooltips. Unknown scopes SHALL NOT become zero totals; failed reads SHALL preserve last-success totals. Wallet rows and the root SHALL remain visible. + +#### Scenario: Empty venue +- **WHEN** Jupiter or Phoenix has no positions and no Cross accounts +- **THEN** its heading is absent from that wallet's displayed children +- **AND** a successful empty scope still contributes zero to totals + +#### Scenario: Funded Cross account without positions +- **WHEN** Phoenix returns a Cross account with capital but no open positions +- **THEN** Phoenix and its Cross account remain visible with that capital counted once + +#### Scenario: Positions disappear and return +- **WHEN** a venue loses its last child and later returns a position +- **THEN** its heading disappears and reappears with the correct child +- **AND** unrelated retained rows keep their selection and expansion state + +#### Scenario: Hidden scope has not been read successfully +- **WHEN** a childless venue has never been read successfully and its first read is pending or failed +- **THEN** the heading is hidden and its read status is available on the wallet tooltip +- **AND** required totals remain unavailable rather than reporting zero diff --git a/openspec/changes/hide-empty-perps-venues/tasks.md b/openspec/changes/hide-empty-perps-venues/tasks.md new file mode 100644 index 0000000..01ce7ba --- /dev/null +++ b/openspec/changes/hide-empty-perps-venues/tasks.md @@ -0,0 +1,11 @@ +# Tasks + +## 1. Presentation and documentation + +- [x] 1.1 Filter childless venues and retain their wallet-level read status; verify empty, funded Cross, unknown/failed and returning-position cases in the standalone preview while preserving unrelated tree state. +- [x] 1.2 Update the overview specification and relevant project/shared documentation; verify obsolete visible-empty-group claims are removed and links remain valid. + +## 2. Integrated verification + +- [x] 2.1 Run the normal Gradle build and strict validation for the change and affected spec; record the preview/build results. +- [x] 2.2 Inspect the final diffs and confirm existing unrelated changes, integration behavior and the no-commit/no-push constraint are preserved. diff --git a/openspec/changes/hide-empty-perps-venues/verification.md b/openspec/changes/hide-empty-perps-venues/verification.md new file mode 100644 index 0000000..ccb48c2 --- /dev/null +++ b/openspec/changes/hide-empty-perps-venues/verification.md @@ -0,0 +1,24 @@ +# Verification + +Verified locally on 24 October 2026. No commits, pushes or live Hub restart. + +- Normal `JAVA_HOME=/usr/local/software/java/jfx-25 ./gradlew build` passed: + 42 existing tests, zero failures. +- Strict OpenSpec validation passed for this change and `evelyn-perps-overview`; + the added requirement is synchronized into the main specification. +- Reused the temporary standalone JavaFX preview outside application sources. + Checked both empty venues hidden with wallet retained; pending/failed hidden + scopes still unavailable in totals with wallet-level status; funded empty + Cross account keeping Phoenix visible; Jupiter appearing, disappearing and + returning; unrelated Phoenix item identity, selection and collapse retained; + a previously successful empty read still contributing zero after a failure. +- Existing preview checks for eight columns, formatting and tree reconciliation + also passed. Screenshots are under `/tmp/issue100-check/hide-empty-venues/`; + the TEST and controlled-case views were visually inspected. The preview reused + prior read-only snapshots, with no new exchange reads or application sample data. +- Updated `docs/Evelyn.md`, `docs/PhoenixPerps.md` and the canonical shared + `r35157_docs/projects/evelyn/README.md`, replacing obsolete claims about visible + empty groups and their error/loading indicators. Local links and diff checks passed. +- The source change is confined to `PerpsTab.tjava`; snapshots, integrations, + totals and refresh timing are unchanged. Existing unrelated staged/deleted + OpenSpec artifacts were left untouched. diff --git a/openspec/specs/evelyn-perps-overview/spec.md b/openspec/specs/evelyn-perps-overview/spec.md index a0cadfa..78a4b3a 100644 --- a/openspec/specs/evelyn-perps-overview/spec.md +++ b/openspec/specs/evelyn-perps-overview/spec.md @@ -67,3 +67,25 @@ Tooltips SHALL explain isolated collateral, exposure-based leverage, collateral- - **WHEN** the owner inspects a Cross row and its account group - **THEN** the position shows a USD margin requirement and the account shows shared capital once - **AND** no position-only metric is labeled account utilization + +### Requirement: Venue visibility follows available child rows +EMC SHALL hide venue rows with neither positions nor Cross accounts and show them when children reappear. Funded empty Cross accounts SHALL keep their venue visible. Hidden venues SHALL remain in snapshots and totals, with read status available in wallet tooltips. Unknown scopes SHALL NOT become zero totals; failed reads SHALL preserve last-success totals. Wallet rows and the root SHALL remain visible. + +#### Scenario: Empty venue +- **WHEN** Jupiter or Phoenix has no positions and no Cross accounts +- **THEN** its heading is absent from that wallet's displayed children +- **AND** a successful empty scope still contributes zero to totals + +#### Scenario: Funded Cross account without positions +- **WHEN** Phoenix returns a Cross account with capital but no open positions +- **THEN** Phoenix and its Cross account remain visible with that capital counted once + +#### Scenario: Positions disappear and return +- **WHEN** a venue loses its last child and later returns a position +- **THEN** its heading disappears and reappears with the correct child +- **AND** unrelated retained rows keep their selection and expansion state + +#### Scenario: Hidden scope has not been read successfully +- **WHEN** a childless venue has never been read successfully and its first read is pending or failed +- **THEN** the heading is hidden and its read status is available on the wallet tooltip +- **AND** required totals remain unavailable rather than reporting zero diff --git a/src/main/tjava/com/r35157/evelyn/emc/impl/ref/PerpsTab.tjava b/src/main/tjava/com/r35157/evelyn/emc/impl/ref/PerpsTab.tjava index 88bc569..e6d703b 100644 --- a/src/main/tjava/com/r35157/evelyn/emc/impl/ref/PerpsTab.tjava +++ b/src/main/tjava/com/r35157/evelyn/emc/impl/ref/PerpsTab.tjava @@ -162,11 +162,20 @@ final class PerpsTab { List> wallets = new ArrayList<>(); Map> existingWallets = childrenById(table.getRoot()); for (PerpsSnapshot.Wallet wallet : snapshot.wallets()) { + String walletNotes = TOTAL_NOTES; + for (PerpsSnapshot.Venue venue : wallet.venues()) { + if (venue.positions().isEmpty() && venue.crossAccounts().isEmpty()) { + walletNotes += "\n" + venue.name() + " (no rows): " + status(venue); + } + } TreeItem walletItem = item(existingWallets, - group(wallet.id(), wallet.name(), wallet.totals(), TOTAL_NOTES)); + group(wallet.id(), wallet.name(), wallet.totals(), walletNotes)); List> venues = new ArrayList<>(); Map> existingVenues = childrenById(walletItem); for (PerpsSnapshot.Venue venue : wallet.venues()) { + if (venue.positions().isEmpty() && venue.crossAccounts().isEmpty()) { + continue; + } String status = status(venue); String label = venue.name() + (venue.lastSuccess() == null ? venue.failed() ? " (unavailable)" : " (loading)" : venue.failed() ? " (retained)" : ""); @@ -288,7 +297,7 @@ final class PerpsTab { + "account exactly once, including free capital in those accounts. Cross position requirements are " + "not added to owned collateral. Missing inputs make the affected total unavailable. " + "Successfully read empty scopes total zero. Totals can include last-success observations retained " - + "after failures; inspect venue read status. Ratios are not aggregated."; + + "after failures; inspect wallet and venue read status. Ratios are not aggregated."; private static final String LONG_ROW_STYLE = "-fx-control-inner-background: #e6f4ea;" + "-fx-control-inner-background-alt: #e6f4ea;"; private static final String SHORT_ROW_STYLE = "-fx-control-inner-background: #fce8e6;"