Skip to content

client: skip vault sign-out broadcast when nothing existed#70

Merged
dolonet merged 1 commit into
mainfrom
fix/vault-signout-empty-skip
May 17, 2026
Merged

client: skip vault sign-out broadcast when nothing existed#70
dolonet merged 1 commit into
mainfrom
fix/vault-signout-empty-skip

Conversation

@dolonet
Copy link
Copy Markdown
Owner

@dolonet dolonet commented May 17, 2026

Summary

confirmSignOut called ensureVaultId() (the minting variant) at the top. On a fresh tab where the user clicks Sign Out without ever having signed in, that minted a fresh vault_id just to delete it on the next line — and worse, _broadcastSignedOut still fired unconditionally, telling sibling tabs (which may have a live unrelated vault session) to invalidate caches, tear down their panes, and set _vaultRecentlySignedOut (blocking any subsequent saves until they hit doConnect).

User-visible impact: open one tab with an active vault session, open a second clean tab, click Sign Out on the second tab → the first tab's vault panes drop with "Vault key missing" and the next save attempt silently bails.

Fix

Switch to the non-minting ensureVaultIdIfPresent(). Record preexisting (truthy iff there was actually a vault to sign out of) and gate the four broadcast-shaped side-effects on it:

  • _disconnectAllVaultPanesForNoKey()
  • invalidateVaultCache()
  • _vaultRecentlySignedOut = true
  • _broadcastSignedOut()

Local-only cleanup (_idbDelete of K + vault_id, saveSaved([]), sessionStorage.removeItem, pane manifest filter) still runs unconditionally as defensive housekeeping — the user did click Sign Out, the local list might have orphan rows from an older session, no reason to skip the scrub.

Toast copy softens to "No saved credentials in this browser to remove" on the empty path so the click isn't silently no-op.

Tests

Two regression tests in the same Vault: Sign out of this browser block:

  • sign out: empty-vault path does NOT mint vault_id or broadcast — fresh tab, no ensureVaultId calls, click Sign Out, assert broadcasts === 0 (BroadcastChannel.postMessage capture), IDB vault_id still empty, _vaultRecentlySignedOut === false.
  • sign out: populated-vault path DOES broadcast to siblings — counter-test for the gate: populate vault, click Sign Out, assert broadcasts === 1 and the flag IS set.

Test plan

  • cd tests/frontend && node test_connect.js — 497 / 0
  • python3 test_server.py -q — 420 / 0 (unchanged; client-only fix)
  • Manual: open tab A with active vault session, open tab B clean, Sign Out on tab B, verify tab A's session stays alive

Refs #67 (follow-up from holistic review).

confirmSignOut called ensureVaultId() (minting variant) at the top.
On a fresh tab where the user clicks Sign Out without ever having
signed in, that minted a vault_id just to delete it on the next
line — and worse, _broadcastSignedOut still fired, telling sibling
tabs (which may have an active unrelated vault session) to
invalidate caches and tear down their panes for nothing.

Fix: use ensureVaultIdIfPresent(); record `preexisting` and gate
_broadcastSignedOut + _disconnectAllVaultPanesForNoKey +
invalidateVaultCache + _vaultRecentlySignedOut on it. Local wipes
(IDB delete, saved-card list, sessionStorage, pane manifest) still
run unconditionally as defensive cleanup. Toast message softens to
"No saved credentials in this browser to remove" on the empty
path.

Tests: two regressions — empty-vault path asserts no broadcast, no
minted vault_id, and the sign-out flag stays clear; populated-vault
path asserts the broadcast still fires (counter-test for the gate).
@dolonet dolonet merged commit c537178 into main May 17, 2026
5 checks passed
@dolonet dolonet deleted the fix/vault-signout-empty-skip branch May 17, 2026 21:11
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.

1 participant