docs/adr/0087-status-first-startup.md

ADR 0087: Status-first startup

Status: Implementation candidate.

Decision

Start authenticated GET /api/bootstrap and the existing full /api/state request together. Bootstrap returns accounts without credentials, configuration, compose preferences, draft count/token and CSRF. It omits mail, mail cursors, arrival records and arrival counters. It reuses the status builder used at the full snapshot boundary, behind the existing API authentication/origin checks. It never initializes the mail index, scans mail or decrypts mail/draft bodies.

The renderer distinguishes status readiness from complete mail loading. Apply CSRF before enabling account/configuration controls or requesting the workspace. Preserve the full initial snapshot and subsequent delta/removal cursor protocol. A late bootstrap cannot overwrite full state, including after a failed full read. Bootstrap failure or an older service falls back to the existing full request.

Until full mail arrives, keep mail counts unavailable, lists loading and mail source-dependent work details gated. Workspace reads may prefetch, but missing sources must not be presented as absent from the cache. Draft count comes from the independent complete draft inventory. Do not start the existing automatic sync earlier than the full snapshot. The desktop event path remains unchanged. Bootstrap does not replace browser focus/visibility refresh.

Full-read failure offers an explicit retry. Authentication failure clears status readiness, cached renderer state, CSRF and the cursor, without deleting drafts or changing a compose session. Abort startup reads on unmount and ignore late completions. Keep reload coalescing. No storage, key, provider, gzip or paging change is part of this decision. Older clients keep their full-state contract.

Verification

server/bootstrap.test.ts uses an ephemeral synthetic service with corrupt mail ciphertext and blocks mail-index SQL. It checks authenticated no-store status, origin rejection, credential omission, no mail/cursor/arrival fields, draft preservation and unchanged snapshot/delta behavior.

src/bootstrap.test.tsx mounts App with deferred responses. Cover both response orders, status CSRF readiness, unknown counts, no false empty/source results, older-service fallback, failed full read and retry, authentication reset before and after status, desktop cursor refresh and unmount cancellation. Existing App mail, drafts, search, navigation and notification checks remain applicable.

scripts/benchmark-bootstrap.ts creates and removes its own synthetic profile and uses the 34,000-message, four-account fixture. Three serial pairs compare status availability from full-state-only startup with parallel bootstrap/full requests, each in a fresh process. Record bootstrap bytes/time and full-mail bytes/time separately. Module/service startup is reported separately. OS caches are not flushed. HTTP/JSON availability is not browser paint or installed-app performance proof. Runtime receipts and integration diffs stay outside the repo.