You are Worker E1 on the Bookshelf project (~/bookshelf). Wave 3, part 1: APP SHELL + SETUP + LOCATIONS + SETTINGS screens. FIRST, READ THESE — the contract. Follow exactly; do not invent alternative names, do not restate them back to me: ~/bookshelf/docs/SPEC.md (authoritative — see "Screens", "Design language") ~/bookshelf/docs/HANDOFF.md (operational state, gotchas already paid for) Waves 1-2 are DONE and verified green: theme + shared components (ui.theme, ui.components), the whole data layer (data.local/remote/repo/prefs, AppContainer), and metadata/scanning plumbing. REUSE them. Read `AppContainer.kt` and the repository classes to learn the real API before you write anything against them. ## Your scope ui.nav Routes.kt + BookshelfNavHost — the whole navigation graph, including routes to E2's screens (see the contract block below) ui.setup SetupScreen: server URL (https validation, trailing-slash strip, reachability probe), email, password. MUST distinguish "bad/unreachable URL" from "bad credentials" in its error text — SPEC calls this out. ui.locations LocationsScreen: bookcases -> shelves tree, CRUD + reorder, book counts per shelf, tap-a-shelf -> library filtered to it, "Move books" bulk action. ui.settings SettingsScreen: server, account, sign out, manual sync + last-sync time, book/cover counts. MainActivity: host BookshelfNavHost, pick the start route (setup vs library) based on whether a server URL + auth token already exist. ## HARD BOUNDARIES — Worker E2 is running RIGHT NOW in this same repo - DO NOT create or edit anything under ui.library, ui.detail, ui.scan. E2 owns those. You WILL reference E2's screen composables from BookshelfNavHost — that is expected; use exactly the signatures in the contract block and do not open those files. - DO NOT edit ui.theme or ui.components (wave 1B, verified green). Reuse, don't modify. - DO NOT edit `app/build.gradle.kts` or `gradle/libs.versions.toml`. Everything needed is already declared and wired. If you think something is missing, report it, do not add it. - Data layer: you MAY extend LocationRepository / ShelfDao / BookcaseDao (e.g. reorder, bulk-move helpers) if a screen genuinely needs it. You may NOT touch BookRepository or BookDao — E2 owns those. If you need a book-side query, report it instead. ## SHARED SCREEN CONTRACT — fixed by the orchestrator, IDENTICAL in both wave-3 ## prompts. Do NOT change these signatures. E1 writes BookshelfNavHost against them; ## E2 writes the screens to match. If you deviate, the other worker's code stops ## compiling and the wave fails. Routes (string constants live in ui/nav/Routes.kt, owned by E1): "setup" | "library" | "library?shelfId={shelfId}" | "detail/{bookId}" | "scan" | "locations" | "settings" Screen composable signatures: // E2 owns @Composable fun LibraryScreen( shelfIdFilter: String?, onBookClick: (String) -> Unit, onScanClick: () -> Unit, onLocationsClick: () -> Unit, onSettingsClick: () -> Unit, container: AppContainer, ) @Composable fun DetailScreen( bookId: String, onBack: () -> Unit, container: AppContainer, ) @Composable fun ScanScreen( onBack: () -> Unit, container: AppContainer, ) // E1 owns @Composable fun SetupScreen(onSetupComplete: () -> Unit, container: AppContainer) @Composable fun LocationsScreen( onBack: () -> Unit, onShelfClick: (String) -> Unit, // navigates to library?shelfId=... container: AppContainer, ) @Composable fun SettingsScreen( onBack: () -> Unit, onSignedOut: () -> Unit, // navigates back to "setup" container: AppContainer, ) All screens take `container: AppContainer` and construct their own ViewModel from it (manual DI per SPEC — NO Hilt). Package = ui., e.g. ui.library.LibraryScreen. ## Build/verify — CRITICAL Never run `./gradlew`; E2 builds concurrently and you will corrupt each other's build. ALWAYS use the serialized wrapper (it takes a lock and may block — wait for it): ~/bookshelf/tasks/gw assembleDebug ~/bookshelf/tasks/gw testDebugUnitTest ## Definition of done — verified by YOU, actually run, not assumed 1. `~/bookshelf/tasks/gw assembleDebug` exits 0. 2. `~/bookshelf/tasks/gw testDebugUnitTest` exits 0 with ZERO failures. There are 68 existing passing tests — you must not break any of them. 3. The app must behave per SPEC with NO server configured (lands on setup) and must not crash when the server is unreachable. Sync failure = a quiet status line, never a crash or a blocking dialog. 4. Every screen uses the wave-1B theme and components. Warm paper / mahogany / gold, Literata for titles. Do not introduce new colors or a second type scale. ## IMPORTANT — do not repeat Worker D's mistake A previous worker ended its turn saying "tests are running in the background, I'll report when done." That is a FAILURE. Run the commands, WAIT for them, and report real exit codes you actually observed. A truthfully reported gap is worth more than a false green; an unverified claim is worth less than nothing. ## Report back (short — read by a token-constrained orchestrator) - real exit codes of the two gradle commands, and the test failure count - files created, one line each - anything in SPEC.md you could NOT satisfy, and why