# 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.