- auth-identity.md claimed electing sync involves 'no migration, no copy'; in reality the runtime opens the managed namespace and copies local rows across. Describe the durable election record and offline-safe local-tier copy instead. - Document the two-step backup flow: sync is never enabled while the recovery phrase is still unread. - The passkey decision record said principal replacement calls db.logout() and recreates the runtime 'with sync elected'; replacement deliberately uses shutdown() and commits election only after the restored secret is durably saved.
- commit
- ffd751bf77f04a26ecf15219f8a723e951891b0e
- parent
- 8f32b2405f45dbece1908bc4c1bbddaa14586121
- author
- Dami <dami.etoile@gmail.com>
| M | docs/ | 12 | ++++++++---- |
| M | docs/ | 9 | ++++++--- |
@@ -37,9 +37,12 @@ local-only: createDb({ appId, secret }) → account X, on this
3737 synced: createDb({ appId, secret, serverUrl }) → account X, now replicated3838 ```3939 40-Electing to sync just recreates the runtime with `serverUrl` added. Because the secret (and thus the41-account id) is unchanged, every write made while local-only is already part of account X and syncs42-up. No migration, no copy, no new account.40+Electing to sync recreates the runtime with `serverUrl` added. Because the secret (and thus the41+account id) is unchanged, every write made while local-only still belongs to account X — no new42+account, and nothing for the user to re-enter. Internally, the election is one durable record: lofi43+opens the account's managed namespace, copies the rows written while local-only into it (waiting44+only for local durability, so the copy also completes offline), and replicates them up through45+normal sync once connected.4346 4447 ## The recovery phrase is the portable backup4548 @@ -77,7 +80,8 @@ confused.
7780 7881 - **First boot** → local-only account opens immediately. No gate.7982 - **Back up & sync** → create a recoverable passkey when supported → reveal the recovery phrase to80- save → turn on sync → the runtime recreates and the account replicates.83+ save → the user confirms the phrase is saved → sync turns on and the runtime recreates (a page84+ reload), and the account replicates. Sync is never enabled while the phrase is still unread.8185 - **Return boots** → the same cached secret opens the same account, synced or not.8286 - **A fresh browser** → explicitly confirm replacement → restore from passkey or phrase → the old8387 subscriptions, stores, workers, cached clients, and Jazz client shut down → the restored account@@ -45,9 +45,12 @@ account backups.
4545 holding it can act as the account.4646 - Restoring a different secret requires explicit confirmation while the current account is4747 local-only, because unsynced local rows cannot be recovered from Jazz sync.48-- Principal replacement detaches lofi stores/subscriptions, saves the restored secret for the app49- ID, calls Jazz `db.logout()` to stop workers and cached clients, recreates the runtime with sync50- elected, and exposes the restored `session.user_id` for verification.48+- Principal replacement detaches lofi stores/subscriptions and shuts down the old Jazz client and49+ workers via `db.shutdown()` — deliberately not `logout()`, which would clear local account state50+ that must carry forward. It then saves the restored secret for the app ID, commits the sync51+ election and managed-namespace record only after that save succeeds (a failed replacement leaves52+ the previous local account bootable), reopens the runtime on the restored principal, and exposes53+ the restored `session.user_id` for verification.5154 5255 ## Evidence sources5356