feat(workspace): make workspace changes take effect on restart - #129
Closed
Yuge Zhang (ultmaster) wants to merge 4 commits into
Closed
feat(workspace): make workspace changes take effect on restart#129Yuge Zhang (ultmaster) wants to merge 4 commits into
Yuge Zhang (ultmaster) wants to merge 4 commits into
Conversation
Every layer had to answer "which workspace am I looking at?" before it could do its job: handles captured the active path and rejected the next call if it had moved, the cache keyed on it, and `createSpace`/`deleteSpace` took an operation lease so a switch could not strand them mid-flight. All of it existed to move a live process from workspace A to B. Issue microsoft#126 says that is not a product requirement, and the price is about to rise — a connection-holding backend would have to be staged, published, and detached to keep the trick working, and a backend with no workspace at all (Postgres plus Azure Blob) would still have to answer the question. So the workspace is now fixed for a process. Activation happens at most once: asking for a different one is refused with `WORKSPACE_RESTART_REQUIRED` without preparing a thing, and asking for the active one again is a no-op, because the client re-sends its remembered path on every boot. Choosing a different folder saves the choice and restarts — the desktop shell does it, since it owns both `workspace.json` and the server child; a browser tab says so instead. The shell hands its choice to the server as `HUABU_WORKSPACE_STARTUP`, deliberately not `HUABU_WORKSPACE`: the operator's variable locks the workspace, hides the path, and fails the boot when the folder cannot be opened, which is right for a deployment and wrong for a user whose drive is unplugged. A shell-chosen workspace that will not open leaves the process unconfigured with the reason in `WorkspaceInfo.startupError`, so the client shows the picker rather than the app being unusable — and does not spend another 70-second preparation on the path the server just failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q6jDM21KBHPynupZHVg2o3
Every Disk handle, repository, blob scope, and log/task/node writer captured the workspace active when it was built and refused to run once the active one moved. The registries did the same by other means: the `CanvasStore` LRU self-detected a switch and cleared itself, and its key — along with the node tombstone map's and the Task mutation mutex's — carried a workspace path beside the Space id. All of it answered a question a process can no longer ask. The workspace is fixed for a process lifetime, so a Space id already denotes one Space, and a handle can only have been built against the workspace being served. The guards are gone, the keys are Space ids, and the one thing that was genuinely load-bearing is now explicit: committing a workspace drops the instance cache and the node fences together, which is what keeps a test moving through several temporary workspaces from reading a stale one. The blob adapter keeps resolving each operation's directory once before its first await — that was never about workspaces. It stops a Space directory renamed mid-write from landing the temp file in one place and the destination in another, so its test now says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q6jDM21KBHPynupZHVg2o3
The architecture docs still described a Server that could move between workspaces while running: activation kept "the previously active workspace" serving, deletion held an active-Workspace lease, handles and cache keys were Workspace-qualified, and the desktop cold start paid for a `PUT` the renderer had to make because the server always booted with nothing. None of that is true after issue microsoft#126. What replaces it is shorter: the workspace is named at startup — by the operator, by the shell, or by the one runtime activation an unconfigured process accepts — a second choice comes back as `WORKSPACE_RESTART_REQUIRED`, and nothing in storage records which workspace it was built for. The proposal's open question about connections on a free-mode switch is answered rather than restated, since a backend that holds one now opens at startup and closes at shutdown. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q6jDM21KBHPynupZHVg2o3
Yuge Zhang (ultmaster)
force-pushed
the
feat/workspace-restart-bound
branch
from
August 21, 2026 02:48
dde402b to
0159c07
Compare
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #126.
What changes
A server process now serves one workspace for its lifetime. Selecting a different Home folder persists the choice and takes effect on restart, rather than moving a live process from workspace A to workspace B.
<userData>/workspace.jsonbefore forking the server and hands the path over asHUABU_WORKSPACE_STARTUP. That is deliberately notHUABU_WORKSPACE: the operator's variable locks the workspace, hides the path, removes the picker, and fails the boot when the folder cannot be opened — right for a deployment, wrong for a user whose drive is unplugged. A shell-chosen workspace that will not open leaves the process unconfigured with the reason inWorkspaceInfo.startupError, so the client shows the picker instead of the app being unusable.PUT /api/workspacefor a different path returns409 WORKSPACE_RESTART_REQUIREDwithout preparing anything; re-sending the active path stays a no-op, because the client re-sends its remembered path on every boot and a second tab must not be told to restart. Standalone deployments keep usingHUABU_WORKSPACE.workspace:restart); a browser tab, which cannot restart the server it is talking to, saves the choice and says a restart is needed.CanvasStoreLRU, and the workspace component of the node-tombstone and admission-gate keys. Committing a workspace now drops the instance cache and node fences together (resetStorage()), which is the one part that was load-bearing — it keeps a test moving through several temporary workspaces from reading a stale one.Net: -651 lines across server, desktop, web, and shared.
Why now
This is the storage-lifecycle simplification issue #126 asks for, and it lands before phase 4.6 on purpose: without it, the multi-backend work would have to build staged connection publication, detach, stale-mount recovery, and workspace-scoped invalidation for connection-holding backends (SQLite, Postgres, Azure Blob) — machinery whose only job is a switch that is not a product requirement. Phase 4.6 (#125) rebases on top of this and drops that scope.
Verification
pnpm run checkpasses end to end: lint, format, typecheck, 118 server test files (1004 tests), 131 web test files (990 tests), i18n parity, agent-team skills, license headers.Tests written for the new behavior:
Not done here
The proposal's open question about connections on a free-mode switch is answered rather than deleted; the Phase 2/4 retrospectives keep their historical wording.
docs/architecture/canvas-storage.mdanddesktop-startup.mdare updated to describe the one-workspace process.🤖 Generated with Claude Code
https://claude.ai/code/session_01Q6jDM21KBHPynupZHVg2o3