Skip to content

Make data-dense pool, trading and Zoltar views glanceable - #1163

Merged
KillariDev merged 11 commits into
mainfrom
t3code/improve-data-dense-ui
Oct 16, 2026
Merged

KillariDev merged 11 commits into
mainfrom
t3code/improve-data-dense-ui

Conversation

@KillariDev

@KillariDev KillariDev commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The data-dense screens in Statoblast, Trading and Zoltar made people read paragraphs and tables to find the figure that decides their next step. This PR reorders them so that figure leads: details recede, related data is grouped, and nothing new is hidden behind a disclosure. It also fixes four wrong or contradictory states, moves repeated logic into shared helpers, adds three simulation scenarios, and makes timing-sensitive tests pass on a heavily loaded machine.

Fixes

Behaviour that was wrong on main, separate from the layout work:

  • Minting paused: while an escalation game pauses minting, the pool directory said "0 ETH remaining". The directory, the new header strip and the Shares tab now say "Minting paused".
  • Forked pool's Mint: the disabled Mint action now gives the fork stage as its reason before any capacity figure.
  • Migration status: when a pool's migration deadline had not loaded but its truth auction had started, the Migration tab's badge said "Not started" beside a "Migration ended" date, and the vault action's reason said "Migration timing is unavailable". A started truth auction now counts as migration ended everywhere, so the badge reads Closed, an unknown start shows "—", and the reason says the window has closed.
  • Ended pools: the selected vault's Backing details showed an "Associated backing ratio" and health verdict that no longer apply. Both are hidden, matching the vault list.

Changes by area

Statoblast pool page

  • Header strip: one row of figures beside the lifecycle bar. Which figures depend on the stage:

    • Operating pool: capacity used against commitment.
    • Forked or migrating pool: settlement collateral and the migration deadline.
    • Truth auction: the ETH raised against the target and the auction end.
    • Ended pool: the outcome.

    Deadlines lead with the relative time ("in 6d 23h") and set the UTC time beneath it. On phones the strip uses two columns, and a Next actions entry keeps its "Shown below" hint, which points to an action further down the page, on the same line.

  • Pool from another universe: until the app switches to the pool's universe, the strip shows no figures instead of "0 ETH / 0 ETH", and a pending price report stays reachable.

  • Lifecycle bar: stages a pool skipped, such as the fork stages of a pool that settled without a fork, are drawn hollow and announced as "(skipped)".

  • Vaults:

    • The directory shows each vault's health (healthy, near minimum, underwater) and lists the riskiest first. A line above the rows names the REP/ETH price used, because it falls back to Uniswap once the OpenOracle price expires.
    • A row's "Liquidate vault" becomes the primary action when the protocol price confirms the liquidation. While the oracle price is expired or missing it stays available but secondary.
    • Addresses use the short form, so the copy icon sits beside the text.
    • The vault operations form drops repeated context, uses one label style, and a disabled action's reason spans the row.
  • Fork & migration and truth auction:

    • Figures the header already shows, such as the auction's ETH raised and end time, are not repeated in the stage cards.
    • The price ladder marks the prices where you have bids ("Yours 9.00 ETH", or "Yours ≥" while more of your bids are loading), and the bid table names your bids "You".
  • Reporting: REP amounts in the status sentences, preset buttons and notes are rounded and marked "≈", with the exact value on hover and for screen readers. Minimums round up, so "Add at least ≈ 1.01 REP" is always enough to take the lead. Presets still fill the exact amount.

Trading

  • Market page: conditional odds are the headline, and holdings show their payout as a caption.
  • Fork settlement: a one-line explanation, and one-line child-universe rows with short "Pool ready" / "No pool yet" badges.
  • Portfolio: "Needs attention" lists each market once, with all its states and one link per action.
  • Liquidity previews: received shares show their payout as a caption, like the LP amount.

Zoltar

  • The Overview states a fork once, in its status and next step, with one "Migrate REP" action. Other pages keep the app-wide fork notice.

Simulation and docs

  • New scenarios, each booted in an automated test and listed in the README:
    • escalation-in-progress: a disputed report in a running escalation game.
    • near-minimum-vault: a healthy vault just above the security multiplier.
    • finalized-truth-auction: a settled fork auction.
  • Documentation screenshots are recaptured.

Code structure

Where the shared logic lives, for reviewers:

  • Shared components (ui/coreShared):
    • TimestampValue takes relative: 'after' | 'first' | false; 'first' is the relative-first form above.
    • AddressValue has an abbreviated mode that keeps the full address for assistive technology and text search.
    • formatAmount and CurrencyValue accept rounding: 'up'.
  • Protocol timing (statoblastShared/ts/protocol): forkMigrationTiming.ts and truthAuctionTiming.ts hold the deadline constants and the closed and ended checks. getMigrationEnd in truth-auctions/lib/forkAuction.ts is the single migration-ended rule behind the badge, the dates and the action guards.
  • Pool header (security-pools/lib/poolStrip.ts): maps a lifecycle state to the strip's figures and deadline, so the stage cards can leave out what the strip already shows.
  • Vault health and liquidation (security-pools/lib):
    • vaultHealth.ts gives the directory and the selected vault the same health tier and risk order.
    • liquidation.ts adds getVaultLiquidatability, which decides the liquidation emphasis, and shares the base REP requirement and blocked-liquidation reason.
  • Minting pause (security-pools/lib/poolLifecycle.ts): isMintingPausedByEscalation is shared by the header, the directory and the Shares tab.
  • Reporting (reporting/components/RepAmount.tsx): renders REP amounts through CurrencyValue.
  • Trading: OutcomeHolding.tsx holds the holding row and locked caption shared by the market page and the portfolio, and OUTCOME_BALANCE_KEYS lists the outcome balances in one place.
  • Tests: truth auction and pool builders are shared across the Statoblast tests (workflow/builders.ts, forkAuctionFixtures.ts), and testUtils/fakeClock.ts adds withFakeClock.

Unused props, an always-on address flag, an unreachable capacity state and unused CSS are removed. The PR changes 180 files.

Tests under load

Several tests failed when the machine was busy, because they measured real time:

  • Countdowns: about a dozen tests slept for real time and then asserted an exact value, such as "Can settle in 9s". A starved process sleeps longer than asked, so the value had already moved on. They now run on a fake clock (withFakeClock), so time moves only when the test advances it.
  • Waits: waitFor allows 5s instead of 1s; a longer limit only delays reporting a real failure. Waits on the in-process simulation chain share a 60s limit, and simulation setup hooks use the runner's 300s default instead of 180–240s.
  • Stopwatch checks: the anvil diagnostics test proved three lookups run in parallel by finishing within 2s; it now checks that all three start before any times out. The Trading stalled-pool test no longer shortens the healthy pool's reads to 3s.

With four busy loops per core on a 24-core machine, every UI test now passes except two CPU-bound simulation setup hooks, which exceed even 300s at that load. Their limit stays at 300s so that a hung setup still fails within the CI job's time limit.

Screenshots

All captures are from the simulation (?simulate=1) in headless Chromium, at 1440x900 unless noted.

Statoblast: operating pool, header strip and vault form (security-pool)
Pool and vault form

Statoblast: vault directory, with health tiers ordered by risk and the price they use (liquidation-distance)
Vault directory

Statoblast: the same directory after the OpenOracle price expires: Uniswap fallback named, liquidations secondary
Vault directory with expired price

Statoblast: pool directory row while an escalation game pauses minting (escalation-in-progress)
Minting paused

Statoblast: truth auction with ETH raised in the header and your bids on the ladder (securitypoolx2-auction)
Truth auction

Statoblast: migration after the truth auction started: Closed badge, no start date, and the closed window as the vault action's reason (securitypoolx2-auction)
Migration closed

Statoblast: fork & migration, with figures shown once and relative-first dates
Fork and migration

Statoblast: ended pool without a fork, skipped stages drawn hollow (ended-pool-commitment)
Ended pool

Statoblast: the same ended pool's vault, with no health verdict in Backing details (ended-pool-commitment)
Ended pool vault

Statoblast: reporting status with rounded REP amounts (escalation-in-progress)
Reporting rounded amounts

Statoblast: phone header and reporting, 390x844 (escalation-in-progress)
Phone header

Statoblast: light theme, near-minimum vault (near-minimum-vault)
Light near-minimum vault

Trading: market page (trading-funded)
Trading market

Trading: fork settlement (trading-forked)
Trading settlement

Trading: portfolio, with "Needs attention" grouped per market (trading-forked)
Trading portfolio

Zoltar: forked Overview (forked-categorical)
Zoltar overview

Documentation images, before (main) and after

Before After
Portfolio before after
Remove liquidity before after

Validation

On the final head; the branch is current with main:

  • bun run tsc, bun run format:check, bun run check:changed and bun run knip pass.
  • The full UI test list (362 files): 4143 pass, 10 skip, 0 fail.
  • Each fix, the liquidation emphasis and the "ETH raised" strip figure have regression tests that fail on the previous behaviour.
  • bun run docs:check-screenshots -- --strict passes (22 images, 23 embeds), and git diff --check is clean.
  • Browser QA at 1440x900 and 390x844, with no console errors or horizontal overflow. It covered the Statoblast pool header, vault directory (valid and expired price), truth auction, migration, ended pool, escalation and reporting, and the Shares tab; Trading's market, settlement and portfolio; and the Zoltar overview.
  • bun run test:browser:smoke passed earlier on this branch (25 pass; production build tests 22 pass, 6 skip). The final cleanup changes no build or routing code, and CI runs this tier.

Notes

  • Transaction button labels, such as "Report No · 7.999999999999999999 REP…", still quote the exact amount being sent.
  • check:generated-clean and the full bun run check were not run: no contracts, generation scripts or package scripts changed, and check:changed covers the changed files.

Rework the data-dense surfaces so the figures that decide the next action
lead and details recede, without hiding more behind disclosures:

- Statoblast pool header: one strip of stage figures (capacity, settlement
  collateral, deadlines, auction progress) beside the lifecycle bar, with
  skipped stages drawn hollow, a two-column phone layout, and no empty
  figures for a pool from another universe.
- Vaults: health tiers (near minimum, underwater) ordered by risk, a
  compact vault operations form with consistent fields, and addresses that
  keep their copy icon beside the text.
- Fork & migration and truth auction: relative-first dates, figures shown
  once, viewer bids marked on the price ladder ("Yours") and in the bid
  table ("You").
- Reporting: REP amounts render rounded with the exact value on hover;
  minimums round up so the shown figure is always enough.
- Trading: shorter fork settlement copy with one-line target rows,
  portfolio "Needs attention" grouped per market, and caption payouts in
  liquidity previews.
- Zoltar: the Overview states a fork once.
- Simulation: escalation-in-progress, near-minimum-vault and
  finalized-truth-auction scenarios.

Recapture the documentation screenshots.
…ense-ui

# Conflicts:
#	docs/assets/screenshots/fingerprints.json
- Extract the shared pool status strip helpers (poolStrip.ts) so the pool
  header and stage panel build the same tiles and meter, and give the
  strip meter a neutral class instead of reusing the capacity meter.
- Only give the liquidation action primary emphasis when the protocol
  price allows liquidation, not when the UI price shows a vault underwater.
- Share the escalation-game check, the TradingSection outcome helpers,
  and the fork-auction presentation state instead of repeating them.
- Fix the oracle tile padding conflict in the pool strip.
- Derive simulation scenarios from shared builders and hoist repeated
  pool-state fixtures in the workspace tests.
…ense-ui

# Conflicts:
#	docs/assets/screenshots/fingerprints.json
#	docs/assets/screenshots/statoblast/pool-after-mint.png
- Label the truth-auction strip tile "ETH raised": it shows the clearing
  amount capped at the target, which the auction card already calls ETH
  raised. While the strip shows the pool's own auction, the card leaves
  out its duplicate row, as it already did for the end time.
- Make a vault row's liquidation primary only when the protocol price
  confirms it (new getVaultLiquidatability verdict); with an expired or
  missing oracle price every liquidation stays available but secondary.
- Say "Minting paused" instead of "0 ETH remaining" while an escalation
  game pauses an operating pool's minting, through one lifecycle-aware
  isMintingPausedByEscalation shared by the header, the pool directory
  and the Shares tab. A forked pool's Mint states the stage reason before
  any capacity figure.
- Name the REP/ETH price behind the vault directory's health verdicts,
  which fall back to Uniswap once the OpenOracle price expires.
- Drive the header strip and the views that omit what it shows from one
  getPoolStripStage mapping; move the fork timing helpers to the public
  forkAuction lib with a getMigrationEnd unit test.
- Phone strip spacing, the add-target button's height and label, and a
  clearer name for the share formatter that omits the redemption note.
- Recapture the Statoblast documentation screenshots and fingerprints.
- Run countdown tests on a fake clock (new withFakeClock test helper), so
  a starved process no longer sleeps past the exact value they assert.
- Raise the default waitFor limit from 1s to 5s; a longer limit only
  delays reporting a real failure.
- Give waits on the in-process simulation chain a shared 60s limit and
  simulation setup hooks the runner's 300s default.
- Shorten the stalled-pool read deadline in the Trading discovery test to
  10s instead of 3s, leaving the healthy pool's reads room under load.
- Check that the anvil diagnostic lookups start before any times out,
  instead of timing them against a 2s stopwatch.
- Give the tooling timeout test, which starts a separate Bun process,
  60s instead of 15s.
@KillariDev
KillariDev force-pushed the t3code/improve-data-dense-ui branch from 86f5277 to e2561ea Compare October 16, 2026 03:15
- Decide when fork migration has ended in one place (getMigrationEnd):
  a started truth auction or a passed deadline closes it. The badge,
  the Migration started and ended figures and the vault action reason
  now agree, instead of showing "Not started" beside "Closed" or
  "Migration timing is unavailable" after the window closed.
- Move the migration and truth auction timing checks into the protocol
  timing modules, and share the base REP requirement and the blocked
  liquidation reason between the vault views.
- Compute vault health once for the directory and the selected vault,
  so an ended pool's Backing details no longer shows a health verdict.
- Share the outcome holding pieces and outcome balance keys in Trading,
  build the share action launchers from one helper, and drop the
  wrapper around formatOutcomeWithValue.
- Replace TimestampValue's relative and relativeFirst flags with one
  relative option ('after', 'first' or false), and keep the
  relative-first lead on one line.
- Remove dead props, the always-on responsiveAbbreviation flag, an
  unreachable commitment state and unused switch CSS.
- Share truth auction and pool builders across the Statoblast tests,
  restore assertions the cleanup had weakened, and add regression tests
  for the migration states and the ended-pool vault.
- Refresh the documentation screenshot fingerprints; the images are
  unchanged.
@KillariDev
KillariDev enabled auto-merge October 16, 2026 14:37
@KillariDev
KillariDev added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit d144ad3 Oct 16, 2026
48 checks passed
@KillariDev
KillariDev deleted the t3code/improve-data-dense-ui branch October 16, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant