fix(lib): say what actually blocks disconnecting a workspace - #1790
Conversation
Turning workspace sync off answered all three of its preconditions with "Open this drive with local storage available before disconnecting". Two of them have nothing to do with local storage, so someone signed out, or on a server this client holds no live connection to, was told to do something they had already done. Each precondition now names itself. The local database is waited for rather than refused: it attaches a few hundred milliseconds after a page load and again after every sign-in, and a click inside that window was rejected outright. A websocket that exists but is not open is reported as such, instead of letting the inventory request fail on the raw "WebSocket is not open". Also normalize the local-only drive set on every write and on rehydrate. Every reader looks through normalizeSubject, so a trailing slash or a legacy did:ad: spelling could store a key nothing found again, and a resource inside a disconnected workspace could still try the server.
build.rs stages the plugin assets there before embedding them, exactly as it does with the already-ignored server/assets_tmp, so a built checkout reports the staging directory as untracked.
|
The red Feature branches do not trigger Generated by Claude Code |
|
CI on
Why it is not the diff:
The run landed while three other pipelines were in flight on the same host (runs 4619 to 4621), which is the load this suite's 5 s default does not survive. Raising that budget, or stopping the four runner processes from overlapping, is a separate change and not something I will fold into this PR. Re-running the failed jobs once, which is the single re-run this failure gets. Generated by Claude Code |
…ywhere
Normalizing only the writes broke the readers that did a raw `has`:
`isLocalOnlyDrive('did:ad:drive:test')` missed a drive registered under
that same spelling, because the set now held `atomic:drive:test`. That is
how vaultAutoBackup's two failures came about: a restored drive was not
recognised as local, and a drive switch dropped a pending backup.
`isLocalOnlyDrive` and the `driveOf` fallback in `isLocalOnlySubject` now
normalize like the rest. Covered by a test registering and reading back
the legacy spelling.
|
Attempt 2 got past the Cause: I normalized the writes into Fixed in 2a8efee: Verified locally before pushing: the two failures reproduce with the old raw One unrelated local failure worth flagging for anyone else running this suite outside CI: Dispatching CI on the new head. Generated by Claude Code |
makeDriveLocal keeps both sides: the named preconditions and the attach-window wait from this branch, then develop's refused-drive path, which now runs after the database is known to be attached. rbsrItems is driveInventory on develop. The refused-drive test's 'hosted drive' case has no socket, so it now expects the connection message.
|
Generated by Claude Code |
|
Run 4711 ( Generated by Claude Code |
Only browser/CHANGELOG.md conflicted; both sides' entries are kept.
Before: turning workspace sync off on the Sync page could fail with "Open this drive with local storage available before disconnecting", whatever was actually wrong. All three preconditions shared that one sentence, and two of them have nothing to do with local storage: a signed-out user, and a client that holds no live connection to the server, were both told to do something they had already done. The third case was not even a real refusal. The local database attaches a few hundred milliseconds after a page load, and again after every sign-in, so a click inside that window was rejected although the database was on its way. And when a socket existed but was not open, the guard let it through and the attempt died on the raw
WebSocket is not open.After: each precondition says what it is.
A click during the database's attach window waits for the attach instead of being refused, and a socket that exists but is not open now produces the connection message rather than
WebSocket is not open.The same change also settles the spelling of the local-only workspace registry.
localOnlyDriveswas written raw and read raw in some places and throughnormalizeSubjectin others, so a trailing slash or a legacydid:ad:identifier could store a key another reader never found again, and a resource inside a disconnected workspace could still try to reach the server. Every write and every read now goes throughnormalizeSubject:registerLocalOnlyDrive,unregisterLocalOnlyDrive, the rehydrate fromlocalStorage,isLocalOnlyDrive, and both fallbacks inisLocalOnlySubject(the resource's rawdrivepropval and thedriveOfparent chain).How:
Store.makeDriveLocalchecks the agent, then awaitswaitForClientDb()anddb.waitForInit(), then resolves a socket the waypromoteLocalDrivealready does (getDefaultWebSocket()falling back togetWebSocketForSubject), requiringreadyState === WebSocket.OPEN. The subject handed torbsrItems,verifyLocalDriveCopyandunsubscribeFromDrivestays the caller's spelling on purpose: the server echoes back the subjects it was asked about, and the drive-wide SUB was sent undergetDrive()'s own unnormalized spelling. Normalization is confined to the registry.browser/lib/src/make-drive-local.test.tscovers the three messages, the attach-window wait, both registry spellings, the legacydid:ad:round trip and the legacy propval.Tested:
browser/lib996 passed and 1 skipped;browser/data-browserincludingvaultAutoBackup.test.ts(38 passed), whose two failures on the first push are what exposed the half-normalized registry;pnpm run -r lintandtsc --noEmitclean.No screenshots: this changes error copy inside the Sync page's existing error banner, with no layout or component change. The three strings are quoted above in full.
Requested by Joep