Database transfer and profiles¶
The user guide explains moving a database between computers. Development rules remain in AGENTS.md; verification and shipping belong in the completion audit.
Local profile identity¶
profiles.sqlite lists local profiles and the next-launch choice. The original workspace remains shep.sqlite, named My mail, with its existing credential keys. Imports get a fresh device-owned UUID and profiles/<uuid>/shep.sqlite. Neither imported values nor a shared Google profile ID can select that path or credential namespace.
The catalog uses its own bounded 32-command SQLite worker. Pages contain at most 50 profiles. Rename/selection use revision checks so an older window cannot overwrite a newer choice. The running engine keeps its current Store and credential scope until exit; changing the next-launch choice cannot retarget in-flight work. There is no hot profile switch.
Complete transfer¶
Export pins a consistent read transaction and copies SQLite pages through a separate connection. Its bounded progress/cancel/completion channels do not occupy provider capacity or the mail-cache worker for the whole copy. Export protects the profile catalog, all profile caches, journals and operation paths, including aliases.
Import copies into a private file, checks schema versions ⅔ against an independently created schema, runs integrity/foreign-key checks and validates connection metadata before review. Newer/foreign schemas and extra triggers/views are rejected. SQL work is cancellable; raw mail is not collected into a single application buffer. The complete database format has no encrypted-snapshot 256 MiB ceiling, but still needs disk space for a staged copy and any pinned WAL history.
Confirmation consumes the reviewed file rather than reopening the user's source path. Device preparation commits in one transaction, then closes SQLite before publishing the file without overwrite. Publication is the commit boundary: later cancellation or registration failure must preserve the saved copy. A ready marker lets catalog refresh adopt that same file after interruption. A damaged unselected profile produces a warning without hiding other profiles; a missing selected file is never silently recreated.
Pending work and device settings¶
Import archives changed metadata in imported_operations, retaining original MIME in its existing rows. Pending outgoing deliveries/Sent uploads, bulk steps and unacknowledged folder changes become unconfirmed review work. Existing move acknowledgments remain available for their recovery path. An import must never cause an unacknowledged provider action to repeat automatically. The review requires an explicit acknowledgment when pending actions exist.
Imported credential-cleanup requests are archived and cleared. Notification baselines reset quietly. Local window dimensions and backup location stay device-specific; automatic backup/readiness and Google connection/grant state are reset. The imported account/calendar definitions, cached events, mail, drafts and portable preferences remain available. Passwords, Google tokens and external encrypted-backup upload journals are outside this database format.
Credentials¶
credentials.rs owns OS calls on one bounded 32-command FIFO thread shared by the engine's adapters. Accepted writes drain even if their observer disappears. Missing-password restore checks and writes in that same queue. Imported profiles use profile:<local UUID>:<key> and never fall back to another profile's secrets.
Portable account/CalDAV IDs are validated before they can address credentials. Reserved Google/backup keys, SMTP-key aliases and overlapping connection keys are rejected. Comparison includes case-insensitive aliases because Windows credential target names are case-insensitive. CalDAV discovery's caldav:<64 hex digits> IDs remain valid, including in encrypted backup/password restore.
Shared profiles¶
OAuth/profile sync uses the Flutter interoperability handover and shared profile-core operations. Desktop SQLite remains a local transfer format. First-device creation, new-device discovery/import, continuous field reconciliation and portable-setting reviews are implemented; endpoint/removal decisions and broader live interoperability are tracked separately.
Connection reviews read at most eight mapped native accounts per page. Each freezes the profile/Google/consent and native connection generations, the exact history revision and all reviewed versions. A stale action cannot be retargeted after another review row disappears. Pausing account sync clears its controls and invalidates pending decisions.
Keep this device's connection publishes the reviewed local endpoints, preserving other field intent. Add shared connection assigns a fresh native account UUID and requires reconnection. The old account keeps its endpoints, credentials, mail and server identities, is named “(previous setup)” and remains local-only. It can later be removed through the normal account-removal review. No existing message UID or password is redirected to a different server. The shared operation retains its original optional fields and exact conflict resolutions.
Native account changes and a durable pending operation are committed before shared-history admission. Restart retries that saved operation; it does not add another native account. Remote removals require a separate decision and cannot be revived by accepting an old connection review. Global removal choices and actual cross-client Google verification remain open. Imported accounts still start with Reconnect; synced passwords (below) can complete it after a tested import.
Synced account passwords¶
Sam chose Google-only protection (11 September 2026). Sync account passwords
through your Google account sits under Profiles and sync, off until the user
turns it on, and says plainly that anyone with access to that Google account's
Drive app data could read them. It only runs while account sync is on. The
contract, key custody and concurrency rules are in the credential section of the
handover;
the codec is shared/profile-core's vault module.
profile_sync/vault runs one pass after each continuous cycle, and on its own
after the toggle changes. It lists the binding's key and vault files, merges
every readable vault, publishes each mapped account's incoming (and separate
SMTP) password from the keychain, confirms equal values and removes the entries
of accounts removed here or in the shared history, rotating the key. Turning the
toggle off removes this device's entries on the next online pass, even while
profile sync is paused; when no password remains every credential file is
deleted. A newer vault format is read-only here. While the toggle is on, each
pass lists and downloads the binding's credential files (normally one key and
one vault) and reads the mapped accounts' keychain entries; nothing is written
when every slot is already current.
Received passwords are staged in <account>:vault-incoming/<account>:vault-smtp
keychain slots, read back and tested against the account's own servers under its
account lock. Activation then takes the connection lifecycle and account locks,
rechecks the account and mapping, writes the SMTP then incoming active slots and
clears profile_reconnect_v1 in the same transaction that records the revisions.
A failed test keeps the active pair, deletes the staging and records the failed
revision; Try synced passwords again retries it explicitly. A password is only
offered to an account whose portable connection gives the published endpoint, so
changed or downloaded servers keep the reviewed reconnection rules.
profile_credentials_v1 holds the toggle's pending removal, a vault device UUID,
per-slot synchronised and failed revisions and staged account IDs; never a
password, a digest of one or key material. Database import archives it. The two
active keychain writes are not atomic: a failure between them leaves the
revisions unrecorded, so the next pass stages, tests and activates the pair again.
Post-enrollment account linking¶
A new shared account definition that arrives through the continuous loop is held for review whenever an unmapped native account has the same connection fields or the same address; the cycle reports it instead of silently creating another reconnecting account. The link review shares the eight-per-page account review controls and freezes the same profile, Google, consent, connection and native generations, the exact history revision and the exact shared operation. Conflicting definitions stay in the ordinary cycle report.
Link to existing account is offered only when every portable connection field matches exactly, using the import-time comparison. It maps the native account to the shared UUID, keeps its mail, credentials, reconnect state and identity, and records the shared definition with its original optional fields as the common basis, so no connection is republished. As at import, this device's account name is then shared. Add as a new account creates a fresh reconnecting native identity, as the loop would have done. Keep this device's account local records durable suppression of the shared UUID without mapping or changing the native account; later local edits stay local. An address-only match, or a match on a different protocol or server, never offers Link, so no message UID or password can be redirected. Every choice is one cache transaction with no shared-history admission; restart reads the saved result and never duplicates accounts. Stale native, Google, option, history or already-decided identities reject the choice with a refresh message.
Shared account removal is reviewed separately from endpoint choices. Keep on this device records durable suppression while preserving that account, cached mail and keychain identity. Later local edits remain local. Review removal opens the normal local-data confirmation, including draft and unfinished-work checks; Cancel leaves everything intact. A confirmed local removal clears stale review controls and does not delete server mail or publish a shared removal.
Keep decisions validate the selected profile, sync consent, Google lifecycle,
native connection revision and exact reviewed remote history before committing.
No cloud tombstone is inferred from removing an account only on this device.
Global account removal remains a separate follow-up. The saved native profile_account_removal
scenarios cover Keep, Cancel, confirmed removal and restart; Rust fixtures retain
actual cached mail through remote removal and reject stale choices.