Skip to content

feat(dashboard): consume recent_events + chain_meta from authoritative endpoint#35

Merged
hizrianraz merged 1 commit into
mainfrom
feat/dashboard-consume-recent-events
May 16, 2026
Merged

feat(dashboard): consume recent_events + chain_meta from authoritative endpoint#35
hizrianraz merged 1 commit into
mainfrom
feat/dashboard-consume-recent-events

Conversation

@hizrianraz
Copy link
Copy Markdown
Contributor

@hizrianraz hizrianraz commented May 16, 2026

Summary

Wires the dashboard sub-widgets to the new fields on
`/v1/users/{handle}/dashboard` (api PR #14 — required to land first).
After this lands + api deploys, the three sub-widgets that render empty
post-D3 (Recent activity widget, bottom Audit chain mini-widget,
`/audit` page metric chips) all populate from one authoritative
round-trip. The public-feed scrape becomes a fallback path, not the
source of truth.

Files

file change
`apps/dashboard/lib/ainfera/types.ts` Adds `RecentAuditEvent` + `ChainMeta` types. `UserDashboardResponse` gets two optional fields (back-compat with older api deploys).
`apps/dashboard/app/(tenant)/dashboard/page.tsx` `composeSnapshot` overrides `recentEvents` with owner-scoped `fleet.recent_events` when present; overrides `chainHeight` with `owner_chain_height` → `global_chain_height` → feed-derived fallback.
`apps/dashboard/app/(tenant)/audit/page.tsx` SSR-fetches `/v1/users/{handle}/dashboard.chain_meta` and passes `initialChainHeight + initialLatestAt` to AuditPageClient.
`apps/dashboard/app/(tenant)/audit/AuditPageClient.tsx` Accepts the two new props (back-compat defaulted to `null`). Seeds `useState` from them so the SSR value persists until the client poll backfills.

Dependency

Requires api PR #14 to merge + Railway-deploy first.
Until then, this PR is back-compat safe — the new fields are optional
and the frontend falls back to the existing public-feed reduce when
they're absent. So merging this before api PR #14 is non-breaking.

Reference

  • Audit doc Part 5.2 ("/dashboard rewrite spec" + Principle 1)
  • D3 receipt (defensive boundary kept; this PR fills it with real data)

Note

Low Risk
Low risk UI/data-wiring change that only affects dashboard/audit rendering; main risk is incorrect empty-state or stale display if the new optional API fields are missing or shaped unexpectedly.

Overview
Improves first-paint correctness for audit/overview widgets by consuming the authenticated /v1/users/{handle}/dashboard response as the authoritative source for recent activity and chain height.

The /audit page now SSR-fetches chain_meta via proxyGet and seeds AuditPageClient state with initialChainHeight/initialLatestAt so the metric chips don’t render as "—" while the client poll catches up. The overview snapshot composition prefers recent_events and chain_meta (owner → global → public-feed fallback) when present, and apps/dashboard/lib/ainfera/types.ts adds the corresponding optional response types for back-compat with older API deploys.

Reviewed by Cursor Bugbot for commit 57f701c. Bugbot is set up for automated code reviews on this repo. Configure here.

…e endpoint

Wires the dashboard sub-widgets to the new fields on
/v1/users/{handle}/dashboard (api PR #14):

  composeSnapshot in app/(tenant)/dashboard/page.tsx
    - overrides recentEvents with owner-scoped fleet.recent_events
      when present; falls back to the public-feed-derived value on
      older api deploys (back-compat via optional types).
    - overrides chainHeight with fleet.chain_meta.owner_chain_height,
      else global_chain_height, else fromFeed.chainHeight.

  app/(tenant)/audit/page.tsx
    - SSR-fetches /v1/users/{handle}/dashboard.chain_meta and passes
      initialChainHeight + initialLatestAt to AuditPageClient so the
      chips render on first paint (not "—" until client poll fires).

  AuditPageClient
    - accepts initialChainHeight + initialLatestAt props (back-compat
      defaulted to null).
    - seeds useState from those props so the SSR value persists until
      the client poll backfills.

Net effect: the three sub-widgets that were rendering empty post-D3
(Recent activity widget, bottom Audit chain mini-widget, /audit page
metric chips) all populate from one authoritative round-trip. The
public-feed scrape is now a fallback path, not the source of truth.

Resolves the "one viewport = one truth" violation flagged in the
deep-audit doc Part 5.2 + Principle 1.

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 16, 2026

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

Project Deployment Actions Updated (UTC)
ainfera-dashboard Ready Ready Preview, Comment May 16, 2026 4:06pm
ainfera-marketing Ready Ready Preview, Comment May 16, 2026 4:06pm
web Error Error May 16, 2026 4:06pm

Request Review

@supabase
Copy link
Copy Markdown

supabase Bot commented May 16, 2026

This pull request has been ignored for the connected project dftfpwzqxoebwzepygzl because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@hizrianraz hizrianraz merged commit 2408310 into main May 16, 2026
7 of 8 checks passed
@hizrianraz hizrianraz deleted the feat/dashboard-consume-recent-events branch May 16, 2026 16:08
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit 57f701c. Configure here.

initialChainHeight =
data.chain_meta.owner_chain_height ||
data.chain_meta.global_chain_height ||
null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SSR seeds owner-scoped height, client poll overwrites with global

Medium Severity

The SSR seeds initialChainHeight preferring owner_chain_height (the owner's event count), and initialLatestAt from the owner's latest_event_at. However, the client poll in AuditPageClient unconditionally overwrites both with global values from /v1/audit/publicd.chain_height is the global chain height, and first.created_at is the global latest event timestamp. This causes the chips to flash from owner-scoped values to global values on first poll, changing semantic meaning mid-render.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 57f701c. Configure here.

recentEventsAuthoritative.length > 0
? recentEventsAuthoritative
: fromFeed.recentEvents,
chainHeight: chainHeightForChip,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Client poll overwrites authoritative recentEvents with public-feed data

High Severity

The SSR now computes authoritative, owner-scoped recentEvents and chainHeight via the authenticated endpoint, but the client poll in OverviewView.tsx spreads ...next from reduceOverview (public-feed data) and only preserves agentCount, inferencesInRange, receiptsInRange, and agents. Within ~5 seconds the authoritative recentEvents and chainHeight are silently replaced by public-feed-derived values. When the public feed is drowned by other tenants' high-volume test runs, the Recent Activity widget re-empties — the exact P0 scenario this PR intends to fix, but only for the first paint.

Fix in Cursor Fix in Web

Triggered by learned rule: Use proxyGet with /v1/users/{handle}/dashboard for fleet/stats — not /v1/audit/public

Reviewed by Cursor Bugbot for commit 57f701c. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant