Skip to content

fix(web): a claim closes one heir's share, not the whole vault - #351

Merged
Jolah1 merged 1 commit into
mainfrom
fix/vault-means-account
Aug 19, 2026
Merged

fix(web): a claim closes one heir's share, not the whole vault#351
Jolah1 merged 1 commit into
mainfrom
fix/vault-means-account

Conversation

@Jolah1

@Jolah1 Jolah1 commented Aug 19, 2026

Copy link
Copy Markdown
Owner

The problem

One owner email and one owner key make one vault. Every row underneath it is one heir's share, with its own descriptor, address, funds, timelock and claim link. The server already works this way (see the prevent_conflicting_verified_owner_email trigger, which allows rows to share an owner email as long as they carry the same owner key).

The UI did not. It treated a row as the whole vault, so when one heir claimed, the owner was told the vault's work was done and handed a button that hid the share, even with three other heirs still waiting.

What changed

A claim closes one share. VaultClosedCard no longer says "This vault's work is done" and no longer has a Done button. It names the heir, and when there are siblings it says the other shares are unaffected. The share stays on screen marked claimed, and only leaves when the owner removes that heir. The dismiss handler and the now-unreachable "closed" empty reason went with it.

Sign-in lands on the oldest share. openGroup sorts the recovery bundles by created_at (id as tiebreak) before writing them. "The first heir" now means the one set up first, not whatever order the server returned. It still skips claimed shares and lands on the next live one.

getAllVaultMetas() sorts the same way. It was returning Object.values(), which is storage insertion order, not creation order. That was the root of the landing bug, and it silently disagreed with getVaultsByGroup, which already sorted. Three tests cover ordering, the agreement between the two functions, and the id tiebreak.

The empty-state button tells the truth. It offered "Add an heir" or "Set up a vault" depending on why the screen was empty, but both went to "setup", which is full new-email account setup. It now says "Set up a vault" in both cases.

Not in this PR

"Add an heir" cannot be made real from the client. PasswordSetupPortal always mints a fresh groupId, and api.deleteVault drops the row that carries the owner's email, key and verified status, so removing the last heir deletes the account. Once the server keeps that row and clears the heir fields instead, the second button comes back with a route that joins the existing vault.

Testing

  • npx tsc --noEmit clean
  • npm run lint clean
  • npx vitest run 125 passed, 16 files (was 122)
  • The three new tests were checked against a reverted sort: all three fail without it.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ghost-key Ready Ready Preview Aug 19, 2026 2:35pm

One owner email and one owner key make one vault. Every row under it is
one heir's share, with its own descriptor, address, funds and timelock.
The UI had been treating a row as the whole vault, which made a single
heir's claim look like the end of everything.

Three fixes:

- The claimed card no longer says "This vault's work is done" and no
  longer offers a Done button that hid the share. It names the heir
  ("Fola's share is claimed") and says the other shares are unaffected.
  The share stays visible until the owner removes that heir.

- Sign-in lands on the oldest share. The recovery bundles are sorted by
  created_at (id as tiebreak) before they are written, so "the first
  heir" means the one set up first rather than whatever order the
  server returned.

- getAllVaultMetas() sorts the same way. It was returning
  Object.values(), which is storage insertion order, not creation
  order. That was the root of the landing bug, and it disagreed with
  getVaultsByGroup, which already sorted. Three tests cover it.

The empty-state button now says "Set up a vault", which is the only
thing that route has ever done. "Add an heir" needs the server to keep
the owner row when the last heir is removed, so it comes back with that
change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@Jolah1 Jolah1 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Jolah1
Jolah1 merged commit d5dc042 into main Aug 19, 2026
9 checks passed
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