fix: persist active workspace and redirect on session/workspace mismatch#238
fix: persist active workspace and redirect on session/workspace mismatch#238igorcesarcode wants to merge 2 commits into
Conversation
Persists the selected workspace ID in localStorage so that direct navigation to a session URL (e.g. after a page refresh) resolves the correct workspace without falling back to the first available one. - Add Zustand persist middleware to use-active-workspace-store with key "agh:active-workspace" and partialize on selectedWorkspaceId - Auto-set selectedWorkspaceId to the first workspace when null so the selection is immediately persisted on first load - Add useSessionWorkspaceGuard hook that detects workspace/session mismatch and navigates immediately to /agents/$name when the active workspace changes to one that does not own the current session, avoiding a multi-second wait for TanStack Query retry exhaustion
|
@igorcesarcode is attempting to deploy a commit to the Compozy Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Review limit reached
More reviews will be available in 24 minutes and 50 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughThis PR adds workspace validation and persistence to enforce that sessions remain bound to their assigned workspaces. It persists the active workspace selection in local storage, refines workspace selection logic to handle edge cases, introduces a session workspace guard hook, and integrates that guard into the SessionPage component. ChangesWorkspace Validation and Persistence
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@web/src/hooks/routes/use-session-workspace-guard.ts`:
- Around line 25-33: The guard effect only depends on activeWorkspaceId so it
misses the initial load when sessionWorkspaceRef.current (or sessionWorkspaceId)
is populated after mount; update the hook so the validation runs immediately by
adding sessionWorkspaceId (or sessionWorkspaceRef.current) to the dependency
array of the second useEffect (or merge the two useEffect blocks into one) and
perform the same mismatch check (compare sessionWorkspaceRef.current /
sessionWorkspaceId to activeWorkspaceId) and call navigate({ to:
"/agents/$name", params: { name: agentName }, replace: true }) when they differ.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 878020f8-4908-4e8f-9447-4a60ef103b93
📒 Files selected for processing (4)
web/src/hooks/routes/use-session-workspace-guard.tsweb/src/routes/_app/agents.$name.sessions.$id.tsxweb/src/systems/workspace/hooks/use-active-workspace-store.tsweb/src/systems/workspace/hooks/use-active-workspace.ts
Merge the two useEffect blocks into one so the mismatch check fires immediately when sessionWorkspaceId arrives after mount, not only on subsequent activeWorkspaceId changes.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
pedronauck
left a comment
There was a problem hiding this comment.
Automated review — self + Codex (gpt-5.5, xhigh)
Independent automated review of PR #238 (web-only: persist active workspace + redirect on session/workspace mismatch). Authoritative change set is 4 files: use-session-workspace-guard.ts [new], agents.$name.sessions.$id.tsx, use-active-workspace-store.ts, use-active-workspace.ts.
- Self verdict: REWORK (1 blocker, 2 risks, 1 nit)
- Codex verdict: FIX_BEFORE_SHIP (2 blockers, 2 risks, 1 nit)
- Combined: not shippable as-is.
This PR already carries a human CHANGES_REQUESTED, so it is not an auto-merge candidate regardless.
Blockers
- [codex B-1 / self] The headline redirect fails on the exact reload / direct-nav path it targets.
workspace_iddoes exist on the session response (optional), so the guard is wired — butuseSession(id)fetches via the active workspace (GET /api/workspaces/{activeWorkspaceId}/sessions/{id}), and the backend is strictly workspace-scoped (requireSessionInWorkspace→ 404 on mismatch). On initial load with a mismatched persisted workspace, the session never loads,session?.workspace_idisundefined, the guard ref stays empty, and the page falls through to the generic "Session not found" toast instead of redirecting. The redirect only works for the in-app workspace-switch case (truthful-UI gap). Fix: fetch the session by id independent of the active workspace (or resolve its workspace first), then redirect; add a test proving the reload/direct-nav mismatch redirects. - [codex B-2 / self] No tests, and the route now pulls real workspace TanStack Query state into a suite that can't provide it. The canonical
-agents.$name.sessions.$id.test.tsxonly wrapsTopbarSlotProviderand mocksuseSession— noQueryClient/workspace mock — so pullinguseActiveWorkspace→useWorkspacesinto the route likely breaks that suite and leaves both new invariants (persistence + redirect) uncovered. Fix: add the QueryClient/workspace test scaffolding and cover the persisted store and the redirect.
Risks
- [self / codex R-1] Hydration race in
use-active-workspace.ts:28-37. Auto-select-first-workspace can run before zustandpersistrehydratesselectedWorkspaceId, causing flicker or an unintended redirect on first paint. Fix: gate auto-select onpersist.hasHydrated()/onFinishHydration. - [codex R-2] Persisted
localStoragestore (agh:active-workspace) needs an explicit test reset — setup clearssessionStorage, notlocalStorage→ cross-test state leakage. Fix: clearlocalStoragein test setup.
Nits
- [codex N-1 / self] Render-phase ref mutation in
use-session-workspace-guard.ts:19-26; the effect compares the mutable ref rather than thesessionWorkspaceIddependency. Fix: compute the derived value in the effect keyed on the id.
Codex ran once via compozy exec --ide codex --model gpt-5.5 --reasoning-effort xhigh (exit 0, findings validated). No source files modified.
Summary
selectedWorkspaceIdin localStorage via Zustand persist middleware so that direct navigation to a session URL (e.g. after a page refresh or sharing a link) resolves the correct workspace instead of falling back to the first one in the list.selectedWorkspaceIdis null, the first available workspace is automatically selected and persisted, avoiding the case where the fallbackquery.data[0]changes silently across refreshes.useSessionWorkspaceGuardhook detects when the active workspace changes to one that does not own the current session and navigates to/agents/$nameinstantly — without waiting for TanStack Query's multi-second retry exhaustion on the 404.Root cause
useActiveWorkspaceStorehad no persistence —selectedWorkspaceIdreset tonullon every page load.useActiveWorkspacesilently fell back toquery.data[0], which could be a different workspace. When navigating directly to a session URL, the wrong workspace was used to fetch the session, so the transcript query was either fetching from the wrong workspace (empty result) or was disabled entirely.Test plan
/agents/$nameimmediately (< 500 ms), not after a 7+ second retry timeoutmake web-lintpasses (zero oxlint warnings)bunx turbo run typecheck --filter=./webpassesSummary by CodeRabbit
New Features
Bug Fixes