fix(workspace): restore last selection after restart - #7067
Conversation
|
🧪 This PR has changes that need a manual QA pass before merge — please hold off self-merging for now; we'll loop QA in once it's merge-ready (and design/product have signed off, where applicable). |
e983f6d to
9ad9236
Compare
4a7c40b to
a912103
Compare
Siri-Ray
left a comment
There was a problem hiding this comment.
@lefarcen Thanks for the careful workspace-restoration work. I verified the persisted restart-default flow, exact request authority, stale-membership recovery, and the focused daemon/web/e2e suites. The restoration path looks solid; I’m leaving one non-blocking follow-up on the directory-only seat sentinel, where the entry gate and invite dialog currently disagree.
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.
Siri-Ray
left a comment
There was a problem hiding this comment.
@lefarcen Thanks for the careful workspace-restoration work and the quick seat-capacity follow-up. I verified the persisted restart default, stale-membership recovery, exact request authority, multi-client isolation, and the focused daemon/web/E2E paths; the repository gates and live CI matrix are green. The main flow looks solid. I’m leaving one non-blocking error-handling follow-up where a rejected persistence write can still change the daemon’s in-memory restart default.
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.
Siri-Ray
left a comment
There was a problem hiding this comment.
@lefarcen Thanks for the careful workspace-restoration work and the follow-ups that made persistence failures state-neutral. I verified the restart-default flow, exact request authority, stale-membership recovery, multi-client isolation, and the focused daemon/web/E2E paths; the repository gates and live CI matrix are green. The main flow looks solid. I’m leaving one non-blocking observability follow-up for the directory-only seat-capacity sentinel.
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.
Siri-Ray
left a comment
There was a problem hiding this comment.
@lefarcen Thanks for the careful workspace-restoration work and the quick follow-ups on persistence and seat-capacity handling. I verified the restart-default flow, directory-only authority, stale-membership recovery, multi-client request isolation, and the focused daemon/web/E2E coverage; local validation and the live CI matrix are green. I found one non-blocking concurrency issue in stale-selection cleanup that can erase a newer restart default from another tab.
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.
Siri-Ray
left a comment
There was a problem hiding this comment.
@lefarcen Thanks for the careful workspace-restoration work and the follow-up that made stale cleanup compare-and-clear. I reviewed every changed range and rechecked the persisted restart default, directory-only authority, stale-membership recovery, multi-client isolation, and focused daemon/web/E2E coverage. The local repository gates and live CI matrix are green. I found one remaining non-blocking ordering window where stale recovery can persist its fallback after a newer user selection.
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.
Siri-Ray
left a comment
There was a problem hiding this comment.
@lefarcen Thanks for the careful workspace-restoration work and the follow-ups that hardened persistence and stale recovery. I reviewed every changed range and verified the saved cold-start default, directory-only request authority, stale-membership fallback, multi-tab isolation, unknown seat handling, and the atomic conditional replacement path. The focused daemon, web, E2E, and browser checks pass locally, root guard and typecheck pass, and the live CI matrix is green. Nicely done—this is a thoughtful fix. 🙌
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.|
Successfully created backport PR for |
* fix(workspace): restore the last selection on restart * test(workspace): cover persisted restart default * fix(workspace): reuse directory authority for context reads * test(workspace): align unknown seat invite behavior * test(workspace): cover unknown seat invite fallback * fix(workspace): preserve unknown invite capacity * fix(workspace): commit selection after persistence * fix(workspace): preserve unknown seat analytics * fix(workspace): guard stale selection cleanup * fix(workspace): make stale recovery atomic (cherry picked from commit 879236e) Co-authored-by: lefarcen <935902669@qq.com>













































Why
QA found that quitting and reopening the client did not return users to the workspace they had last selected. The web client kept its selection only in tab-scoped
sessionStorage, while the daemon's selection store was no longer updated, so a cold client fell back to Personal/default instead of the user's last workspace.The same investigation found that workspace resolution still depended on Vela's account-global
/api/v1/workspaces/currentendpoint. That state cannot represent multiple tabs or clients using different workspaces, so this PR removes that dependency and keeps request authority explicitly workspace-scoped.What users will see
After selecting a workspace, quitting Open Design, and reopening it, the client returns to that workspace when the membership is still active. If the saved workspace was removed or deleted, startup safely falls back to an available workspace.
Already-open tabs remain independently scoped: the saved workspace is only a cold-start preference and never authorizes data-plane requests.
Surface area
apps/weborapps/desktop(including Electron menu bar)odsubcommand or flag, newtools-dev/tools-packflag, or newOD_*env var/api/*endpoint, new SSE event, or changed shape inpackages/contractsskills/,design-systems/,design-templates/, orcraft/, or change to the skills protocolTRANSLATIONS.mdfor the locale workflow)package.json(dependenciesordevDependencies); workspace-packagepackage.jsonfiles are out of scope. Include a paragraph on what we get vs. what bytes we ship (seeCONTRIBUTING.md→ Code style)Screenshots
Not applicable: this changes restart selection behavior without adding or visually changing a UI entry point.
Bug fix verification
apps/web/tests/useWorkspaceContext.cache.test.tsx(restores the daemon-saved workspace when a new client session has no tab selection)mainand green on this branch? Yes. Onmain, the cold client context remainednull/fell through instead of selecting the saved Team workspace; on this branch all four tests pass.e2e/tests/collab/workspace-switch-and-billing.test.tspersists a Team selection, restarts the daemon over the same data root, and verifies both restoration and stale-membership cleanup.Validation
corepack pnpm install --frozen-lockfilecorepack pnpm guardcorepack pnpm typecheckcorepack pnpm --filter @open-design/daemon exec vitest run -c vitest.config.ts tests/vela-workspace-context.test.ts tests/collab/active-workspace-selection.test.ts tests/collab/workspace-multi-client-scope.test.ts tests/collab/workspace-scope.test.ts tests/collab-presence-routes.test.ts tests/collab/workspace-switch-warms-caches.test.ts tests/workspace-context-authority-server-wiring.test.ts— 111 passedcorepack pnpm --filter @open-design/web exec vitest run -c vitest.config.ts tests/useWorkspaceContext.cache.test.tsx— 4 passedcorepack pnpm --filter @open-design/e2e exec vitest run -c vitest.config.ts tests/amr/turn.test.ts tests/collab/headerless-mutation.test.ts tests/collab/new-account-default-workspace.test.ts tests/collab/reconcile-unbound-authority.test.ts tests/collab/team-project-catalog.test.ts tests/collab/workspace-invite-flow.test.ts tests/collab/workspace-skill-resource-isolation.test.ts tests/collab/workspace-switch-and-billing.test.ts— 20 passed/api/v1/workspaces/current,workspaces/current, andWORKSPACE_CURRENT_PATH— 0 matches