# Boot loading contract The initial HTML owns the **only full-screen loading UI**. Its spinner stays centered and turning, including with reduced motion enabled. The short status below it changes to reflect the blocking stage (account restoration, repository, vault, search wiring, tabs, note, plugins) without changing the screen. The application mounts behind this surface, invisible and inert, so its intermediate empty/editor-loading states cannot flash. Startup errors before React mounts replace the boot surface with a retry message. ## Inventory and ownership These are the boot checkpoints, not twelve separate screens. Entries marked “background” do not block the first usable view. | Checkpoint | Owner | Completion / behavior | | --- | --- | --- | | 1. HTML and entry bundle | `index.html`, `src/entries/*` | Boot surface exists before JS; failed module load changes its message. | | 2. Edition modules and classic WASM | `src/editions/*` | Load editor/runtime code; classic initializes subduction WASM. | | 3. Account restoration (ATProto) | `src/atproto/account.ts` | Complete pending OAuth callback or restore session, then select/create vault. Signed-out users use a local space. | | 4. Repository/space (ATProto) | `src/atproto/native-repo.ts` | Open remote or local space; remote initial sync and root discovery finish before the app runtime is built. | | 5. Runtime and root URL | `src/app/app-runtime.ts` | Construct document manager, vault index, workspace and plugin host. | | 6. Root validation and vault hydration | `src/App.tsx`, `src/plugin/vault.ts` | Validate root, hydrate file index. A bad root triggers a reload with the new root. | | 7. Search wiring | `src/services/SearchContext.tsx` | Start indexer wiring; full indexing is **background**. | | 8. Saved tabs | `src/App.tsx` | Await `workspace.restoreLayout` so leaves settle before routing. | | 9. Initial URL | `src/App.tsx` | Route the original hash after restoration; notify on invalid/unreachable URLs. | | 10. Fallback note | `src/App.tsx` | If no leaf remains, open an existing note or create/open Welcome; seed its optional image without blocking the view. | | 11. Plugins and sidebars | `src/layout/AppShell.tsx` | Enable built-ins and stored plugins, restore sidebar leaves, signal layout ready. | | 12. First view | `src/plugin/views/markdown-leaf-binding.tsx`, `src/layout/MainAreaViewContainer.tsx` | Wait for the active CM6 editor binding or a document error; a non-Markdown view is ready when mounted, or an empty workspace when no leaves remain. Readiness belongs to the current leaf, view and file. | Once checkpoints 11 and 12 complete, `onReady` in `src/app/mount.tsx` removes the original boot DOM and reveals the app in one handoff. Loading a different note *after* startup remains a local editor operation, and search discovery/derived indexing continues in the background. Failure to start the vault or an individual plugin is currently logged and treated as degraded operation, as before; an individual note load error is shown in its view. React render and commit-lifecycle exceptions replace the boot screen with a retry action; event handlers and rejected asynchronous work have their own error handling. The HTML starts with “Loading application…” before JavaScript runs. Editions report account/repository preparation, `App` reports vault/search/tabs/note, and `AppShell` reports plugin activation and the final first-view wait via the typed `BootStage` labels in `src/app/boot-stages.ts`. Only the initial loader reads these updates; later document loads keep their local view states. ## Previous surfaces removed from startup - `index.html` already displayed “Opening Reams…”; React used to replace it. - `src/App.tsx` displayed a separate full-height vault “Opening Reams…” page. - `src/App.tsx` then displayed a second, smaller workspace “Opening Reams…” page or exposed the shell early when a leaf appeared before restoration completed. - `src/layout/MainAreaViewContainer.tsx` could show “Open a document to start editing” while the initial leaf was still in flight. - `src/plugin/views/markdown-leaf-binding.tsx` could show “Loading document...” before the initial editor was bound. - Built-in and stored plugins could add sidebar views after the shell appeared. The latter local placeholders still serve later document switches; the boot handoff now waits for their first settled view. UI for account sign-in, settings, file search previews, and background indexing is interaction-scoped and does not take over the boot screen. ## Ownership review Boot is a **projection of existing lifecycles**, not a second account, vault, or workspace. The account snapshot and repository own identity and data availability; Vault/FileIndex owns hydrated files; SearchProvider owns indexer wiring; Workspace owns leaves and view selection; PluginLoader owns plugin states; the Markdown binding owns CM6 attachment. The boot callback in `src/app/mount.tsx` only changes the text of the one HTML screen and removes that screen at handoff. It stores no account or document data. The React gates (`vaultReady`, `searchInitialized`, `initialized`, `pluginsReady`, `readyView`) are **ephemeral completion signals** for those owners. `readyView` is tied to the currently selected workspace leaf/view and file identity rather than a persistent "document loaded" record. PluginLoader's in-flight enable promise and import cancellation belong to its plugin lifecycle and protect both StrictMode replay and real remounts; they are not boot stages. `BootStage` values are presentation labels emitted as work starts, not a state machine that drives work. ATProto repository code reports the semantic account-restored milestone; the edition translates it into a UI label. If an initialization or React rendering failure prevents handoff, the same surface becomes an error with Retry. It includes the last visible step and the exception message so a repeated failure can be distinguished from a new loading phase. Those are diagnostic clues, not a replacement for the browser console stack; restoring a signed-in account still depends on its own runtime.