feat: /protocol stats — inline Δ%, volume prior-window %, daily series, flatten nesting #652

Closed
opened 2026-08-26 01:10:53 +00:00 by PlasticDigits · 24 comments
PlasticDigits commented 2026-08-26 01:10:53 +00:00 (Migrated from gitlab.com)

Summary

Retail /protocol Global stats shows Total liquidity as $57K in one box and 24h liquidity +13.48% / 30d liquidity — in separate boxes. Last 24h vol has no prior-period Δ%. Fees on the same page already compute trailing-window flow Δ% but also split value vs % into six StatBox cards. The section is a shell-panel wrapping a grid of card-glass StatBoxes (chrome-in-chrome).

Bundle into one issue: inline Δ% on each metric, volume prior-window Δ% (24h / 7d / 30d), flatten Global stats + Protocol fees nesting, and a UTC-day volume series (7d / 30d) under the volume row. Do not split “volume %” vs “merge boxes” vs “daily chart” vs “fees inline Δ%”.

Related: #550 (USD census), #569 (TVL + snapshot Δ%), #586 (fee totals + flow_change_pct), #576 (trailing vs calendar copy), #577 (window decay), #489 (short copy), #631 (Llama UTC-day rollup — wrong shape to N+1 from the browser), #561 L561-2 (one chrome layer). Companion chrome pass: follow-up issue filed in the same batch (anti-nesting invariant + dApp audit).

Current codebase

/protocol is the DEX USD census page. Global stats and fees already have the numbers; the layout treats Δ% as extra cards and volume has no prior-window % at all.

Layer Behavior today
Global stats UI ProtocolGlobalStats.tsx: shell-panel (protocol-global-stats) + 11-entry STATS grid. Each cell wraps StatBox (card-glass !p-3). Liquidity is three boxes: protocol-stat-liquidity (formatProtocolUsd(total_liquidity_usd)), protocol-stat-liquidity-24h / protocol-stat-liquidity-30d (formatProtocolPct). Volume 24h / 7d / 30d are USD only — no volume_change_*. Census (tokens, new tokens/pairs 30d, active pairs, 24h trades) is count-only.
Fees UI ProtocolFeeStats.tsx: same shell-panel + StatBox nest. Six boxes: 24h/7d/30d USD and three sibling “fee change” cards (protocol-stat-fees-*-chg). Source/token tables sit below.
StatBox Always card-glass. No delta column, no flat variant. Value is a single string.
Overview JSON overview.rs: 60s cache. Has total_volume_{24h,7d,30d}_usd, total_liquidity_usd, liquidity_change_{24h,30d}_pct, total_fees_*_usd, fees_change_{24h,7d,30d}_pct. No volume_change_*_pct. Liquidity Δ% is vs snapshots (stock). Fee Δ% is vs prior equal trailing window (flow).
Volume rollup refresh_global_stats aggregates swap_events for now−24h / now−7d / now−30d only. Does not compute [48h,24h), [14d,7d), [60d,30d) priors. GET live path (OVERVIEW_GLOBAL_STATS_LIVE) also lacks priors.
Fee Δ% pattern protocol_fees.rs + flow_change_pct: (current − prior) / prior × 100 when prior > 0; else None (never Inf). Aggregator-only; GET reads global_stats_24h.
Liquidity Δ% Snapshot vs global_liquidity_snapshots (P569-2). then=0 / missing → null → em-dash. Not a flow Δ%.
Daily series GET /api/v1/defillama/daily is one UTC timestamp (L631-7). from/to ignored. No range dump. Llama volume excludes gems, wrap/unwrap, UST1 window (L631-3–L631-5) — not the same as Protocol total_volume_*_usd. Frontend has no Protocol volume chart. PriceChart is pair candles, not DEX-wide daily bars.
Copy trailingWindowCopy.ts: volume labels are trailing Utc::now()−N, not calendar. Fee change titles already say “prior window / em-dash until both windows fill.”
Tests / verify ProtocolPage.test.tsx asserts separate liquidity-24h / 30d boxes and fee-chg boxes. e2e/protocol-page.spec.ts same. make verify-issue-550 / 569 / 586 / 576.
Docs / skills AGENTS_FRONTEND_PROTOCOL_STATS.md P569-1 / P569-7 require liquidity Δ% as boxes inside protocol-global-stats. PFee-2 is fee Δ% vs prior window. docs/design-system.md “One chrome layer per region” still allows nested card-glass inside shell-panel for “distinct inner blocks.”

Why this is needed

  1. Δ% as a sibling card is unreadably expensive. On a phone, 24h liquidity occupies a full tile that is only a percent. Operators expect $57K with +13.48% 24h (and 30d) on the same row — same for volume and fees.
  2. Volume has no “vs last period.” Liquidity and fees already answer “is this growing?” Volume is the headline flow metric and still has no prior-window %. A circled empty 24h-vol tile is that gap.
  3. A single 24h % is a thin view of flow. After seeing the fee breakdown, a 7d / 30d by-day chart is the right second surface: totals stay on the tiles; shape of the last week/month lives in bars. Trailing 24h/7d/30d totals stay; calendar bars are additive, not a replacement.
  4. Nesting violates the chrome principle. shell-panel + 11× card-glass is box-in-box for the same metric region. #561 audited Trade/Swap/Pool/Limits/Charts strip wording, but Protocol (and StatBox itself) still nests. Fix this page here; the repo-wide pass is the companion issue.
  5. Fees already have the math. Shipping a second Δ% algorithm for volume would drift from flow_change_pct / PFee-2 / #576.

Constraints / guardrails

  1. Keep P550 / P569 / PFee / V5 / D6. GET /overview stays 60s cache + O(1) rollup. Do not SUM 60d swap_events on the request path. Volume priors are computed on the aggregator (~5 min), same as fees.
  2. Volume Δ% is flow, not TVL snapshots. Reuse flow_change_pct. Windows: current now−W vs prior [2W, W). prior ≤ 0 / missing / overflow → JSON null, UI em-dash. Never Infinity / NaN / "∞%" / client now/then without a zero guard. --fresh / young indexer → em-dash until 2×W fills (PFee-9 / P569-8 pattern).
  3. Do not confuse stock vs flow. Liquidity 24h/30d stay snapshot Δ% (P569-2). Do not recompute liquidity % from volume. Do not title volume Δ% “liquidity.”
  4. Same USD catalog as volume (P550-4 / P522-Q / X4). Never vFDUSD. Never $1 UST1 or 2.5× USTR. Activity + all unpriced → volume USD null and Δ% null (do not treat as $0 then −100%). Idle (trades=0) → $0; Δ% vs a positive prior may be −100% (same as fees).
  5. Additive overview JSON. New keys volume_change_24h_pct / volume_change_7d_pct / volume_change_30d_pct optional on IndexerOverview until indexer ships. Old indexers → volume tiles show USD + em-dash Δ%. Charts overview strip stays additive-compatible.
  6. Inline Δ%, do not delete testids. Merge liquidity 24h/30d into protocol-stat-liquidity (value + % 24h + % 30d). Merge each fee window’s chg box into the USD tile. Keep protocol-stat-liquidity-24h / protocol-stat-liquidity-30d / protocol-stat-fees-*-chg as child testids on the Δ% nodes so #569 / #586 / e2e can be updated, not silently dropped.
  7. Census tiles stay value-only. Tokens / new tokens / new pairs / active pairs / 24h trades do not invent a 0% column.
  8. Flatten chrome on this page. Inside protocol-global-stats and protocol-fee-stats, metric cells must not be card-glass (no StatBox default nest). Use a flat StatRow / StatBox variant="flat": label, value, optional Δ% column (positive --color-positive, negative --color-negative). One shell-panel per section. Do not wrap the grid in a second panel. Light + dark; 375px wrap: value and Δ% stay one cell (Δ% to the right of the value, not a new tile).
  9. Copy / #489 / #576. Visible labels stay ≤ ~5 words. Δ% suffix 24h / 7d / 30d is enough. Depth in title / aria-label (reuse fee prior-window titles). Daily chart must say UTC calendar day so it is not read as the trailing 24h/7d/30d tiles. No lecture banner. No “launched on chain” / genesis claims.
  10. Daily series is a new bounded Protocol API — not Llama N+1. Do not have the dApp call GET /defillama/daily 7–30 times. Do not add unbounded from/to to Llama (L631-7). Add GET /api/v1/protocol/volume/daily?days=7|30 (allowlist; else 400). 60s cache. Reads a capped daily rollup only (prune ≥ 35 days). Aggregator refresh, not GET-path swap_events scan. OVERVIEW_GLOBAL_STATS_LIVE=1 must still not 60d-SUM on GET.
  11. Daily methodology = Protocol headlines, not Llama. UTC-day SUM(swap_events.volume_usd) with the same P522-Q catalog as overview. Do not silently reuse defillama_daily_stats (gem / wrap / window exclusions). If a future change shares storage, copy must label the exclusion. Idle day → "0"; activity + unpriced → null bar (not $0). Cap 30 points. No CSV / no per-pair dump in v1.
  12. Chart is bars, not pair candles. Do not mount PriceChart. No trading overlay. Empty / loading / error + retry. Hide the chart if the range endpoint is missing (old indexer), do not invent zeros. Default 7d; 30d toggle. Do not headline unique traders.
  13. Page order (P550-1) unchanged: title → Global stats (tiles + optional volume chart inside protocol-global-stats) → Protocol fees → hub → oracle → audit → hooks. Do not clone factory/router AddressRow (#378).
  14. Update invariants. P569-1 / P569-7 / PFee-2 currently describe separate Δ% boxes. Rewrite to inline Δ%. Skill + docs/frontend.md § Protocol + docs/indexer-invariants.md. New make verify-issue-* for this ticket; keep verify-issue-550 / 569 / 586 / 576 / 577 / 631 green (adjust selectors, do not weaken rollup/DoS tests).
  15. No unique-trader headline. Dust-swap gaming (#489 / #550 AC7).
  16. Advisory. Reference USD, not settlement / TWAP / /ust1 window.

Relevant files

Path Role
frontend-dapp/src/components/protocol/ProtocolGlobalStats.tsx Merge liquidity Δ%; add volume Δ%; flatten; host daily chart
frontend-dapp/src/components/protocol/ProtocolFeeStats.tsx Inline fee Δ%; flatten
frontend-dapp/src/components/ui/StatBox.tsx flat variant + optional delta
frontend-dapp/src/utils/formatProtocolStats.ts USD / pct (never Inf)
frontend-dapp/src/utils/trailingWindowCopy.ts Volume Δ% + UTC-day chart titles
frontend-dapp/src/types/index.ts IndexerOverview Additive volume_change_*
frontend-dapp/src/pages/ProtocolPage.test.tsx RTL: inline Δ%, missing fields, no extra tiles
frontend-dapp/e2e/protocol-page.spec.ts Smoke: one liquidity tile, fee tiles, chart toggle
indexer/src/api/overview.rs Additive volume Δ% JSON
indexer/src/db/queries/volume.rs Prior windows on refresh; GET still O(1)
indexer/src/indexer/protocol_fees.rs flow_change_pct Reuse — do not fork
indexer/src/indexer/volume_aggregator.rs Refresh daily rollup + volume Δ%
indexer/src/api/defillama.rs Do not range-dump; Protocol gets its own route
New indexer/src/api/protocol_volume_daily.rs (or equivalent) days=7|30 allowlist + 60s cache
New migration on global_stats_24h + daily table (35d prune) Materialize Δ% + UTC-day USD
indexer/tests/indexer_overview_global_stats.rs Rollup vs live; EXPLAIN no GET scan
indexer/tests/indexer_protocol_fees.rs flow_change_pct parity for volume
skills/AGENTS_FRONTEND_PROTOCOL_STATS.md P569 / PFee layout rewrite
docs/frontend.md § Protocol Inline Δ% + chart
docs/indexer-invariants.md Volume Δ% + daily GET DoS
  1. Indexer — volume flow Δ%. Extend refresh_global_stats (and live helper used only by tests) with prior equal windows, same cutoffs as fees (c48 / c14 / c60). Persist volume_change_*_pct on global_stats_24h. Call flow_change_pct. Do not walk snapshots.
  2. Indexer — UTC-day series. New table (or Protocol-owned columns) refreshed in the volume loop: one row per UTC day, volume_usd + trade_count, prune 35d. New GET with days allowlist 7 | 30, newest-last array, 60s cache. EXPLAIN tests: no swap_events on GET.
  3. Frontend — StatRow. Add variant?: 'card' \| 'flat' (default card so Swap/Trade callers stay). flat = no card-glass. Optional delta + deltaLabel (24h). Protocol Global stats + fees use flat.
  4. Frontend — merge tiles. Liquidity: one cell, USD + 24h Δ% + 30d Δ%. Volume: three cells, each USD + Δ%. Fees: three cells, each USD + Δ%. Chart under the volume row, 7d/30d toggle, data-testid="protocol-volume-daily-chart".
  5. Docs. Rewrite P569-1/P569-7/PFee-2. Point chrome flattening at this ticket; repo-wide pass is the companion issue.

Acceptance criteria

  • GET /overview includes volume_change_{24h,7d,30d}_pct (string or null). Cache-miss does not scan swap_events / protocol_fee_events / snapshot history.
  • Volume Δ% matches flow_change_pct vs prior equal trailing window. prior ≤ 0 → null. Unpriced activity → null. Overflow → null. Never Inf.
  • /protocol Global stats: Total liquidity shows USD and 24h/30d Δ% in that cell. No standalone liquidity-% tiles.
  • Last 24h / 7d / 30d vol each show USD and prior-window Δ% in the same cell (em-dash until both windows fill).
  • Protocol fees: three USD tiles with inline Δ%; no sibling “fee change” tiles.
  • Census tiles unchanged (no fake %).
  • No card-glass inside protocol-global-stats or protocol-fee-stats metric grids (one shell-panel each).
  • Daily volume chart (7d default / 30d) inside Global stats; UTC-day copy; missing endpoint hides chart; idle $0, unpriced —.
  • GET /api/v1/protocol/volume/daily?days= only 7 | 30; else 400. No Llama range dump. Methodology = Protocol catalog, not Llama gem-exclude, unless explicitly labeled (do not silently mix).
  • Old indexer (no new keys / no daily route): tiles still render; Δ% em-dash; chart hidden. Charts overview still works.
  • Light + dark; 375px: value + Δ% stay one cell; no horizontal overflow from nested cards.
  • aria-label includes trailing-window / prior-window / UTC-day text so mobile is not hover-only (#576).
  • Skills + frontend + indexer-invariants + make verify-issue-* for this ticket. verify-issue-550 / 569 / 586 / 576 / 577 / 631 still pass.

Test plan (all paths)

Indexer — volume Δ%

  • Seed priced swaps in now−24h and [48h,24h): Δ% = (cur−prior)/prior×100 (fixture parity with flow_change_pct).
  • Prior window empty or prior=0 → JSON null.
  • Current idle (trades=0, usd=0) + positive prior → −100 (or documented equivalent); UI shows $0 + negative %.
  • Current trades>0 and volume_usd all null → overview volume null, Δ% null (not −100% from a fake $0).
  • 7d / 30d same matrix ([14d,7d), [60d,30d)).
  • --fresh / no history → all three null.
  • Decay (#577): age swaps out of current 24h into prior; totals drop; Δ% updates on refresh, not on GET.
  • OVERVIEW_GLOBAL_STATS_LIVE=1 GET still does not 60d-SUM fees or volume priors from swap_events (rollup read). EXPLAIN on GET /overview and GET daily: no swap_events.
  • Additive JSON: omit new keys on a unit fixture that mimics old indexer; frontend still renders.

Indexer — daily series

  • days=7 → ≤7 points; days=30 → ≤30; days=1 / days=90 / days= / days=7%3b / days[]= → 400.
  • UTC midnight boundaries: swap at 23:59Z vs 00:00Z land on the correct day.
  • Idle closed day → "0"; activity+unpriced → null; no row yet → omit or "0" consistently (document).
  • Prune: rows older than 35d gone; GET never walks them.
  • Gem / wrap / window swaps: included if they are in overview volume_usd; do not copy Llama exclusions without a label test.
  • Cache: two GETs within 60s hit cache; refresh updates after TTL.

Frontend — layout + Δ%

  • RTL: liquidity USD and both Δ% inside protocol-stat-liquidity; queryByTestId standalone 24h/30d cards absent; child Δ% testids present.
  • Volume 24h cell contains compact USD and %; 7d/30d same.
  • Fees: three tiles; protocol-stat-fees-24h contains USD + Δ%; chg testid is a child, not a sibling card.
  • Missing / null / "Infinity" / "NaN" / 1e309 → em-dash (existing formatProtocolPct).
  • XSS: total_volume_24h_usd / Δ% / daily point = "><script> / javascript: render as text, not HTML.
  • Loading skeletons; overview error → existing RetryError; daily error → retry on chart only (do not hide tiles).
  • Word count of new visible labels ≤ 5 (trailingWindowCopy test).
  • Theme: positive/negative Δ% use semantic tokens; gold not a fill.

Frontend — daily chart

  • 7d default; toggle 30d refetches days=30 only.
  • Old indexer 404 / unimplemented → chart not mounted (no $0 sparkline).
  • Empty series / all null → empty state, not a fake axis.
  • Does not render PriceChart / pair interval chips.
  • Keyboard: toggle is a button/tab with visible focus (--focus-ring).

E2E / verify

  • e2e/protocol-page.spec.ts: page order, one liquidity tile, fee tiles, chart testid when API present.
  • make verify-issue-550 569 586 576 577 631 + new verify script.
  • Mobile 375 and desktop 1280: no card-in-card ring; Δ% not dropped under the fold as its own tile.

Test plan (attack, hack, and abuse)

  • DoS / GET amplification. days=999999, negative, array, SQL-looking strings → 400, no scan. Parallel burst of /overview + daily stays 60s cache (no per-request 60d SUM).
  • Llama coupling. Client must not hammer /defillama/daily. Adding from/to to Llama in this ticket is a fail.
  • Methodology spoof. Chart must not display Llama gem-excluded volume as if it were Protocol total_volume_*_usd without label.
  • Infinity / overflow. Huge current vs dust prior that overflows NUMERIC(38,18) → null, not a 1e400 string that breaks UI or JSON.
  • Unpriced → fake dump. Oracle down must not print −100% on a $0 that is actually unpriced activity.
  • XSS / HTML injection in USD, %, day labels, SVG/title attributes.
  • Open redirect / ticker. Chart and stats ignore ?ticker=; still allowlist oracle chips (P550-2).
  • Cache poisoning. Daily response must not key on unvalidated raw query beyond allowlisted days.
  • Dust / wash volume. Δ% and daily bars use the same swap set as overview (dust counts, same as volume/fees). Do not add unique-trader or “bot filtered” math in v1.
  • Stale rollup. updated_at >15 min: log + serve (D6); do not fall back to live 60d scan.
  • Clickjacking / overlay. Chart is non-interactive (no wallet). No new signing surface.

Verification criteria

  • make setup-indexer-postgres then new make verify-issue-* (lib + overview + daily integration, --test-threads=1).
  • make test-frontend includes ProtocolPage / StatBox / trailingWindowCopy / formatProtocolStats.
  • Playwright e2e-smoke Protocol path green (5 workers; no e2e-tx required).
  • Manual: /protocol at 375px and 1280px, light + dark — liquidity is one cell ($… + % 24h + % 30d); 24h vol shows a % or em-dash; fees are three tiles; chart 7d/30d; no card-in-card rings in those two panels.
  • Docs/skills match the shipped layout (no leftover “24h liquidity box” language).
  • Companion anti-nesting issue referenced; this ticket does not restyle Charts/Trader/Swap IO cards except StatBox API backward compatibility.
## Summary Retail `/protocol` **Global stats** shows **Total liquidity** as `$57K` in one box and **24h liquidity** `+13.48%` / **30d liquidity** `—` in separate boxes. **Last 24h vol** has no prior-period Δ%. Fees on the same page already compute trailing-window flow Δ% but also split value vs % into six `StatBox` cards. The section is a `shell-panel` wrapping a grid of `card-glass` `StatBox`es (chrome-in-chrome). Bundle into **one** issue: inline Δ% on each metric, volume prior-window Δ% (24h / 7d / 30d), flatten Global stats + Protocol fees nesting, and a **UTC-day volume series** (7d / 30d) under the volume row. Do **not** split “volume %” vs “merge boxes” vs “daily chart” vs “fees inline Δ%”. Related: [#550](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/550) (USD census), [#569](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/569) (TVL + snapshot Δ%), [#586](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/586) (fee totals + `flow_change_pct`), [#576](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/576) (trailing vs calendar copy), [#577](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/577) (window decay), [#489](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/489) (short copy), [#631](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/631) (Llama UTC-day rollup — **wrong** shape to N+1 from the browser), [#561](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/561) **L561-2** (one chrome layer). Companion chrome pass: follow-up issue filed in the same batch (anti-nesting invariant + dApp audit). ## Current codebase `/protocol` is the DEX USD census page. Global stats and fees already have the **numbers**; the layout treats Δ% as extra cards and volume has **no** prior-window % at all. | Layer | Behavior today | |-------|----------------| | **Global stats UI** | [`ProtocolGlobalStats.tsx`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/protocol/ProtocolGlobalStats.tsx): `shell-panel` (`protocol-global-stats`) + 11-entry `STATS` grid. Each cell wraps [`StatBox`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/ui/StatBox.tsx) (`card-glass !p-3`). Liquidity is **three** boxes: `protocol-stat-liquidity` (`formatProtocolUsd(total_liquidity_usd)`), `protocol-stat-liquidity-24h` / `protocol-stat-liquidity-30d` (`formatProtocolPct`). Volume 24h / 7d / 30d are USD only — **no** `volume_change_*`. Census (tokens, new tokens/pairs 30d, active pairs, 24h trades) is count-only. | | **Fees UI** | [`ProtocolFeeStats.tsx`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/protocol/ProtocolFeeStats.tsx): same `shell-panel` + `StatBox` nest. Six boxes: 24h/7d/30d USD **and** three sibling “fee change” cards (`protocol-stat-fees-*-chg`). Source/token tables sit below. | | **StatBox** | Always `card-glass`. No delta column, no `flat` variant. Value is a single string. | | **Overview JSON** | [`overview.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/api/overview.rs): 60s cache. Has `total_volume_{24h,7d,30d}_usd`, `total_liquidity_usd`, `liquidity_change_{24h,30d}_pct`, `total_fees_*_usd`, `fees_change_{24h,7d,30d}_pct`. **No** `volume_change_*_pct`. Liquidity Δ% is vs **snapshots** (stock). Fee Δ% is vs **prior equal trailing window** (flow). | | **Volume rollup** | [`refresh_global_stats`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/db/queries/volume.rs) aggregates `swap_events` for `now−24h` / `now−7d` / `now−30d` only. Does **not** compute `[48h,24h)`, `[14d,7d)`, `[60d,30d)` priors. GET live path (`OVERVIEW_GLOBAL_STATS_LIVE`) also lacks priors. | | **Fee Δ% pattern** | [`protocol_fees.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/db/queries/protocol_fees.rs) + [`flow_change_pct`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/indexer/protocol_fees.rs): `(current − prior) / prior × 100` when `prior > 0`; else `None` (never Inf). Aggregator-only; GET reads `global_stats_24h`. | | **Liquidity Δ%** | Snapshot vs `global_liquidity_snapshots` (**P569-2**). `then=0` / missing → `null` → em-dash. Not a flow Δ%. | | **Daily series** | [`GET /api/v1/defillama/daily`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/api/defillama.rs) is **one** UTC `timestamp` (**L631-7**). `from`/`to` ignored. No range dump. Llama volume **excludes** gems, wrap/unwrap, UST1 window (**L631-3–L631-5**) — **not** the same as Protocol `total_volume_*_usd`. Frontend has **no** Protocol volume chart. [`PriceChart`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/charts/PriceChart.tsx) is pair candles, not DEX-wide daily bars. | | **Copy** | [`trailingWindowCopy.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/utils/trailingWindowCopy.ts): volume labels are trailing `Utc::now()−N`, not calendar. Fee change titles already say “prior window / em-dash until both windows fill.” | | **Tests / verify** | [`ProtocolPage.test.tsx`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/pages/ProtocolPage.test.tsx) asserts **separate** liquidity-24h / 30d boxes and fee-chg boxes. [`e2e/protocol-page.spec.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/e2e/protocol-page.spec.ts) same. `make verify-issue-550` / `569` / `586` / `576`. | | **Docs / skills** | [`AGENTS_FRONTEND_PROTOCOL_STATS.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_FRONTEND_PROTOCOL_STATS.md) **P569-1** / **P569-7** require liquidity Δ% as **boxes inside** `protocol-global-stats`. **PFee-2** is fee Δ% vs prior window. [`docs/design-system.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/design-system.md) “One chrome layer per region” still **allows** nested `card-glass` inside `shell-panel` for “distinct inner blocks.” | ## Why this is needed 1. **Δ% as a sibling card is unreadably expensive.** On a phone, **24h liquidity** occupies a full tile that is only a percent. Operators expect `$57K` with `+13.48% 24h` (and 30d) on the **same** row — same for volume and fees. 2. **Volume has no “vs last period.”** Liquidity and fees already answer “is this growing?” Volume is the headline flow metric and still has no prior-window %. A circled empty 24h-vol tile is that gap. 3. **A single 24h % is a thin view of flow.** After seeing the fee breakdown, a **7d / 30d by-day** chart is the right second surface: totals stay on the tiles; shape of the last week/month lives in bars. Trailing 24h/7d/30d totals stay; calendar bars are additive, not a replacement. 4. **Nesting violates the chrome principle.** `shell-panel` + 11× `card-glass` is box-in-box for the **same** metric region. #561 audited Trade/Swap/Pool/Limits/Charts strip wording, but Protocol (and `StatBox` itself) still nests. Fix this page here; the repo-wide pass is the companion issue. 5. **Fees already have the math.** Shipping a second Δ% algorithm for volume would drift from `flow_change_pct` / PFee-2 / `#576`. ## Constraints / guardrails 1. **Keep P550 / P569 / PFee / V5 / D6.** `GET /overview` stays 60s cache + O(1) rollup. Do **not** `SUM` 60d `swap_events` on the request path. Volume priors are computed on the **aggregator** (~5 min), same as fees. 2. **Volume Δ% is flow, not TVL snapshots.** Reuse `flow_change_pct`. Windows: current `now−W` vs prior `[2W, W)`. `prior ≤ 0` / missing / overflow → JSON `null`, UI em-dash. **Never** `Infinity` / `NaN` / `"∞%"` / client `now/then` without a zero guard. `--fresh` / young indexer → em-dash until 2×W fills (**PFee-9** / **P569-8** pattern). 3. **Do not confuse stock vs flow.** Liquidity 24h/30d stay **snapshot** Δ% (**P569-2**). Do not recompute liquidity % from volume. Do not title volume Δ% “liquidity.” 4. **Same USD catalog as volume (P550-4 / P522-Q / X4).** Never vFDUSD. Never `$1` UST1 or `2.5×` USTR. Activity + all unpriced → volume USD `null` and Δ% `null` (do not treat as `$0` then `−100%`). Idle (`trades=0`) → `$0`; Δ% vs a positive prior may be `−100%` (same as fees). 5. **Additive overview JSON.** New keys `volume_change_24h_pct` / `volume_change_7d_pct` / `volume_change_30d_pct` optional on `IndexerOverview` until indexer ships. Old indexers → volume tiles show USD + em-dash Δ%. Charts overview strip stays additive-compatible. 6. **Inline Δ%, do not delete testids.** Merge liquidity 24h/30d **into** `protocol-stat-liquidity` (value + `% 24h` + `% 30d`). Merge each fee window’s chg box into the USD tile. Keep `protocol-stat-liquidity-24h` / `protocol-stat-liquidity-30d` / `protocol-stat-fees-*-chg` as **child** testids on the Δ% nodes so #569 / #586 / e2e can be updated, not silently dropped. 7. **Census tiles stay value-only.** Tokens / new tokens / new pairs / active pairs / 24h trades do **not** invent a 0% column. 8. **Flatten chrome on this page.** Inside `protocol-global-stats` and `protocol-fee-stats`, metric cells must **not** be `card-glass` (no `StatBox` default nest). Use a flat `StatRow` / `StatBox variant="flat"`: label, value, optional Δ% column (positive `--color-positive`, negative `--color-negative`). One `shell-panel` per section. Do **not** wrap the grid in a second panel. Light + dark; 375px wrap: value and Δ% stay one cell (Δ% to the **right** of the value, not a new tile). 9. **Copy / #489 / #576.** Visible labels stay ≤ ~5 words. Δ% suffix `24h` / `7d` / `30d` is enough. Depth in `title` / `aria-label` (reuse fee prior-window titles). Daily chart must say **UTC calendar day** so it is not read as the trailing 24h/7d/30d tiles. No lecture banner. No “launched on chain” / genesis claims. 10. **Daily series is a new bounded Protocol API — not Llama N+1.** Do **not** have the dApp call `GET /defillama/daily` 7–30 times. Do **not** add unbounded `from`/`to` to Llama (**L631-7**). Add `GET /api/v1/protocol/volume/daily?days=7|30` (allowlist; else **400**). 60s cache. Reads a **capped** daily rollup only (prune ≥ 35 days). Aggregator refresh, not GET-path `swap_events` scan. `OVERVIEW_GLOBAL_STATS_LIVE=1` must still not 60d-SUM on GET. 11. **Daily methodology = Protocol headlines, not Llama.** UTC-day `SUM(swap_events.volume_usd)` with the **same** P522-Q catalog as overview. Do **not** silently reuse `defillama_daily_stats` (gem / wrap / window exclusions). If a future change shares storage, copy must label the exclusion. Idle day → `"0"`; activity + unpriced → `null` bar (not `$0`). Cap 30 points. No CSV / no per-pair dump in v1. 12. **Chart is bars, not pair candles.** Do not mount `PriceChart`. No trading overlay. Empty / loading / error + retry. Hide the chart if the range endpoint is missing (old indexer), do not invent zeros. Default **7d**; **30d** toggle. Do not headline unique traders. 13. **Page order (P550-1) unchanged:** title → Global stats (tiles + optional volume chart **inside** `protocol-global-stats`) → Protocol fees → hub → oracle → audit → hooks. Do not clone factory/router `AddressRow` (#378). 14. **Update invariants.** **P569-1** / **P569-7** / **PFee-2** currently describe **separate** Δ% boxes. Rewrite to inline Δ%. Skill + `docs/frontend.md` § Protocol + `docs/indexer-invariants.md`. New `make verify-issue-*` for this ticket; keep `verify-issue-550` / `569` / `586` / `576` / `577` / `631` green (adjust selectors, do not weaken rollup/DoS tests). 15. **No unique-trader headline.** Dust-swap gaming (#489 / #550 AC7). 16. **Advisory.** Reference USD, not settlement / TWAP / `/ust1` window. ## Relevant files | Path | Role | |------|------| | [`frontend-dapp/src/components/protocol/ProtocolGlobalStats.tsx`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/protocol/ProtocolGlobalStats.tsx) | Merge liquidity Δ%; add volume Δ%; flatten; host daily chart | | [`frontend-dapp/src/components/protocol/ProtocolFeeStats.tsx`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/protocol/ProtocolFeeStats.tsx) | Inline fee Δ%; flatten | | [`frontend-dapp/src/components/ui/StatBox.tsx`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/components/ui/StatBox.tsx) | `flat` variant + optional delta | | [`frontend-dapp/src/utils/formatProtocolStats.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/utils/formatProtocolStats.ts) | USD / pct (never Inf) | | [`frontend-dapp/src/utils/trailingWindowCopy.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/utils/trailingWindowCopy.ts) | Volume Δ% + UTC-day chart titles | | [`frontend-dapp/src/types/index.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/types/index.ts) `IndexerOverview` | Additive `volume_change_*` | | [`frontend-dapp/src/pages/ProtocolPage.test.tsx`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/src/pages/ProtocolPage.test.tsx) | RTL: inline Δ%, missing fields, no extra tiles | | [`frontend-dapp/e2e/protocol-page.spec.ts`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/frontend-dapp/e2e/protocol-page.spec.ts) | Smoke: one liquidity tile, fee tiles, chart toggle | | [`indexer/src/api/overview.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/api/overview.rs) | Additive volume Δ% JSON | | [`indexer/src/db/queries/volume.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/db/queries/volume.rs) | Prior windows on refresh; GET still O(1) | | [`indexer/src/indexer/protocol_fees.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/indexer/protocol_fees.rs) `flow_change_pct` | Reuse — do not fork | | [`indexer/src/indexer/volume_aggregator.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/indexer/volume_aggregator.rs) | Refresh daily rollup + volume Δ% | | [`indexer/src/api/defillama.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/src/api/defillama.rs) | **Do not** range-dump; Protocol gets its own route | | New `indexer/src/api/protocol_volume_daily.rs` (or equivalent) | `days=7\|30` allowlist + 60s cache | | New migration on `global_stats_24h` + daily table (35d prune) | Materialize Δ% + UTC-day USD | | [`indexer/tests/indexer_overview_global_stats.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/tests/indexer_overview_global_stats.rs) | Rollup vs live; EXPLAIN no GET scan | | [`indexer/tests/indexer_protocol_fees.rs`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/indexer/tests/indexer_protocol_fees.rs) | `flow_change_pct` parity for volume | | [`skills/AGENTS_FRONTEND_PROTOCOL_STATS.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/skills/AGENTS_FRONTEND_PROTOCOL_STATS.md) | P569 / PFee layout rewrite | | [`docs/frontend.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/frontend.md) § Protocol | Inline Δ% + chart | | [`docs/indexer-invariants.md`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/blob/main/docs/indexer-invariants.md) | Volume Δ% + daily GET DoS | ## Recommended direction 1. **Indexer — volume flow Δ%.** Extend `refresh_global_stats` (and live helper used only by tests) with prior equal windows, same cutoffs as fees (`c48` / `c14` / `c60`). Persist `volume_change_*_pct` on `global_stats_24h`. Call `flow_change_pct`. Do not walk snapshots. 2. **Indexer — UTC-day series.** New table (or Protocol-owned columns) refreshed in the volume loop: one row per UTC day, `volume_usd` + `trade_count`, prune 35d. New GET with `days` allowlist `7` \| `30`, newest-last array, 60s cache. EXPLAIN tests: no `swap_events` on GET. 3. **Frontend — StatRow.** Add `variant?: 'card' \| 'flat'` (default `card` so Swap/Trade callers stay). `flat` = no `card-glass`. Optional `delta` + `deltaLabel` (`24h`). Protocol Global stats + fees use `flat`. 4. **Frontend — merge tiles.** Liquidity: one cell, USD + 24h Δ% + 30d Δ%. Volume: three cells, each USD + Δ%. Fees: three cells, each USD + Δ%. Chart under the volume row, 7d/30d toggle, `data-testid="protocol-volume-daily-chart"`. 5. **Docs.** Rewrite P569-1/P569-7/PFee-2. Point chrome flattening at this ticket; repo-wide pass is the companion issue. ## Acceptance criteria - [ ] `GET /overview` includes `volume_change_{24h,7d,30d}_pct` (`string` or `null`). Cache-miss does not scan `swap_events` / `protocol_fee_events` / snapshot history. - [ ] Volume Δ% matches `flow_change_pct` vs prior equal trailing window. `prior ≤ 0` → `null`. Unpriced activity → `null`. Overflow → `null`. Never Inf. - [ ] `/protocol` Global stats: **Total liquidity** shows USD **and** 24h/30d Δ% in that cell. No standalone liquidity-% tiles. - [ ] Last 24h / 7d / 30d vol each show USD **and** prior-window Δ% in the same cell (em-dash until both windows fill). - [ ] Protocol fees: three USD tiles with inline Δ%; no sibling “fee change” tiles. - [ ] Census tiles unchanged (no fake %). - [ ] No `card-glass` inside `protocol-global-stats` or `protocol-fee-stats` metric grids (one `shell-panel` each). - [ ] Daily volume chart (7d default / 30d) inside Global stats; UTC-day copy; missing endpoint hides chart; idle `$0`, unpriced `—`. - [ ] `GET /api/v1/protocol/volume/daily?days=` only `7` \| `30`; else 400. No Llama range dump. Methodology = Protocol catalog, not Llama gem-exclude, unless explicitly labeled (do not silently mix). - [ ] Old indexer (no new keys / no daily route): tiles still render; Δ% em-dash; chart hidden. Charts overview still works. - [ ] Light + dark; 375px: value + Δ% stay one cell; no horizontal overflow from nested cards. - [ ] `aria-label` includes trailing-window / prior-window / UTC-day text so mobile is not hover-only (#576). - [ ] Skills + frontend + indexer-invariants + `make verify-issue-*` for this ticket. `verify-issue-550` / `569` / `586` / `576` / `577` / `631` still pass. ## Test plan (all paths) ### Indexer — volume Δ% - [ ] Seed priced swaps in `now−24h` and `[48h,24h)`: Δ% = `(cur−prior)/prior×100` (fixture parity with `flow_change_pct`). - [ ] Prior window empty or `prior=0` → JSON `null`. - [ ] Current idle (`trades=0`, usd=0) + positive prior → `−100` (or documented equivalent); UI shows `$0` + negative %. - [ ] Current trades>0 and `volume_usd` all null → overview volume `null`, Δ% `null` (not `−100%` from a fake `$0`). - [ ] 7d / 30d same matrix (`[14d,7d)`, `[60d,30d)`). - [ ] `--fresh` / no history → all three `null`. - [ ] Decay (#577): age swaps out of current 24h into prior; totals drop; Δ% updates on refresh, not on GET. - [ ] `OVERVIEW_GLOBAL_STATS_LIVE=1` GET still does **not** 60d-SUM fees or volume priors from `swap_events` (rollup read). EXPLAIN on GET `/overview` and GET daily: no `swap_events`. - [ ] Additive JSON: omit new keys on a unit fixture that mimics old indexer; frontend still renders. ### Indexer — daily series - [ ] `days=7` → ≤7 points; `days=30` → ≤30; `days=1` / `days=90` / `days=` / `days=7%3b` / `days[]=` → **400**. - [ ] UTC midnight boundaries: swap at `23:59Z` vs `00:00Z` land on the correct day. - [ ] Idle closed day → `"0"`; activity+unpriced → `null`; no row yet → omit or `"0"` consistently (document). - [ ] Prune: rows older than 35d gone; GET never walks them. - [ ] Gem / wrap / window swaps: **included** if they are in overview `volume_usd`; do **not** copy Llama exclusions without a label test. - [ ] Cache: two GETs within 60s hit cache; refresh updates after TTL. ### Frontend — layout + Δ% - [ ] RTL: liquidity USD and both Δ% **inside** `protocol-stat-liquidity`; `queryByTestId` standalone 24h/30d **cards** absent; child Δ% testids present. - [ ] Volume 24h cell contains compact USD **and** `%`; 7d/30d same. - [ ] Fees: three tiles; `protocol-stat-fees-24h` contains USD + Δ%; chg testid is a child, not a sibling card. - [ ] Missing / `null` / `"Infinity"` / `"NaN"` / `1e309` → em-dash (existing `formatProtocolPct`). - [ ] XSS: `total_volume_24h_usd` / Δ% / daily point = `"><script>` / `javascript:` render as **text**, not HTML. - [ ] Loading skeletons; overview error → existing `RetryError`; daily error → retry on chart only (do not hide tiles). - [ ] Word count of new visible labels ≤ 5 (`trailingWindowCopy` test). - [ ] Theme: positive/negative Δ% use semantic tokens; gold not a fill. ### Frontend — daily chart - [ ] 7d default; toggle 30d refetches `days=30` only. - [ ] Old indexer 404 / unimplemented → chart not mounted (no `$0` sparkline). - [ ] Empty series / all null → empty state, not a fake axis. - [ ] Does not render `PriceChart` / pair interval chips. - [ ] Keyboard: toggle is a button/tab with visible focus (`--focus-ring`). ### E2E / verify - [ ] `e2e/protocol-page.spec.ts`: page order, one liquidity tile, fee tiles, chart testid when API present. - [ ] `make verify-issue-550` `569` `586` `576` `577` `631` + new verify script. - [ ] Mobile 375 and desktop 1280: no card-in-card ring; Δ% not dropped under the fold as its own tile. ## Test plan (attack, hack, and abuse) - [ ] **DoS / GET amplification.** `days=999999`, negative, array, SQL-looking strings → 400, no scan. Parallel burst of `/overview` + daily stays 60s cache (no per-request 60d `SUM`). - [ ] **Llama coupling.** Client must not hammer `/defillama/daily`. Adding `from`/`to` to Llama in this ticket is a **fail**. - [ ] **Methodology spoof.** Chart must not display Llama gem-excluded volume as if it were Protocol `total_volume_*_usd` without label. - [ ] **Infinity / overflow.** Huge current vs dust prior that overflows `NUMERIC(38,18)` → `null`, not a 1e400 string that breaks UI or JSON. - [ ] **Unpriced → fake dump.** Oracle down must not print `−100%` on a `$0` that is actually unpriced activity. - [ ] **XSS / HTML injection** in USD, %, day labels, SVG/title attributes. - [ ] **Open redirect / ticker.** Chart and stats ignore `?ticker=`; still allowlist oracle chips (**P550-2**). - [ ] **Cache poisoning.** Daily response must not key on unvalidated raw query beyond allowlisted `days`. - [ ] **Dust / wash volume.** Δ% and daily bars use the same swap set as overview (dust counts, same as volume/fees). Do not add unique-trader or “bot filtered” math in v1. - [ ] **Stale rollup.** `updated_at` >15 min: log + serve (**D6**); do not fall back to live 60d scan. - [ ] **Clickjacking / overlay.** Chart is non-interactive (no wallet). No new signing surface. ## Verification criteria - [ ] `make setup-indexer-postgres` then new `make verify-issue-*` (lib + overview + daily integration, `--test-threads=1`). - [ ] `make test-frontend` includes ProtocolPage / StatBox / trailingWindowCopy / formatProtocolStats. - [ ] Playwright e2e-smoke Protocol path green (5 workers; no e2e-tx required). - [ ] Manual: `/protocol` at 375px and 1280px, light + dark — liquidity is one cell (`$…` + `% 24h` + `% 30d`); 24h vol shows a % or em-dash; fees are three tiles; chart 7d/30d; no card-in-card rings in those two panels. - [ ] Docs/skills match the shipped layout (no leftover “24h liquidity box” language). - [ ] Companion anti-nesting issue referenced; this ticket does **not** restyle Charts/Trader/Swap IO cards except `StatBox` API backward compatibility.
PlasticDigits commented 2026-08-26 01:11:05 +00:00 (Migrated from gitlab.com)

mentioned in issue #653

mentioned in issue #653
PlasticDigits commented 2026-08-26 01:11:09 +00:00 (Migrated from gitlab.com)

Companion chrome pass (invariant + Charts/Trader/oracle grids): #653.

Companion chrome pass (invariant + Charts/Trader/oracle grids): #653.
PlasticDigits commented 2026-08-26 01:37:11 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1151

mentioned in merge request !1151
PlasticDigits commented 2026-08-26 01:48:55 +00:00 (Migrated from gitlab.com)

mentioned in commit df236fcc9b

mentioned in commit df236fcc9b9d7a9754e8dc444ad52510cfd27f57
PlasticDigits commented 2026-08-26 01:48:57 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1152

mentioned in merge request !1152
PlasticDigits commented 2026-08-26 01:54:20 +00:00 (Migrated from gitlab.com)

mentioned in commit 640bb28f36

mentioned in commit 640bb28f36f0357c0a2e8e418dadf7892ce55720
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-08-26 01:54:20 +00:00
PlasticDigits commented 2026-08-26 01:57:31 +00:00 (Migrated from gitlab.com)

mentioned in commit 7245ac1c74

mentioned in commit 7245ac1c74fe87eb122ad44ac714839365ba7a09
PlasticDigits commented 2026-08-26 01:58:32 +00:00 (Migrated from gitlab.com)

mentioned in issue #654

mentioned in issue #654
PlasticDigits commented 2026-08-26 01:58:33 +00:00 (Migrated from gitlab.com)

marked as related to #654

marked as related to #654
PlasticDigits commented 2026-08-26 01:58:43 +00:00 (Migrated from gitlab.com)

Merge !1152 is on main (640bb28f). Local make verify-issue-652 was 8/8: docs/source guards, indexer lib (protocol_volume allowlist + flow_change_pct), integration (indexer_protocol_volume + api_overview), Protocol/StatBox/trailing-window RTL, Playwright e2e/protocol-page.spec.ts e2e-smoke (5 workers), plus related verify-issue-550 and verify-issue-586.

Problems / leftovers (tracked on #654 — do not reopen this issue unless a merged invariant is wrong):

  • GitLab CI on !1152 failed ci_quota_exceeded (not a code defect). Did not wait for CI.
  • Coolify has not applied 20260826120000_protocol_volume_change_and_daily.sql yet. Live /overview volume_change_* and /api/v1/protocol/volume/daily are unconfirmed on production.
  • Manual /protocol 375 + 1280, light + dark (one liquidity cell, inline Δ%, no card-in-card, 7d/30d chart) was not run.
  • Standalone verify-issue-569 / 576 / 577 / 631 were not re-run this pass (550 + 586 related path did run).
Merge !1152 is on `main` (`640bb28f`). Local `make verify-issue-652` was 8/8: docs/source guards, indexer lib (`protocol_volume` allowlist + `flow_change_pct`), integration (`indexer_protocol_volume` + `api_overview`), Protocol/StatBox/trailing-window RTL, Playwright `e2e/protocol-page.spec.ts` e2e-smoke (5 workers), plus related `verify-issue-550` and `verify-issue-586`. Problems / leftovers (tracked on #654 — do not reopen this issue unless a merged invariant is wrong): - GitLab CI on !1152 failed `ci_quota_exceeded` (not a code defect). Did not wait for CI. - Coolify has not applied `20260826120000_protocol_volume_change_and_daily.sql` yet. Live `/overview` `volume_change_*` and `/api/v1/protocol/volume/daily` are unconfirmed on production. - Manual `/protocol` 375 + 1280, light + dark (one liquidity cell, inline Δ%, no card-in-card, 7d/30d chart) was not run. - Standalone `verify-issue-569` / `576` / `577` / `631` were not re-run this pass (550 + 586 related path did run).
PlasticDigits commented 2026-08-26 04:17:22 +00:00 (Migrated from gitlab.com)

mentioned in issue #666

mentioned in issue #666
PlasticDigits commented 2026-08-26 04:18:46 +00:00 (Migrated from gitlab.com)

mentioned in issue #667

mentioned in issue #667
PlasticDigits commented 2026-08-26 04:18:46 +00:00 (Migrated from gitlab.com)

marked as related to #667

marked as related to #667
PlasticDigits commented 2026-08-26 04:19:22 +00:00 (Migrated from gitlab.com)

mentioned in issue #668

mentioned in issue #668
PlasticDigits commented 2026-08-26 04:19:22 +00:00 (Migrated from gitlab.com)

marked as related to #668

marked as related to #668
PlasticDigits commented 2026-08-26 06:58:03 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1158

mentioned in merge request !1158
PlasticDigits commented 2026-08-26 07:06:00 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1163

mentioned in merge request !1163
PlasticDigits commented 2026-08-26 07:06:46 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1164

mentioned in merge request !1164
PlasticDigits commented 2026-08-27 00:17:42 +00:00 (Migrated from gitlab.com)

mentioned in issue #677

mentioned in issue #677
PlasticDigits commented 2026-08-27 00:17:43 +00:00 (Migrated from gitlab.com)

marked as related to #677

marked as related to #677
PlasticDigits commented 2026-08-27 09:00:10 +00:00 (Migrated from gitlab.com)

mentioned in issue #689

mentioned in issue #689
PlasticDigits commented 2026-08-27 09:00:11 +00:00 (Migrated from gitlab.com)

marked as related to #689

marked as related to #689
PlasticDigits commented 2026-08-29 08:04:47 +00:00 (Migrated from gitlab.com)

mentioned in issue #703

mentioned in issue #703
PlasticDigits commented 2026-08-29 08:04:49 +00:00 (Migrated from gitlab.com)

marked as related to #703

marked as related to #703
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#652
No description provided.