Skip to content

refactor(dashboard): update metrics for latest leaderboard API#193

Closed
eliteprox wants to merge 51 commits into
mainfrom
feat/metrics-api-update
Closed

refactor(dashboard): update metrics for latest leaderboard API#193
eliteprox wants to merge 51 commits into
mainfrom
feat/metrics-api-update

Conversation

@eliteprox
Copy link
Copy Markdown
Contributor

@eliteprox eliteprox commented Mar 5, 2026

Summary

This PR updates the dashboard stack to align with the latest Livepeer Leaderboard API contract, improves metric correctness/terminology, and tightens dashboard refresh/error behavior for a more reliable UX.

What changed

Leaderboard API/schema changes introduced naming and field-shape drift. This PR brings dashboard contracts and rendering back into sync, reduces ambiguity in GPU/pipeline metrics, and improves user trust during polling/refetch scenarios.

  • Metrics contract alignment

    • Standardized KPI naming from dailyStreamCount to dailySessionCount across schema/provider/UI paths.
    • Updated provider mappings to current leaderboard response fields and terminology.
    • Added/updated orchestrator metric support for effectiveSuccessRate.
  • Pipelines + GPU semantics

    • Updated pipeline presentation to reflect GPU-oriented meaning (labeling/wording updates).
    • Refined pipeline aggregation logic to better represent GPU counts per pipeline/model from SLA-backed data.
  • Dashboard UX and resiliency

    • Improved refresh/loading behavior for dashboard widgets (including stale-data-friendly refresh states).
    • Improved handling and visibility of transient query errors so users get clearer feedback when data may be stale.

Impact

  • User-facing: clearer metric labels, more consistent refresh behavior, better stale/error feedback.
  • Developer-facing: cleaner contract consistency between SDK, provider, and dashboard query consumers.
  • Breaking changes: none intended (contract updates are applied end-to-end in this branch).

Validation

  • Dashboard query paths verified with updated provider field mappings.
  • KPI/orchestrator/pipeline behavior exercised via existing and updated test coverage in affected modules.
  • Build/lint/test checks should be run in CI for final merge gate.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added raw data explorer with detailed network demand, GPU metrics, and SLA compliance queries.
    • Pipeline information now includes region data.
    • Added visual refresh indicators for dashboard updates.
  • Metrics & Data

    • Updated dashboard to display Sessions instead of Streams.
    • Introduced Effective Success Rate metric for orchestrators with dedicated column display.
    • Enhanced performance tracking with expanded health signals and error metrics.
    • Improved job feed polling with customizable intervals.
  • UI Updates

    • Updated metric labels for clarity (e.g., "Startup %" display).
    • Added timeframe selector to dashboard header.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Mar 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
naap-platform Ready Ready Preview, Comment Mar 30, 2026 8:35pm

Request Review

@github-actions github-actions Bot added size/L Large PR (201-500 lines) scope/shell Shell app changes scope/sdk Plugin SDK changes scope/packages Shared package changes labels Mar 5, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 5, 2026

⚠️ This PR is very large (7763 lines changed). Please split it into smaller, focused PRs if possible.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 5, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds raw "explorer" data endpoints and types (networkDemand, gpuMetrics, slaCompliance), renames KPI dailyStreamCount→dailySessionCount, adds orchestrator.effectiveSuccessRate and pipeline.regions, updates leaderboard API shapes and provider wiring, and adjusts dashboard UI polling/refresh behavior and hooks.

Changes

Cohort / File(s) Summary
GraphQL Contracts & Provider Factory
packages/plugin-sdk/src/contracts/dashboard.ts, packages/plugin-sdk/src/contracts/createDashboardProvider.ts, packages/plugin-sdk/src/contracts/__tests__/dashboard.test.ts
Renamed KPI.dailyStreamCount→dailySessionCount; added OrchestratorRow.effectiveSuccessRate and PipelineCatalogEntry.regions; introduced Raw*Row types and filter interfaces; added networkDemand/gpuMetrics/slaCompliance resolvers and rootValue wiring; updated tests/mocks.
Dashboard Data Provider
plugins/dashboard-data-provider/frontend/src/provider.ts, plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts
Transformed provider to emit raw explorer resolvers, compute effectiveSuccessRate, rename metrics (sessions_count/total_minutes), normalize rows, update pipeline/GPU/orchestrator aggregations, and adapt tests to new shapes.
Leaderboard API Layer
plugins/dashboard-data-provider/frontend/src/api/leaderboard.ts
Reworked NetworkDemand/GPUMetric/SLA interfaces (field renames pipeline→pipeline_id, totals→sessions_count/total_minutes, known_sessions→known_sessions_count), added many health/startup/effective fields, added filter interfaces, buildParams helper, and fetch overloads.
Service Gateway Connectors
plugins/service-gateway/connectors/livepeer-leaderboard.json
Added three new connector endpoints: /gpu/metrics, /network/demand, /sla/compliance with rate/timeout/cache settings; minor JSON formatting tweak.
Dashboard UI, Hooks & Streaming
apps/web-next/src/app/(dashboard)/dashboard/page.tsx, apps/web-next/src/hooks/useDashboardQuery.ts, apps/web-next/src/hooks/useJobFeedStream.ts
UI: switched KPI tile to dailySessionCount and added RefreshWrap usage across sections; DashboardHeader/timeframe wiring updated; useDashboardQuery exposes new refreshing flag; useJobFeedStream gains optional pollInterval for periodic re-subscribe and cleanup handling.
Docs & Minor UI
apps/web-next/src/content/docs/guides/dashboard-data-provider.mdx, apps/web-next/src/app/(dashboard)/settings/page.tsx
Documentation updated to reference dailySessionCount; trivial import formatting change in settings page.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client as Dashboard UI
participant GraphQL as Dashboard GraphQL
participant Provider as Dashboard Provider
participant Gateway as Service Gateway
participant Upstream as Leaderboard API
Client->>GraphQL: Query dashboard + raw explorer (timeframe, filters)
GraphQL->>Provider: invoke resolver (kpi/pipelines/networkDemand/gpuMetrics/slaCompliance)
Provider->>Gateway: fetch raw endpoints (/network/demand,/gpu/metrics,/sla/compliance)
Gateway->>Upstream: proxy request to upstream API
Upstream-->>Gateway: return raw rows
Gateway-->>Provider: return raw rows
Provider-->>GraphQL: normalized DashboardData (dailySessionCount, effectiveSuccessRate, regions, raw rows)
GraphQL-->>Client: payload (including refreshed flag/state)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • seanhanca
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: updating dashboard metrics to align with the latest leaderboard API, which is the core objective reflected throughout the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/metrics-api-update

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web-next/src/content/docs/guides/dashboard-data-provider.mdx (1)

59-66: ⚠️ Potential issue | 🟡 Minor

Update KPI docs to include all required fields in the current contract.

The resolver example and KPI type row now use dailySessionCount, but still omit required dailyNetworkFeesEth and timeframeHours.

📝 Proposed doc fix
       return {
         successRate: { value: stats.successRate, delta: stats.successRateDelta },
         orchestratorsOnline: { value: stats.orchCount, delta: stats.orchDelta },
         dailyUsageMins: { value: stats.usageMins, delta: stats.usageDelta },
         dailySessionCount: { value: stats.streams, delta: stats.streamsDelta },
+        dailyNetworkFeesEth: { value: stats.feesEth, delta: stats.feesEthDelta },
+        timeframeHours: 24,
       };
-| `KPI` | `successRate`, `orchestratorsOnline`, `dailyUsageMins`, `dailySessionCount` (all `MetricDelta!`) |
+| `KPI` | `successRate`, `orchestratorsOnline`, `dailyUsageMins`, `dailySessionCount`, `dailyNetworkFeesEth` (`MetricDelta!`), `timeframeHours` (`Int!`) |

Also applies to: 180-180

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web-next/src/content/docs/guides/dashboard-data-provider.mdx` around
lines 59 - 66, The kpi resolver example (kpi: async (args) => { ... }) is
missing required fields from the current KPI contract; update the returned
object to include dailyNetworkFeesEth (e.g., { value: stats.networkFeesEth,
delta: stats.networkFeesDelta }) and timeframeHours (e.g., { value:
stats.timeframeHours }) alongside existing successRate, orchestratorsOnline,
dailyUsageMins, and dailySessionCount so the example matches the KPI
type/contract.
🧹 Nitpick comments (3)
plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts (1)

414-415: Add orchestrator coverage for effectiveSuccessRate.

The provider now emits this field, but the orchestrator integration test does not request/assert it yet.

🧪 Suggested test extension
-      query: '{ orchestrators { address knownSessions successSessions successRatio noSwapRatio slaScore pipelines pipelineModels { pipelineId modelIds } gpuCount } }',
+      query: '{ orchestrators { address knownSessions successSessions successRatio effectiveSuccessRate noSwapRatio slaScore pipelines pipelineModels { pipelineId modelIds } gpuCount } }',
     expect(orchA.successRatio).toBe(100);
+    expect(orchA.effectiveSuccessRate).toBe(100);
     expect(orchA.noSwapRatio).toBe(100);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts`
around lines 414 - 415, The orchestrator test needs to request and assert the
new effectiveSuccessRate field: update the GraphQL query string inside the test
(the one returning orchestrators { ... }) to include effectiveSuccessRate, cast
the response as DashboardQueryResponse as before, and add assertions in the same
test that validate the orchestrator objects include the expected
effectiveSuccessRate values (alongside existing checks for successRatio,
slaScore, etc.) so the provider integration covers the new field.
apps/web-next/src/app/(dashboard)/dashboard/page.tsx (1)

94-95: Consider dropping effectiveSuccessRate from the query until it is used in the UI.

It is currently fetched but not rendered/consumed on this page.

✂️ Optional query trim
-      address knownSessions successSessions successRatio effectiveSuccessRate noSwapRatio slaScore pipelines pipelineModels { pipelineId modelIds } gpuCount
+      address knownSessions successSessions successRatio noSwapRatio slaScore pipelines pipelineModels { pipelineId modelIds } gpuCount
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web-next/src/app/`(dashboard)/dashboard/page.tsx around lines 94 - 95,
The GraphQL query in page.tsx is requesting the field effectiveSuccessRate even
though the page does not use it; remove effectiveSuccessRate from the selection
set in the dashboard query (the line containing "address knownSessions
successSessions successRatio effectiveSuccessRate noSwapRatio slaScore pipelines
pipelineModels { pipelineId modelIds } gpuCount") to avoid unnecessary data
fetching and simplify the query.
packages/plugin-sdk/src/contracts/__tests__/dashboard.test.ts (1)

118-127: Strengthen KPI contract test coverage for required fields.

This test now checks dailySessionCount, but adding assertions for the other required KPI fields would better guard schema drift.

✅ Suggested test additions
     expect(fields).toHaveProperty('successRate');
     expect(fields).toHaveProperty('orchestratorsOnline');
     expect(fields).toHaveProperty('dailyUsageMins');
     expect(fields).toHaveProperty('dailySessionCount');
+    expect(fields).toHaveProperty('dailyNetworkFeesEth');
+    expect(fields).toHaveProperty('timeframeHours');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/plugin-sdk/src/contracts/__tests__/dashboard.test.ts` around lines
118 - 127, The KPI contract test ("KPI type has required MetricDelta fields")
currently asserts only a subset of required fields; update this test to assert
presence of all required KPI MetricDelta fields by adding expect checks for each
missing field using the same pattern (use buildSchema(DASHBOARD_SCHEMA),
getType('KPI') as any, kpiType.getFields() and then
expect(fields).toHaveProperty('<fieldName>') for each required field such as the
ones mentioned plus any others defined in the contract) so the test fails if any
required KPI field is removed or renamed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugins/dashboard-data-provider/frontend/src/provider.ts`:
- Around line 112-119: resolveKPI is still calling trueSuccessRate instead of
the new weightedSuccessRate, causing KPI values to use the legacy computation;
update resolveKPI to call weightedSuccessRate (and any other references at the
second occurrence) so the KPI path uses weightedSuccessRate of
effective_success_rate by known_sessions_count rather than trueSuccessRate.
Ensure you replace references to trueSuccessRate with weightedSuccessRate inside
resolveKPI and the duplicate block noted around the later occurrence.

---

Outside diff comments:
In `@apps/web-next/src/content/docs/guides/dashboard-data-provider.mdx`:
- Around line 59-66: The kpi resolver example (kpi: async (args) => { ... }) is
missing required fields from the current KPI contract; update the returned
object to include dailyNetworkFeesEth (e.g., { value: stats.networkFeesEth,
delta: stats.networkFeesDelta }) and timeframeHours (e.g., { value:
stats.timeframeHours }) alongside existing successRate, orchestratorsOnline,
dailyUsageMins, and dailySessionCount so the example matches the KPI
type/contract.

---

Nitpick comments:
In `@apps/web-next/src/app/`(dashboard)/dashboard/page.tsx:
- Around line 94-95: The GraphQL query in page.tsx is requesting the field
effectiveSuccessRate even though the page does not use it; remove
effectiveSuccessRate from the selection set in the dashboard query (the line
containing "address knownSessions successSessions successRatio
effectiveSuccessRate noSwapRatio slaScore pipelines pipelineModels { pipelineId
modelIds } gpuCount") to avoid unnecessary data fetching and simplify the query.

In `@packages/plugin-sdk/src/contracts/__tests__/dashboard.test.ts`:
- Around line 118-127: The KPI contract test ("KPI type has required MetricDelta
fields") currently asserts only a subset of required fields; update this test to
assert presence of all required KPI MetricDelta fields by adding expect checks
for each missing field using the same pattern (use
buildSchema(DASHBOARD_SCHEMA), getType('KPI') as any, kpiType.getFields() and
then expect(fields).toHaveProperty('<fieldName>') for each required field such
as the ones mentioned plus any others defined in the contract) so the test fails
if any required KPI field is removed or renamed.

In `@plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts`:
- Around line 414-415: The orchestrator test needs to request and assert the new
effectiveSuccessRate field: update the GraphQL query string inside the test (the
one returning orchestrators { ... }) to include effectiveSuccessRate, cast the
response as DashboardQueryResponse as before, and add assertions in the same
test that validate the orchestrator objects include the expected
effectiveSuccessRate values (alongside existing checks for successRatio,
slaScore, etc.) so the provider integration covers the new field.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 22232dfb-c7fe-4d85-af02-2e597f4b0eab

📥 Commits

Reviewing files that changed from the base of the PR and between 8e6f6ef and 777561a.

📒 Files selected for processing (8)
  • apps/web-next/src/app/(dashboard)/dashboard/page.tsx
  • apps/web-next/src/content/docs/guides/dashboard-data-provider.mdx
  • packages/plugin-sdk/src/contracts/__tests__/dashboard.test.ts
  • packages/plugin-sdk/src/contracts/dashboard.ts
  • plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts
  • plugins/dashboard-data-provider/frontend/src/api/leaderboard.ts
  • plugins/dashboard-data-provider/frontend/src/provider.ts
  • plugins/service-gateway/connectors/livepeer-leaderboard.json

Comment thread plugins/dashboard-data-provider/frontend/src/provider.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/web-next/src/app/(dashboard)/dashboard/page.tsx (1)

1223-1227: Wire feesRefreshing into the Fees card UI path.

Line 1223 captures feesRefreshing, but the Fees card branch (Line 1270-Line 1272) renders without RefreshWrap. This makes refresh-state UX inconsistent with the other refreshed cards.

♻️ Suggested patch
-          {feesData?.fees
-            ? <FeesCard data={feesData.fees} />
+          {feesData?.fees
+            ? <RefreshWrap refreshing={feesRefreshing}><FeesCard data={feesData.fees} /></RefreshWrap>
             : feesLoading ? <WidgetSkeleton /> : <WidgetUnavailable label="Fees" />}

Also applies to: 1270-1272

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web-next/src/app/`(dashboard)/dashboard/page.tsx around lines 1223 -
1227, The Fees card branch is not wired to the feesRefreshing state; update the
Fees card render (the component/JSX that displays fees around the "Fees card"
block) to wrap its contents in the same RefreshWrap used by other cards and pass
the feesRefreshing boolean so the UI shows the refresh spinner/state;
specifically, use the feesRefreshing value returned from useDashboardQuery
(FEES_OVERVIEW_QUERY) and wrap the Fees card JSX with <RefreshWrap
refreshing={feesRefreshing}> (or the project's equivalent RefreshWrap usage
found on other cards) so the Fees card matches the other refreshed cards'
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web-next/src/hooks/useDashboardQuery.ts`:
- Around line 45-46: The JSDoc for the loading property in useDashboardQuery is
misleading — update the comment where "loading: boolean" is declared/returned so
it states that loading is true for any in-flight request (initial fetch,
polling, or refetch), not just the very first fetch; locate the declaration
returned by useDashboardQuery and replace the description to explicitly mention
initial and subsequent requests (e.g., "true while any fetch is in progress
(initial load, refetch, or polling)").

In `@plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts`:
- Around line 53-70: STUB_DEMAND_2H is missing the required model_id property
for the NetworkDemandRow objects; update every object inside STUB_DEMAND_2H to
include a model_id field (set to the appropriate model identifier for that
entry—e.g., same value as pipeline_id or the canonical model string used
elsewhere) so each entry conforms to the NetworkDemandRow type.
- Around line 32-50: STUB_DEMAND_1H entries are missing the model_id required by
the NetworkDemandRow interface; update each object in STUB_DEMAND_1H to include
the model_id property (e.g., model_id: null or the appropriate string
identifier) so the test stub matches the interface contract and covers model_id
handling in the provider code.

---

Nitpick comments:
In `@apps/web-next/src/app/`(dashboard)/dashboard/page.tsx:
- Around line 1223-1227: The Fees card branch is not wired to the feesRefreshing
state; update the Fees card render (the component/JSX that displays fees around
the "Fees card" block) to wrap its contents in the same RefreshWrap used by
other cards and pass the feesRefreshing boolean so the UI shows the refresh
spinner/state; specifically, use the feesRefreshing value returned from
useDashboardQuery (FEES_OVERVIEW_QUERY) and wrap the Fees card JSX with
<RefreshWrap refreshing={feesRefreshing}> (or the project's equivalent
RefreshWrap usage found on other cards) so the Fees card matches the other
refreshed cards' behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ff8e1185-4516-4a31-98af-bb422da57689

📥 Commits

Reviewing files that changed from the base of the PR and between 777561a and 77fc812.

📒 Files selected for processing (3)
  • apps/web-next/src/app/(dashboard)/dashboard/page.tsx
  • apps/web-next/src/hooks/useDashboardQuery.ts
  • plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts

Comment thread apps/web-next/src/hooks/useDashboardQuery.ts Outdated
Comment thread plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts Outdated
Comment thread plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts Outdated
@eliteprox eliteprox changed the title refactor(dashboard): rename dailyStreamCount to dailySessionCount across the codebase refactor(dashboard): update metrics for latest leaderboard API changes Mar 5, 2026
Copy link
Copy Markdown
Contributor

@qianghan qianghan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — PR #193

Overview

Good work on renaming dailyStreamCountdailySessionCount, adding effectiveSuccessRate as a new orchestrator metric, updating API interfaces for the latest leaderboard schema, and introducing the RefreshWrap component for a smoother polling UX. CI is all green.

However, there are 2 critical bugs and 3 major issues that need to be addressed before merge.


Critical

# Issue File
1 weightedSuccessRate is dead code — KPI still uses legacy trueSuccessRate provider.ts
2 setData(null) on poll errors wipes stale data, defeating RefreshWrap useDashboardQuery.ts

Major

# Issue File
3 loading JSDoc is inaccurate — says "first fetch" but fires on every fetch useDashboardQuery.ts
4 No error UI for timeout/unknown errors — users see blank widgets with no explanation dashboard/page.tsx
5 Missing model_id field in STUB_DEMAND_1H and STUB_DEMAND_2H test data provider.test.ts

See inline comments for details and requested changes.

Comment thread plugins/dashboard-data-provider/frontend/src/provider.ts Outdated
Comment thread apps/web-next/src/hooks/useDashboardQuery.ts
Comment thread apps/web-next/src/hooks/useDashboardQuery.ts
Comment thread apps/web-next/src/app/(dashboard)/dashboard/page.tsx Outdated
Comment thread plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

♻️ Duplicate comments (1)
plugins/dashboard-data-provider/frontend/src/provider.ts (1)

119-125: ⚠️ Potential issue | 🟠 Major

KPI success rate is still weighted off the wrong field.

weightedSuccessRatio() now drives the KPI on Lines 173-174, but this helper still multiplies startup_success_rate. That keeps the headline tile on the startup metric instead of the API’s effective_success_rate, which is what the contract/comment now advertise.

Suggested fix
-function weightedSuccessRatio(rows: Array<{ startup_success_rate: number; known_sessions_count: number }>): number {
+function weightedSuccessRatio(rows: Array<{ effective_success_rate: number; known_sessions_count: number }>): number {
   const totalSessions = rows.reduce((s, r) => s + r.known_sessions_count, 0);
   if (totalSessions === 0) return 0;
-  return rows.reduce((s, r) => s + r.startup_success_rate * r.known_sessions_count, 0) / totalSessions;
+  return rows.reduce((s, r) => s + r.effective_success_rate * r.known_sessions_count, 0) / totalSessions;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/dashboard-data-provider/frontend/src/provider.ts` around lines 119 -
125, The helper weightedSuccessRatio is still using startup_success_rate even
though the KPI should use effective_success_rate; update the function signature
and usages in weightedSuccessRatio to accept rows with effective_success_rate
(e.g., change the param type to { effective_success_rate: number;
known_sessions_count: number }) and replace occurrences of
r.startup_success_rate with r.effective_success_rate so the weighted average is
computed against the API's effective_success_rate field.
🧹 Nitpick comments (2)
plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts (1)

313-341: Please add integration coverage for the new raw explorer fields.

These tests now cover dailySessionCount and effectiveSuccessRate, but they still never query networkDemand, gpuMetrics, slaCompliance, or pipelineCatalog.regions. That leaves the new camelCase transforms and filter plumbing in plugins/dashboard-data-provider/frontend/src/provider.ts unguarded.

Also applies to: 429-470

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts`
around lines 313 - 341, The test is missing assertions for the new raw explorer
fields; update the DashboardQueryRequest (the `request` query string in
provider.test.ts) to include networkDemand, gpuMetrics, slaCompliance, and
pipelineCatalog { regions } (or pipelineCatalog.regions) in the GraphQL query,
then after invoking `testEventBus._invoke(DASHBOARD_QUERY_EVENT, request)`
assert those fields exist on `response.data` and validate basic types/shape
(e.g., numbers or arrays/objects) similar to the existing KPI checks; reference
the test identifiers `request`, `DASHBOARD_QUERY_EVENT`, `testEventBus._invoke`,
and `DashboardQueryResponse` when locating where to add the new query selections
and corresponding expect(...) assertions.
examples/network-analytics/frontend/src/pages/RawExplorer.tsx (1)

1147-1162: Avoid fetching all raw datasets for every tab.

The page always issues SLA, GPU, and demand queries, plus three copies of pipelineCatalog, even when a single tab is visible. On larger result sets that will add a lot of unnecessary load and makes the 8s timeout in useDashboardQuery() much easier to hit. An enabled flag per query, plus a small standalone catalog query, would keep this much cheaper.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/network-analytics/frontend/src/pages/RawExplorer.tsx` around lines
1147 - 1162, Currently SLA_QUERY, GPU_QUERY, and DEMAND_QUERY are all executed
every render (via useDashboardQuery for slaVars/gpuVars/demandVars) and their
pipelineCatalog fields are merged into catalog; change each useDashboardQuery
call to accept an enabled flag that is true only when its corresponding tab is
active (e.g. when activeTab === 'sla' enable SLA_QUERY), and create a small
standalone pipelineCatalog query (e.g. PIPELINE_CATALOG_QUERY) using
useDashboardQuery(enabled: true) to fetch only the catalog for use across tabs;
update the catalog assignment to use the standalone catalog result instead of
slaData?.pipelineCatalog ?? gpuData?.pipelineCatalog ??
demandData?.pipelineCatalog and remove unnecessary query executions when tabs
are not visible.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web-next/src/app/`(dashboard)/dashboard/page.tsx:
- Around line 1219-1225: The state initializer is reading localStorage during
render (via getStoredJobFeedPollInterval), causing a server/client hydration
mismatch; change to initialize jobFeedPollInterval (and similarly timeframe)
with the SSR-safe defaults (e.g., DEFAULT_POLL_INTERVAL/DEFAULT_TIMEFRAME) and
move the localStorage reads into a useEffect that runs on mount which calls
getStoredJobFeedPollInterval/getStoredTimeframe and then calls
setJobFeedPollInterval/setTimeframe to update state and persist any derived
values; keep handleJobFeedPollIntervalChange as-is for writes.

In `@apps/web-next/src/hooks/useJobFeedStream.ts`:
- Around line 127-139: The timer path tears down the active event listener
before establishing the replacement; instead, avoid calling cleanupRef.current
until the new subscription is confirmed: when the poll timer fires, capture the
old cleanup (const oldCleanup = cleanupRef.current), then call connect() and
wait for it to successfully create/return the new cleanup (or have connect
accept a callback/promise to signal success), only after the new cleanup is set
on cleanupRef.current call oldCleanup(); ensure pollTimerRef/mountedRef logic
remains but never null out cleanupRef before the swap. Reference symbols:
pollTimerRef, cleanupRef, connect, eventBusCleanup, pollIntervalMs, mountedRef.

In `@examples/network-analytics/frontend/src/pages/RawExplorer.tsx`:
- Around line 1064-1114: The component currently seeds dataset/filters/period
once (initialDataset/initialFilters/initialPeriod) so URL changes/back-forward
can desync and an invalid exp_ds can later crash DATASET_CONFIG[dataset]; fix by
deriving state from searchParams on change: replace the one-time initial_* usage
with a useEffect that reads parseFiltersFromParams(searchParams), validates the
dataset string against DATASET_CONFIG keys, and calls
setDataset/setFilters/setPeriod when searchParams changes; also add a runtime
guard where DATASET_CONFIG[dataset] is accessed (or default to a safe dataset)
to avoid exceptions if an invalid dataset slips through.
- Around line 1125-1136: gpuTimeRange currently collapses every non-'1h' period
to '24h', causing hardware/models tabs to misrepresent selected periods; update
the logic in RawExplorer.tsx where gpuTimeRange and gpuVars are defined to
either (A) pass the selected period through (set gpuTimeRange = period) so
gpuVars.timeRange reflects the actual picker value, or (B) explicitly map
allowed picker values to supported GPU ranges (e.g., map
'1h'→'1h','6h'→'6h','24h'→'24h','72h'→'72h') and ensure the UI picker is
restricted to those supported values; change the gpuTimeRange computation and
ensure gpuVars.timeRange uses that updated value so hardware and models tabs
display the correct range.
- Around line 991-1005: The current logic only sets an error when
response.errors exists AND response.data is falsy, which hides partial GraphQL
failures (e.g., main field failed but pipelineCatalog succeeded); update the
conditional around setState in RawExplorer.tsx so that whenever response.errors
&& response.errors.length > 0 you populate the error object (using
response.errors.map(e=>e.message).join('; ')) while still preserving
response.data into setState.data (cast to T) instead of clearing it; only set
error: null when there are no response.errors. Ensure you modify the branches
that call setState (the ones referencing response.errors, response.data, and
pipelineCatalog) so partial data + errors are represented.
- Around line 435-438: The SLA score is being multiplied by 100 again when
rendering, causing values like 10000; in RawExplorer.tsx update the rendering of
row.slaScore (from RawSLAComplianceRow) to stop scaling it — remove the
multiplication by 100 and simply format the existing percentage-style value
(e.g., keep toFixed(0) or use formatPercent if you want consistent formatting)
so a perfect score remains 100 instead of 10000.

In `@examples/network-analytics/frontend/tailwind.config.js`:
- Line 3: The Tailwind darkMode is configured as ['class'] but the app never
toggles the .dark class so dark styles in
examples/network-analytics/frontend/src/globals.css (defined under .dark) never
apply; add a small bootstrap that reads the user preference or stored choice and
sets document.documentElement.classList.toggle('dark', ...) on initial load
(same approach used in apps/web-next/src/app/layout.tsx) and wire up any theme
toggle UI to update that class and persist the choice.

In `@examples/network-analytics/plugin.json`:
- Around line 25-28: The PLUGIN_ROUTE_MAP still contains the stale mapping
'/leaderboard': 'networkAnalytics' which no longer exists in the plugin.json
routes; open the PLUGIN_ROUTE_MAP constant (symbol name PLUGIN_ROUTE_MAP) and
remove the '/leaderboard' and '/leaderboard/*' entries (or alternately add the
missing routes back into the plugin's WorkflowPlugin.routes) so the hardcoded
route map matches the plugin.json routes and the middleware rewrite logic is
consistent.

---

Duplicate comments:
In `@plugins/dashboard-data-provider/frontend/src/provider.ts`:
- Around line 119-125: The helper weightedSuccessRatio is still using
startup_success_rate even though the KPI should use effective_success_rate;
update the function signature and usages in weightedSuccessRatio to accept rows
with effective_success_rate (e.g., change the param type to {
effective_success_rate: number; known_sessions_count: number }) and replace
occurrences of r.startup_success_rate with r.effective_success_rate so the
weighted average is computed against the API's effective_success_rate field.

---

Nitpick comments:
In `@examples/network-analytics/frontend/src/pages/RawExplorer.tsx`:
- Around line 1147-1162: Currently SLA_QUERY, GPU_QUERY, and DEMAND_QUERY are
all executed every render (via useDashboardQuery for slaVars/gpuVars/demandVars)
and their pipelineCatalog fields are merged into catalog; change each
useDashboardQuery call to accept an enabled flag that is true only when its
corresponding tab is active (e.g. when activeTab === 'sla' enable SLA_QUERY),
and create a small standalone pipelineCatalog query (e.g.
PIPELINE_CATALOG_QUERY) using useDashboardQuery(enabled: true) to fetch only the
catalog for use across tabs; update the catalog assignment to use the standalone
catalog result instead of slaData?.pipelineCatalog ?? gpuData?.pipelineCatalog
?? demandData?.pipelineCatalog and remove unnecessary query executions when tabs
are not visible.

In `@plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts`:
- Around line 313-341: The test is missing assertions for the new raw explorer
fields; update the DashboardQueryRequest (the `request` query string in
provider.test.ts) to include networkDemand, gpuMetrics, slaCompliance, and
pipelineCatalog { regions } (or pipelineCatalog.regions) in the GraphQL query,
then after invoking `testEventBus._invoke(DASHBOARD_QUERY_EVENT, request)`
assert those fields exist on `response.data` and validate basic types/shape
(e.g., numbers or arrays/objects) similar to the existing KPI checks; reference
the test identifiers `request`, `DASHBOARD_QUERY_EVENT`, `testEventBus._invoke`,
and `DashboardQueryResponse` when locating where to add the new query selections
and corresponding expect(...) assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 52b2d951-6c8e-42c7-b9c6-495943fd1ba4

📥 Commits

Reviewing files that changed from the base of the PR and between 77fc812 and dd9f0c3.

📒 Files selected for processing (16)
  • apps/web-next/src/app/(dashboard)/dashboard/page.tsx
  • apps/web-next/src/app/(dashboard)/settings/page.tsx
  • apps/web-next/src/hooks/useDashboardQuery.ts
  • apps/web-next/src/hooks/useJobFeedStream.ts
  • examples/network-analytics/frontend/src/App.tsx
  • examples/network-analytics/frontend/src/globals.css
  • examples/network-analytics/frontend/src/pages/Analytics.tsx
  • examples/network-analytics/frontend/src/pages/Leaderboard.tsx
  • examples/network-analytics/frontend/src/pages/RawExplorer.tsx
  • examples/network-analytics/frontend/tailwind.config.js
  • examples/network-analytics/plugin.json
  • packages/plugin-sdk/src/contracts/createDashboardProvider.ts
  • packages/plugin-sdk/src/contracts/dashboard.ts
  • plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts
  • plugins/dashboard-data-provider/frontend/src/api/leaderboard.ts
  • plugins/dashboard-data-provider/frontend/src/provider.ts
💤 Files with no reviewable changes (2)
  • examples/network-analytics/frontend/src/pages/Analytics.tsx
  • examples/network-analytics/frontend/src/pages/Leaderboard.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/web-next/src/app/(dashboard)/settings/page.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web-next/src/hooks/useDashboardQuery.ts

Comment thread apps/web-next/src/app/(dashboard)/dashboard/page.tsx Outdated
Comment thread apps/web-next/src/hooks/useJobFeedStream.ts Outdated
Comment thread examples/network-analytics/frontend/src/pages/RawExplorer.tsx Outdated
Comment thread examples/network-analytics/frontend/src/pages/RawExplorer.tsx Outdated
Comment thread examples/network-analytics/frontend/src/pages/RawExplorer.tsx Outdated
Comment thread examples/network-analytics/frontend/src/pages/RawExplorer.tsx Outdated
Comment thread examples/network-analytics/frontend/tailwind.config.js Outdated
Comment thread examples/network-analytics/plugin.json Outdated
@eliteprox eliteprox changed the title refactor(dashboard): update metrics for latest leaderboard API changes refactor(dashboard): update metrics for latest leaderboard API Mar 11, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/web-next/src/app/(dashboard)/dashboard/page.tsx (1)

1219-1220: ⚠️ Potential issue | 🟡 Minor

Hydration mismatch: localStorage read in useState initializer.

Both getStoredJobFeedPollInterval and getStoredTimeframe read from localStorage during the initial render. In Next.js App Router, this causes server/client mismatches since the server renders with defaults while the client may have stored values.

This was flagged in a previous review and appears unresolved. The fix is to initialize with defaults and sync from localStorage in a useEffect.

Hydration-safe pattern
-  const [jobFeedPollInterval, setJobFeedPollInterval] = useState(getStoredJobFeedPollInterval);
-  const [timeframe, setTimeframe] = useState(getStoredTimeframe);
+  const [jobFeedPollInterval, setJobFeedPollInterval] = useState(DEFAULT_POLL_INTERVAL);
+  const [timeframe, setTimeframe] = useState(DEFAULT_TIMEFRAME);
+
+  useEffect(() => {
+    setJobFeedPollInterval(getStoredJobFeedPollInterval());
+    setTimeframe(getStoredTimeframe());
+  }, []);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web-next/src/app/`(dashboard)/dashboard/page.tsx around lines 1219 -
1220, The current useState initializers call getStoredJobFeedPollInterval and
getStoredTimeframe which read localStorage during render and cause hydration
mismatches; change both useState calls to initialize with safe defaults (e.g.,
the server-side fallback value) and then inside a useEffect (guarded by typeof
window !== 'undefined') read localStorage via getStoredJobFeedPollInterval and
getStoredTimeframe and call setJobFeedPollInterval and setTimeframe to sync the
client values; keep the same state variable names (jobFeedPollInterval,
timeframe) and helper functions so the diff is minimal.
🧹 Nitpick comments (1)
plugins/dashboard-data-provider/frontend/src/provider.ts (1)

256-259: Field mins now holds GPU count, not minutes.

The mins field in the returned DashboardPipelineUsage objects now contains GPU counts (line 258: mins: acc.total) rather than minutes. While the UI has been updated to display "GPUs", consumers of this API might be confused by the field name.

Consider renaming the field in a future refactor, or at minimum document this semantic change in the type definition.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/dashboard-data-provider/frontend/src/provider.ts` around lines 256 -
259, The mapping that builds DashboardPipelineUsage objects currently sets mins:
acc.total but acc.total now represents GPU count, causing a semantic mismatch;
update the mapping in the function that returns these objects (the
.map(([pipelineId, acc]) => ({ ... })) using PIPELINE_DISPLAY, PIPELINE_COLOR,
DEFAULT_PIPELINE_COLOR) to include a new explicit field like gpus: acc.total and
preserve mins for backward compatibility (or update the type
DashboardPipelineUsage to reflect the new semantics), and add a short comment
documenting the change in the type definition so consumers know mins now
represents GPUs or can migrate to gpus.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugins/dashboard-data-provider/frontend/src/provider.ts`:
- Around line 118-126: The comment for weightedSuccessRatio and its
implementation disagree: the function currently computes a weighted average
using the startup_success_rate property but the docstring mentions
effective_success_rate; decide which KPI is correct and make them consistent by
either changing the comment to say "Weighted average of startup_success_rate by
known_sessions_count" or updating the implementation and the rows type to use
effective_success_rate instead of startup_success_rate (update occurrences of
startup_success_rate in the function signature and reduce callbacks to
effective_success_rate if you choose that path).

---

Duplicate comments:
In `@apps/web-next/src/app/`(dashboard)/dashboard/page.tsx:
- Around line 1219-1220: The current useState initializers call
getStoredJobFeedPollInterval and getStoredTimeframe which read localStorage
during render and cause hydration mismatches; change both useState calls to
initialize with safe defaults (e.g., the server-side fallback value) and then
inside a useEffect (guarded by typeof window !== 'undefined') read localStorage
via getStoredJobFeedPollInterval and getStoredTimeframe and call
setJobFeedPollInterval and setTimeframe to sync the client values; keep the same
state variable names (jobFeedPollInterval, timeframe) and helper functions so
the diff is minimal.

---

Nitpick comments:
In `@plugins/dashboard-data-provider/frontend/src/provider.ts`:
- Around line 256-259: The mapping that builds DashboardPipelineUsage objects
currently sets mins: acc.total but acc.total now represents GPU count, causing a
semantic mismatch; update the mapping in the function that returns these objects
(the .map(([pipelineId, acc]) => ({ ... })) using PIPELINE_DISPLAY,
PIPELINE_COLOR, DEFAULT_PIPELINE_COLOR) to include a new explicit field like
gpus: acc.total and preserve mins for backward compatibility (or update the type
DashboardPipelineUsage to reflect the new semantics), and add a short comment
documenting the change in the type definition so consumers know mins now
represents GPUs or can migrate to gpus.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c5ca464d-43d4-41fd-98e9-6ffd7761d35a

📥 Commits

Reviewing files that changed from the base of the PR and between dd9f0c3 and 2fbe8e1.

📒 Files selected for processing (3)
  • apps/web-next/src/app/(dashboard)/dashboard/page.tsx
  • plugins/dashboard-data-provider/frontend/src/__tests__/provider.test.ts
  • plugins/dashboard-data-provider/frontend/src/provider.ts

Comment thread plugins/dashboard-data-provider/frontend/src/provider.ts Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 26, 2026
@eliteprox eliteprox requested a review from qianghan March 26, 2026 01:02
- Updated comments and documentation for clarity on cache warming and timeout settings in the dashboard.
- Adjusted TTL settings for various endpoints to ensure consistency and improve cache management.
- Enhanced GraphQL query timeout documentation to reflect changes in client-side handling and upstream fetch behavior.
- Improved clarity in the raw data handling and KPI resolution logic to align with updated caching strategies.
…ents

- Updated the layout of ProtocolCard, FeesCard, and GPUCapacityCard to use flexbox for better responsiveness and alignment.
- Adjusted the minimum height and flex properties of various elements to ensure consistent sizing and appearance.
- Improved the table header component in OrchestratorTableCard by allowing additional class names for better styling flexibility.
- Enhanced the RefreshWrap component usage to maintain consistent height and layout across different dashboard sections.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 27, 2026
… configuration

- Refactored leaderboard API integration to utilize a new utility for constructing upstream URLs, enhancing maintainability.
- Updated environment variable references in `.env.example` and `.env.local.example` to clarify usage and requirements for `LEADERBOARD_API_URL`.
- Adjusted various components to ensure they correctly reference the new leaderboard API structure, including updates to the service gateway and dashboard data provider.
- Improved documentation for environment variables and their expected formats in the README files.
- Add `callConnectorInternal` function to facilitate server-side calls to published connectors without going through the external gateway.
- Introduce tests for the internal client to ensure proper functionality and error handling.
- Update leaderboard and ClickHouse configurations to support new internal calling mechanism.
- Modify existing seed scripts and environment variable handling to align with new API structure.
- Refactor endpoint paths to remove unnecessary prefixes and ensure consistency across connectors.
- Added a new seed script for public connectors that reads from JSON templates and upserts them into the database.
- Integrated the seeding process into the main Prisma seed file.
- Updated the internal client to handle connector calls more robustly.
- Refactored the leaderboard and ClickHouse connector handling.
- Improved test setup for server-only modules.
- Removed the old public connector seeding logic from the start script.
@eliteprox
Copy link
Copy Markdown
Contributor Author

closing in favor of #224

@eliteprox eliteprox closed this Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plugin/developer-api Developer API plugin scope/infra Infrastructure changes scope/packages Shared package changes scope/sdk Plugin SDK changes scope/shell Shell app changes size/XL Extra large PR (500+ lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(developer-api): List models available on the network

4 participants