Skip to content

Add "Sign out and forget this phone" to Pocket - #1251

Merged
nedtwigg merged 1 commit into
mainfrom
pocket-forget-this-phone
Oct 20, 2026
Merged

nedtwigg merged 1 commit into
mainfrom
pocket-forget-this-phone

Conversation

@nedtwigg

Copy link
Copy Markdown
Member

Pocket's plain Sign out keeps the paired-Burrow records, the passkey cache, and the push digest, so signing in to the same account again restores access without pairing. That stays as it is. This adds a second, explicit exit beside it for a phone that is leaving: Sign out and forget this phone.

Behavior

  • Tapping it shows an inline confirmation in place of both exits: "Forget this phone?". The confirmation says the action can't be undone, that each Burrow must be paired again, and that each Burrow still lists this phone until that Burrow's own Disconnect (Settings → Network) clears it. Nothing in the product lets a Burrow remove a single phone (remote-security-model.md → Revocation propagation), so the copy points at Disconnect.
  • Confirming calls PocketClient.forgetThisPhone():
    1. It runs Remove's own record path (#removeRecord, now shared with forgetBurrow) for every KnownBurrowV1, across all accounts. Each delivery id is written to PendingDeliveryDeletionV1 before its record is deleted.
    2. It drains the deletion queue once under the current session. Offline, or for another account's records, the tombstones stay queued, exactly as Remove leaves them.
    3. It clears the :passkey: cache and the :push-endpoint digest (new PocketStorage.clearRegisteredPushEndpoint), then signs out.
  • The app then calls the new unsubscribeFromPushInBrowser(), which is best-effort and never throws, and lands on the auth screen as a first visit. A Relay row that no tombstone can retire, such as another account's, now points at a dead address and is pruned on its next delivery (404/410).
  • If forgetting fails part-way (for example, IndexedDB is unavailable), the user stays signed in on the list with the error shown and can retry. Whatever was already removed stays removed.

Tests

  • pocket-client.test.ts → "forgetting this phone", run offline (no deletion route): every record is removed, every delivery id is queued under its account, the passkey cache and push digest are wiped, hasPriorUse() is false, and the session is cleared in memory and storage. Run online, every row is retired. Another account's record is tombstoned for that account. A last case checks that plain signOut() keeps the records, passkey cache, and digest.
  • pocket-client.test.ts → localStoragePocketStorage forgets the passkey cache and the push digest in both the tab mirror and storage.
  • push-subscribe.test.ts covers that unsubscribeFromPushInBrowser drops the scope's subscription and never throws.
  • App.scan.test.tsx → "forgetting this phone" checks that the action asks first and that Cancel forgets nothing. It checks that confirming calls forgetThisPhone, unsubscribes push, and lands on the auth screen, and that a failure stays on the list with the error and does not unsubscribe. The existing sign-out case now also checks that plain sign-out forgets nothing.
  • I reverted each new test's line one at a time and confirmed the test goes red (16 mutations).
  • New story: Pocket/BurrowsView → ForgetThisPhoneConfirm. Its play step opens the confirmation.

Specs

  • pocket-app.md → "What Pocket stores" now describes both exits. The delivery-mapping paragraph now says only forgetting this phone drops the scope's PushSubscription. The rationale explains why the subscription is dropped. The word budget is ratcheted from 3500 to 3600.
  • security.md → the "Revocation has no mechanism" known gap now notes that a phone can only forget its own pairings, with this action.

🤖 Generated with Claude Code

Plain Sign out keeps the paired records, so signing in again restores
access without pairing. A phone that is leaving now has a second, explicit
exit: asked inline first, it runs Remove for every record (each delivery id
tombstoned before its record goes, the queue drained once), clears the
passkey cache and the push-endpoint digest, unsubscribes the browser's push
subscription, and signs out. Offline, the tombstones stay queued as Remove
already leaves them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 966c3b0
Status: ✅  Deploy successful!
Preview URL: https://5e808f56.mouseterm.pages.dev
Branch Preview URL: https://pocket-forget-this-phone.mouseterm.pages.dev

View logs

@nedtwigg
nedtwigg merged commit e915cd5 into main Oct 20, 2026
18 of 19 checks passed
@nedtwigg
nedtwigg deleted the pocket-forget-this-phone branch October 20, 2026 21:44

This branch is waiting to be deployed

1 waiting deployment
hosted-preview — 966c3b0e Waiting Oct 20, 2026 by nedtwigg via deploy #1693
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.

2 participants