Skip to content

fix(dashboard): project-scope Command Center and Reliability analytics#1971

Merged
gsxdsm merged 1 commit into
Runfusion:mainfrom
Automata-intelligentsia:fux-037-command-center-project-scoping
Jul 9, 2026
Merged

fix(dashboard): project-scope Command Center and Reliability analytics#1971
gsxdsm merged 1 commit into
Runfusion:mainfrom
Automata-intelligentsia:fux-037-command-center-project-scoping

Conversation

@Automata-intelligentsia

@Automata-intelligentsia Automata-intelligentsia commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Problem

Command Center and Reliability analytics were not scoped by projectId, causing multi-project dashboards to blend data across projects.

Change

Pipe projectId through Command Center, Mission Control, and the Reliability view, and use the scoped store resolver so analytics reflect the currently selected project.

Scope

  • ReliabilityView reads and passes projectId.
  • CommandCenter uses projectId for area queries.
  • MissionControlPanel forwards projectId to child widgets.
  • Area components (Signals, Tokens, Workflow, etc.) use projectId where needed.
  • Legacy API helper routes projectId correctly.
  • Tests updated to assert per-project scoping.

Notes

This is the FUX-037 fix. v0.57.0 introduced scoped-store helpers elsewhere but did not project-scope the dashboard analytics surfaces.

Summary by CodeRabbit

  • New Features

    • Command Center and Reliability views can now be scoped to a specific project, so charts, live snapshots, and reset actions reflect the selected project’s data.
    • Analytics areas such as Tokens, Tools, Activity, Productivity, Ecosystem, GitHub, GitLab, Signals, Workflow, and Team now support project-specific results.
  • Bug Fixes

    • Dashboard requests now consistently preserve project selection across refreshes and tab changes, improving data accuracy when switching between projects.

Apply FUX-037 projectId scoping to Command Center and Reliability view.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR threads an optional projectId through the dashboard's Command Center and Reliability views. The legacy withProjectId helper is exported, and analytics fetches, live snapshots, and reliability endpoints are scoped by project across components, hooks, and tests.

Changes

Project-scoped Command Center analytics

Layer / File(s) Summary
Shared API helper and analytics hook
packages/dashboard/app/api/legacy.ts, packages/dashboard/app/components/command-center/areas/useAnalyticsArea.ts
withProjectId becomes exported; useAnalyticsArea gains an optional projectId option and wraps request URLs with withProjectId before fetching.
Area components
.../areas/ActivityArea.tsx, EcosystemArea.tsx, GithubArea.tsx, GitlabArea.tsx, ProductivityArea.tsx, SignalsArea.tsx, TeamArea.tsx, TokensArea.tsx, ToolsArea.tsx, WorkflowArea.tsx, .../areas/__tests__/*
Each analytics area accepts an optional projectId prop forwarded into useAnalyticsArea; tests mock withProjectId and assert requests include/omit the query param accordingly.
ReliabilityView migration to shared API
ReliabilityView.tsx, __tests__/ReliabilityView.test.tsx
ReliabilityView accepts projectId, replaces raw fetch with api/withProjectId-scoped calls for load and reset actions; tests switch from mocking fetch to mocking the shared api client.
MissionControlPanel live snapshot
MissionControlPanel.tsx, __tests__/MissionControlPanel.test.tsx
useLiveSnapshot and MissionControlPanel accept optional projectId, scoping the /command-center/live fetch; tests verify request URL changes when projectId is added.
SdlcFunnel scoping
SdlcFunnel.tsx, __tests__/SdlcFunnel.test.tsx
SdlcFunnel accepts projectId and forwards it to the activity analytics hook; tests verify inclusion/omission.
CommandCenter wiring
CommandCenter.tsx, __tests__/CommandCenter.test.tsx, CommandCenter.mobile-scroll.test.tsx, CommandCenter.tablet-layout.test.tsx
CommandCenter passes projectId into Overview analytics hooks, live snapshot, SdlcFunnel, and tab-specific area/view components; tests updated to mock withProjectId and validate scoped reliability requests.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CommandCenter
  participant AreaComponent
  participant useAnalyticsArea
  participant withProjectId
  participant api

  CommandCenter->>AreaComponent: render with projectId
  AreaComponent->>useAnalyticsArea: fetch(path, range, {projectId})
  useAnalyticsArea->>withProjectId: scope URL with projectId
  withProjectId-->>useAnalyticsArea: scoped URL
  useAnalyticsArea->>api: request(scoped URL)
  api-->>useAnalyticsArea: analytics data
  useAnalyticsArea-->>AreaComponent: data, loading, error
Loading
sequenceDiagram
  participant ReliabilityView
  participant api
  participant HealthEndpoint

  ReliabilityView->>api: load() /health/reliability?projectId
  api->>HealthEndpoint: GET scoped path
  HealthEndpoint-->>api: reliability data
  api-->>ReliabilityView: update state
  ReliabilityView->>api: resetStats() POST /health/reliability/reset?projectId
  api->>HealthEndpoint: POST scoped reset
  HealthEndpoint-->>api: reset ack
  api-->>ReliabilityView: refresh via load()
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 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: scoping Command Center and Reliability analytics by projectId.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Tools execution failed with the following error:

Failed to run tools: 13 INTERNAL: Received RST_STREAM with code 2 (Internal server error)


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.

@greptile-apps

greptile-apps Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes FUX-037, where Command Center and Reliability analytics were fetching data without a projectId scope, causing multi-project dashboards to blend metrics across projects. projectId is now threaded from CommandCenter through every area component, MissionControlPanel, SdlcFunnel, and ReliabilityView to the shared useAnalyticsArea hook and direct api() calls via the existing withProjectId utility.

  • AnalyticsAreaOptions gains a projectId field; all 10+ area components accept and forward it; dependency arrays are updated correctly throughout.
  • withProjectId is exported from legacy.ts so ReliabilityView and MissionControlPanel can import it directly for their non-hook api() calls.
  • Tests replace raw fetch spies with the apiMock pattern and add per-area scoping assertions, but all test files inline a copy of withProjectId's logic in the mock factory rather than using vi.importActual — creating a drift risk. A patch changeset for @runfusion/fusion is also absent.

Confidence Score: 4/5

The scoping logic is correct and fully covered by new tests; the missing changeset is the only blocker before this can be considered release-ready.

The core fix is sound: projectId flows correctly through every area hook, the dependency arrays are updated so project-switching triggers re-fetches, and the reset path in ReliabilityView is also scoped. The test suite is thorough and the existing withProjectId utility is exercised correctly. The one real gap is the absent @runfusion/fusion patch changeset — this bug fix is user-visible to operators of multi-project setups and should appear in release notes; without the changeset the pnpm check:changesets gate may also flag the PR.

A .changeset/<name>.md file with "@runfusion/fusion": patch and category: fix needs to be added. useAnalyticsArea.ts and the other changed source files are missing FNXC comments for this change.

Important Files Changed

Filename Overview
packages/dashboard/app/components/command-center/areas/useAnalyticsArea.ts Core hook for all Command Center analytics; projectId added to AnalyticsAreaOptions and applied via withProjectId before the api() call — logic and dependency array are correct, but no FNXC comment documents the requirement.
packages/dashboard/app/api/legacy.ts withProjectId exported so ReliabilityView and other components can import it directly — minimal, safe change.
packages/dashboard/app/components/ReliabilityView.tsx Accepts optional projectId prop and applies it to both the load and resetStats calls via withProjectId; dependency arrays updated correctly. No changeset present and no FNXC comment added.
packages/dashboard/app/components/command-center/CommandCenter.tsx Forwards projectId to every area component and to the live-snapshot fetch in OverviewTab; OverviewTab already had projectId in its props from the pre-existing TeamArea wiring, so the propagation is complete.
packages/dashboard/app/components/command-center/MissionControlPanel.tsx useLiveSnapshot and MissionControlPanel now accept projectId; the fetchLive callback includes it in its dependency array so project-switching triggers a re-fetch and re-polls correctly.
packages/dashboard/app/components/command-center/SdlcFunnel.tsx Accepts projectId and passes it through useAnalyticsArea options — straightforward, correct change.
packages/dashboard/app/components/command-center/areas/tests/areas.test.tsx Comprehensive FUX-037 regression suite added; withProjectId is reimplemented inline in the mock factory rather than imported from the real module, creating a drift risk if the utility function changes.
packages/dashboard/app/components/tests/ReliabilityView.test.tsx All fetch spies replaced with apiMock; new test verifies projectId is appended to both the load and reset requests. Same withProjectId inline re-implementation drift risk as other test files.
packages/dashboard/app/components/command-center/tests/CommandCenter.test.tsx Reliability tab test updated to assert projectId is threaded to the api() call; previous raw-fetch spy removed in favour of apiMock.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[CommandCenter\nprojectId prop] --> B[OverviewTab\nprojectId]
    A --> C[Area Components\nTokens / Tools / Activity / Signals\nProductivity / Ecosystem / Github / Gitlab\nWorkflow / Team]
    A --> D[SdlcFunnel\nprojectId]
    A --> E[MissionControlPanel\nprojectId]
    A --> F[ReliabilityView\nprojectId]

    B --> G[useAnalyticsArea\noptions.projectId]
    B --> H[api live-snapshot\nwithProjectId]
    C --> G
    D --> G
    E --> I[useLiveSnapshot\nprojectId]
    I --> J[api live-snapshot\nwithProjectId]
    F --> K[api load\nwithProjectId]
    F --> L[api reset\nwithProjectId]

    G --> M[withProjectId\nwithRangeQuery\nendpoint + query + projectId]
    M --> N[api\nGET /command-center/...]

    style A fill:#4A90D9,color:#fff
    style G fill:#5CB85C,color:#fff
    style M fill:#F0AD4E,color:#fff
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[CommandCenter\nprojectId prop] --> B[OverviewTab\nprojectId]
    A --> C[Area Components\nTokens / Tools / Activity / Signals\nProductivity / Ecosystem / Github / Gitlab\nWorkflow / Team]
    A --> D[SdlcFunnel\nprojectId]
    A --> E[MissionControlPanel\nprojectId]
    A --> F[ReliabilityView\nprojectId]

    B --> G[useAnalyticsArea\noptions.projectId]
    B --> H[api live-snapshot\nwithProjectId]
    C --> G
    D --> G
    E --> I[useLiveSnapshot\nprojectId]
    I --> J[api live-snapshot\nwithProjectId]
    F --> K[api load\nwithProjectId]
    F --> L[api reset\nwithProjectId]

    G --> M[withProjectId\nwithRangeQuery\nendpoint + query + projectId]
    M --> N[api\nGET /command-center/...]

    style A fill:#4A90D9,color:#fff
    style G fill:#5CB85C,color:#fff
    style M fill:#F0AD4E,color:#fff
Loading

Comments Outside Diff (1)

  1. packages/dashboard/app/components/command-center/areas/__tests__/areas.test.tsx, line 1074-1078 (link)

    P2 withProjectId reimplemented verbatim in every test mock

    Ten test files each inline an identical copy of withProjectId's logic in their vi.mock factory instead of using vi.importActual. Because withProjectId is a pure URL-transformation utility, mocking it at all prevents the real function from running in tests. If the real implementation changes (e.g. the query-parameter name or encoding strategy), every test will continue asserting against the stale inline copy and silently pass. Using { ...(await vi.importActual('../../../api/legacy')), api: apiMock } for the mock factory would let withProjectId run its actual code while still intercepting api. The same pattern is repeated in ReliabilityView.test.tsx, CommandCenter.test.tsx, CommandCenter.mobile-scroll.test.tsx, CommandCenter.tablet-layout.test.tsx, MissionControlPanel.test.tsx, SdlcFunnel.test.tsx, TokensArea.test.tsx, WorkflowArea.test.tsx, areas.github-signals.test.tsx, and areas.gitlab-signals.test.tsx.

Reviews (1): Last reviewed commit: "fix(dashboard): project-scope Command Ce..." | Re-trigger Greptile

Comment on lines 14 to 19
export interface AnalyticsAreaOptions {
/** Opt-in bounded polling interval in milliseconds; omitted means no polling. */
pollMs?: number;
/** Currently-selected project id; when supplied, scopes the request via `projectId` query param. */
projectId?: string;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Missing FNXC comment for the projectId scoping change

The AGENTS.md rule requires a date-stamped FNXC comment whenever a requirement-driven change is made to the codebase. The addition of projectId to AnalyticsAreaOptions is the central behavioral change for FUX-037, but it has no FNXC:CommandCenter entry describing the requirement. The existing comment in the file (line 39) covers a different feature. This file is the most important place to record why projectId was added, since every area component delegates to this hook. The same gap exists in CommandCenter.tsx, MissionControlPanel.tsx, ReliabilityView.tsx, and SdlcFunnel.tsx — none of them have a new FNXC entry describing the FUX-037 project-scoping requirement.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@@ -42,7 +43,7 @@ function formatDateTime(value: string | null | undefined): string {
return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleString();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Missing changeset for a user-visible bug fix

AGENTS.md requires a changeset file whenever a change affects the published @runfusion/fusion package. @fusion/dashboard is bundled into @runfusion/fusion, and this PR is a behavioral bug fix (FUX-037: multi-project dashboard analytics were blending data across projects). No .changeset/<name>.md file exists in this PR — only the placeholder README.md is present. Without a changeset, this fix will not appear in operator release notes and the pnpm check:changesets gate may flag the PR. A "@runfusion/fusion": patch changeset with category: fix is needed.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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)
packages/dashboard/app/components/command-center/MissionControlPanel.tsx (1)

93-94: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Race condition: inFlightRef blocks the new fetch when projectId changes mid-flight

When projectId changes while a snapshot fetch is in-flight, the useEffect cleanup/re-run cycle sets mountedRef.current back to true before the old fetch resolves. The new load() call sees inFlightRef.current === true and returns early. The old fetch then completes and sets snapshot data from the wrong project, with no immediate refetch scheduled. This can persist until the next SSE event or poll tick (5s for active sessions, potentially indefinite for idle state).

The comment on lines 93-94 is also now stale — load closes over projectId and IS recreated when it changes.

🔒 Suggested fix: generation counter to ignore stale fetches
 export function useLiveSnapshot(projectId?: string): LiveSnapshotState {
   const [snapshot, setSnapshot] = useState<LiveSnapshot | null>(null);
   const [isLoading, setIsLoading] = useState(true);
   const [error, setError] = useState<string | null>(null);
   const [polling, setPolling] = useState(false);

   const snapshotRef = useRef<LiveSnapshot | null>(null);
   const pollTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
   const inFlightRef = useRef(false);
   const mountedRef = useRef(true);
+  const loadGenRef = useRef(0);

-  // Stable callbacks below close over only refs + setState, so `load` (and the
-  // SSE subscription / poll interval that call it) never need to be recreated.
+  // `load` closes over `projectId` and is recreated when it changes.
+  // A generation counter guards against stale fetches from a previous project.

   const load = useCallback(async () => {
     if (inFlightRef.current) return;
     inFlightRef.current = true;
+    const gen = loadGenRef.current;
     try {
       const result = await api<LiveSnapshot>(withProjectId("/command-center/live", projectId));
+      if (gen !== loadGenRef.current) return;
       if (!mountedRef.current) return;
       snapshotRef.current = result;
       setSnapshot(result);
       setError(null);
     } catch (loadError: unknown) {
+      if (gen !== loadGenRef.current) return;
       if (!mountedRef.current) return;
       setError(loadError instanceof Error ? loadError.message : "Failed to load live snapshot");
     } finally {
-      inFlightRef.current = false;
-      if (mountedRef.current) {
+      if (gen === loadGenRef.current) {
+        inFlightRef.current = false;
+      }
+      if (gen === loadGenRef.current && mountedRef.current) {
         setIsLoading(false);
         const snap = snapshotRef.current;
         const inFlight = !!snap && (snap.activeSessions > 0 || snap.activeRuns > 0);
         if (inFlight) {
           if (pollTimerRef.current === null) {
             pollTimerRef.current = setInterval(() => {
               void load();
             }, LIVE_POLL_INTERVAL_MS);
             setPolling(true);
           }
         } else {
           stopPolling();
         }
       }
     }
   }, [stopPolling, projectId]);

   useEffect(() => {
     mountedRef.current = true;
+    loadGenRef.current++;
+    inFlightRef.current = false;
     void load();

     const unsubscribe = subscribeSse("/api/events", {

Also applies to: 104-138

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/app/components/command-center/MissionControlPanel.tsx`
around lines 93 - 94, `MissionControlPanel` has a stale-request race: when
`projectId` changes during an in-flight `load`, the new effect reruns while
`inFlightRef.current` is still true, so the next fetch is skipped and the old
response can win. Update `load`/the related `useEffect` flow to use a
generation/request token (or equivalent stale-response guard) so only the latest
`projectId` fetch may commit state, and ensure the old response is ignored and a
fresh load is triggered for the new project. Also refresh the stale callback
comment near `load` to reflect that it now closes over `projectId` and is
recreated on changes.
🧹 Nitpick comments (2)
packages/dashboard/app/components/command-center/areas/__tests__/areas.test.tsx (1)

1605-1620: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cross-project leakage test should verify rendered content, not just the API call.

The test asserts proj-a renders fixtureA's data (toContain("1")) but after rerendering with proj-b, it only checks the API was called with projectId=proj-b — it never verifies the displayed content switched to fixtureB. A stale-state or caching bug that keeps proj-a's data visible would pass this test.

As per coding guidelines, regression tests for bug fixes must include symptom verification, not only mechanism verification.

🧪 Suggested fix: add content assertion for proj-b
     rerender(<TokensArea range={range7d} projectId="proj-b" />);
-    await waitFor(() => expect(apiMock.mock.calls.some(([path]) => typeof path === "string" && path.includes("projectId=proj-b"))).toBe(true));
+    await waitFor(() => {
+      expect(apiMock.mock.calls.some(([path]) => typeof path === "string" && path.includes("projectId=proj-b"))).toBe(true);
+      expect(screen.getByTestId("cc-area-tokens").textContent).toContain("9");
+    });
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/dashboard/app/components/command-center/areas/__tests__/areas.test.tsx`
around lines 1605 - 1620, The cross-project leakage test in TokensArea only
verifies that the proj-b API request happens after rerender, but it does not
confirm the UI updates to the new fixture. Update the test to assert the
rendered cc-area-tokens content after rerendering with projectId="proj-b"
reflects fixtureB, using the existing TokensArea render/rerender flow and the
fixtureA/fixtureB setup so the regression test checks displayed state, not just
apiMock activity.

Source: Coding guidelines

packages/dashboard/app/components/command-center/__tests__/MissionControlPanel.test.tsx (1)

101-113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a rerender test for projectId changes while mounted

The current test verifies the URL invariant via unmount/remount, but the real-world scenario — switching projects while MissionControlPanel stays mounted — is not covered. A rerender-based test would also serve as a regression guard for the inFlightRef race condition flagged in MissionControlPanel.tsx.

As per coding guidelines: "When fixing a bug, regression tests must assert the general invariant across all known surfaces, and bug-fix work must include symptom verification and surface enumeration rather than only the single reproduction."

🧪 Suggested rerender test
it("refetches with new projectId when it changes via rerender", async () => {
  apiMock.mockResolvedValue(snapshot());
  const { rerender } = render(<MissionControlPanel />);
  await flush();
  expect(apiMock.mock.calls.at(-1)?.[0]).toBe("/command-center/live");

  apiMock.mockClear();
  apiMock.mockResolvedValue(snapshot());
  rerender(<MissionControlPanel projectId="proj-abc" />);
  await flush();
  expect(apiMock.mock.calls.at(-1)?.[0]).toBe("/command-center/live?projectId=proj-abc");
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/dashboard/app/components/command-center/__tests__/MissionControlPanel.test.tsx`
around lines 101 - 113, The current MissionControlPanel test only covers
projectId changes by unmounting and remounting, so add a rerender-based
regression test in MissionControlPanel.test.tsx that changes projectId while the
component stays mounted. Use render, rerender, and flush to verify the live
snapshot request updates from /command-center/live to
/command-center/live?projectId=proj-abc after the prop change, which also guards
the inFlightRef race condition in MissionControlPanel.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/dashboard/app/components/command-center/areas/__tests__/TokensArea.test.tsx`:
- Around line 285-293: The TokensArea projectId scoping test only checks the
supplied-projectId path and does not verify omission when the prop is absent.
Update the TokensArea test case to cover both behaviors using TokensArea and
apiMock: keep the existing assertion for the projectId-present render, then add
a separate render without projectId and assert the tokens request URL does not
include projectId, matching the two-case pattern used by WorkflowArea and
GithubArea.

---

Outside diff comments:
In `@packages/dashboard/app/components/command-center/MissionControlPanel.tsx`:
- Around line 93-94: `MissionControlPanel` has a stale-request race: when
`projectId` changes during an in-flight `load`, the new effect reruns while
`inFlightRef.current` is still true, so the next fetch is skipped and the old
response can win. Update `load`/the related `useEffect` flow to use a
generation/request token (or equivalent stale-response guard) so only the latest
`projectId` fetch may commit state, and ensure the old response is ignored and a
fresh load is triggered for the new project. Also refresh the stale callback
comment near `load` to reflect that it now closes over `projectId` and is
recreated on changes.

---

Nitpick comments:
In
`@packages/dashboard/app/components/command-center/__tests__/MissionControlPanel.test.tsx`:
- Around line 101-113: The current MissionControlPanel test only covers
projectId changes by unmounting and remounting, so add a rerender-based
regression test in MissionControlPanel.test.tsx that changes projectId while the
component stays mounted. Use render, rerender, and flush to verify the live
snapshot request updates from /command-center/live to
/command-center/live?projectId=proj-abc after the prop change, which also guards
the inFlightRef race condition in MissionControlPanel.

In
`@packages/dashboard/app/components/command-center/areas/__tests__/areas.test.tsx`:
- Around line 1605-1620: The cross-project leakage test in TokensArea only
verifies that the proj-b API request happens after rerender, but it does not
confirm the UI updates to the new fixture. Update the test to assert the
rendered cc-area-tokens content after rerendering with projectId="proj-b"
reflects fixtureB, using the existing TokensArea render/rerender flow and the
fixtureA/fixtureB setup so the regression test checks displayed state, not just
apiMock activity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 20ca8673-51f6-4aa9-8af8-ea29cfcb552a

📥 Commits

Reviewing files that changed from the base of the PR and between f10c39f and acc2e9c.

📒 Files selected for processing (27)
  • packages/dashboard/app/api/legacy.ts
  • packages/dashboard/app/components/ReliabilityView.tsx
  • packages/dashboard/app/components/__tests__/ReliabilityView.test.tsx
  • packages/dashboard/app/components/command-center/CommandCenter.tsx
  • packages/dashboard/app/components/command-center/MissionControlPanel.tsx
  • packages/dashboard/app/components/command-center/SdlcFunnel.tsx
  • packages/dashboard/app/components/command-center/__tests__/CommandCenter.mobile-scroll.test.tsx
  • packages/dashboard/app/components/command-center/__tests__/CommandCenter.tablet-layout.test.tsx
  • packages/dashboard/app/components/command-center/__tests__/CommandCenter.test.tsx
  • packages/dashboard/app/components/command-center/__tests__/MissionControlPanel.test.tsx
  • packages/dashboard/app/components/command-center/__tests__/SdlcFunnel.test.tsx
  • packages/dashboard/app/components/command-center/areas/ActivityArea.tsx
  • packages/dashboard/app/components/command-center/areas/EcosystemArea.tsx
  • packages/dashboard/app/components/command-center/areas/GithubArea.tsx
  • packages/dashboard/app/components/command-center/areas/GitlabArea.tsx
  • packages/dashboard/app/components/command-center/areas/ProductivityArea.tsx
  • packages/dashboard/app/components/command-center/areas/SignalsArea.tsx
  • packages/dashboard/app/components/command-center/areas/TeamArea.tsx
  • packages/dashboard/app/components/command-center/areas/TokensArea.tsx
  • packages/dashboard/app/components/command-center/areas/ToolsArea.tsx
  • packages/dashboard/app/components/command-center/areas/WorkflowArea.tsx
  • packages/dashboard/app/components/command-center/areas/__tests__/TokensArea.test.tsx
  • packages/dashboard/app/components/command-center/areas/__tests__/WorkflowArea.test.tsx
  • packages/dashboard/app/components/command-center/areas/__tests__/areas.github-signals.test.tsx
  • packages/dashboard/app/components/command-center/areas/__tests__/areas.gitlab-signals.test.tsx
  • packages/dashboard/app/components/command-center/areas/__tests__/areas.test.tsx
  • packages/dashboard/app/components/command-center/areas/useAnalyticsArea.ts

Comment on lines +285 to +293
describe("FUX-037: TokensArea projectId scoping", () => {
it("appends projectId to the tokens request when supplied, and omits it when not", async () => {
render(<TokensArea range={range7d} projectId="proj-tokens" />);
await screen.findByTestId("cc-tokens-table");
expect(apiMock.mock.calls.at(-1)?.[0]).toBe(
"/command-center/tokens?groupBy=model&granularity=day&from=2026-06-08&projectId=proj-tokens",
);
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Test claims to verify omission but only covers the "supplied" case.

The test description says "appends projectId to the tokens request when supplied, and omits it when not", but the test body only renders with projectId="proj-tokens" and never verifies that projectId is absent when the prop is omitted. A regression where projectId is always appended would pass this test undetected.

As per coding guidelines, when fixing a bug, regression tests must assert the general invariant across all known surfaces. The WorkflowArea and GithubArea tests in this PR already demonstrate the correct two-case pattern.

🧪 Proposed fix: add the omission case
   it("appends projectId to the tokens request when supplied, and omits it when not", async () => {
-    render(<TokensArea range={range7d} projectId="proj-tokens" />);
-    await screen.findByTestId("cc-tokens-table");
-    expect(apiMock.mock.calls.at(-1)?.[0]).toBe(
-      "/command-center/tokens?groupBy=model&granularity=day&from=2026-06-08&projectId=proj-tokens",
-    );
+    const { unmount } = render(<TokensArea range={range7d} projectId="proj-tokens" />);
+    await screen.findByTestId("cc-tokens-table");
+    expect(apiMock.mock.calls.at(-1)?.[0]).toBe(
+      "/command-center/tokens?groupBy=model&granularity=day&from=2026-06-08&projectId=proj-tokens",
+    );
+    unmount();
+
+    apiMock.mockClear();
+    render(<TokensArea range={range7d} />);
+    await screen.findByTestId("cc-tokens-table");
+    expect(apiMock.mock.calls.at(-1)?.[0]).toBe(
+      "/command-center/tokens?groupBy=model&granularity=day&from=2026-06-08",
+    );
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
describe("FUX-037: TokensArea projectId scoping", () => {
it("appends projectId to the tokens request when supplied, and omits it when not", async () => {
render(<TokensArea range={range7d} projectId="proj-tokens" />);
await screen.findByTestId("cc-tokens-table");
expect(apiMock.mock.calls.at(-1)?.[0]).toBe(
"/command-center/tokens?groupBy=model&granularity=day&from=2026-06-08&projectId=proj-tokens",
);
});
});
describe("FUX-037: TokensArea projectId scoping", () => {
it("appends projectId to the tokens request when supplied, and omits it when not", async () => {
const { unmount } = render(<TokensArea range={range7d} projectId="proj-tokens" />);
await screen.findByTestId("cc-tokens-table");
expect(apiMock.mock.calls.at(-1)?.[0]).toBe(
"/command-center/tokens?groupBy=model&granularity=day&from=2026-06-08&projectId=proj-tokens",
);
unmount();
apiMock.mockClear();
render(<TokensArea range={range7d} />);
await screen.findByTestId("cc-tokens-table");
expect(apiMock.mock.calls.at(-1)?.[0]).toBe(
"/command-center/tokens?groupBy=model&granularity=day&from=2026-06-08",
);
});
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/dashboard/app/components/command-center/areas/__tests__/TokensArea.test.tsx`
around lines 285 - 293, The TokensArea projectId scoping test only checks the
supplied-projectId path and does not verify omission when the prop is absent.
Update the TokensArea test case to cover both behaviors using TokensArea and
apiMock: keep the existing assertion for the projectId-present render, then add
a separate render without projectId and assert the tokens request URL does not
include projectId, matching the two-case pattern used by WorkflowArea and
GithubArea.

Source: Coding guidelines

@gsxdsm gsxdsm merged commit 8dce51f into Runfusion:main Jul 9, 2026
7 checks passed
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.

2 participants