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.htmlalready displayed “Opening Reams…”; React used to replace it.src/App.tsxdisplayed a separate full-height vault “Opening Reams…” page.src/App.tsxthen displayed a second, smaller workspace “Opening Reams…” page or exposed the shell early when a leaf appeared before restoration completed.src/layout/MainAreaViewContainer.tsxcould show “Open a document to start editing” while the initial leaf was still in flight.src/plugin/views/markdown-leaf-binding.tsxcould 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.