Files
claude d1a73a1193 Wave 2: data layer (C) + metadata/scanning (D)
Room entities/DAOs/DB, PocketBase Retrofit client + auth interceptor, SyncEngine
(push-then-pull, LWW, tombstones, client-generated ids), SettingsStore, AppContainer.
Open Library + Google Books merge, ISBN validation, CameraX + ML Kit scanner plumbing.

Verified by orchestrator: assembleDebug exit 0; testDebugUnitTest exit 0, 68 tests,
0 failures, 0 errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bThmkmyUUdqQpy3MXFFe5
2026-09-06 03:24:04 +00:00

68 lines
4.0 KiB
Plaintext

You are Worker D on the Bookshelf project (~/bookshelf). Implement BOOK METADATA
LOOKUP + BARCODE SCANNING.
FIRST, READ THESE — they are the contract, follow them exactly, do not invent
alternative names or restate them back to me:
~/bookshelf/docs/SPEC.md (authoritative product/technical spec — see the
"Book metadata lookup" and "Barcode scanning"
sections especially)
~/bookshelf/docs/HANDOFF.md (operational state and gotchas already paid for)
## Your scope — these packages ONLY, under app/app/src/main/java/org/modg/bookshelf/
data.metadata
- IsbnUtils: ISBN-13 checksum validation, ISBN-10 -> 13 conversion,
normalization (strip hyphens/spaces, handle trailing X)
- OpenLibraryClient and GoogleBooksClient (Retrofit or OkHttp + kotlinx-
serialization; endpoints are in SPEC)
- BookMetadata (source-agnostic result model) and MetadataMerger implementing
SPEC's merge rule: prefer whichever has a title, fill blanks from the other,
return null if both miss
- MetadataRepository: the single entry point, `suspend fun lookup(isbn): BookMetadata?`
ui.scan — SCANNER PLUMBING ONLY, no finished screen (wave 3 builds the screen):
- a CameraX ImageAnalysis analyzer wrapping ML Kit BarcodeScanning
(EAN_13, EAN_8, UPC_A), validating the ISBN-13 checksum before emitting,
debouncing repeat reads of the same code
- a small stateful holder exposing scan results as a Flow, plus torch toggle
and camera-permission-denied states
## HARD BOUNDARIES — you share this repo with Worker C, running right now
- DO NOT create or edit anything under `data.local`, `data.remote`, `data.repo`,
`data.prefs`, `AppContainer`, or `BookshelfApplication.kt`. Those are Worker C's.
Touching them WILL cause a conflict.
- DO NOT edit any `ui.theme` or `ui.components` file — wave 1B finished those and
they are verified green. Reuse them; do not modify them.
- DO NOT edit `app/build.gradle.kts` or `gradle/libs.versions.toml`. Everything
you need (camerax core/camera2/lifecycle/view, mlkit barcode-scanning, retrofit,
kotlinx-serialization, okhttp, coroutines-test, robolectric) is ALREADY declared
and wired. If you think something is missing, DO NOT add it — report it instead.
- Your MetadataRepository must be a plain class with an explicit constructor
(e.g. taking OkHttpClient/Json). Do NOT wire it into AppContainer — Worker C owns
that file. In your final report, give the exact one-line wiring snippet needed.
## Build/verify — CRITICAL
Never run `./gradlew` directly; a second worker builds concurrently and you will
corrupt each other's build. ALWAYS build with the serialized wrapper:
~/bookshelf/tasks/gw assembleDebug
~/bookshelf/tasks/gw testDebugUnitTest
It takes the lock and may block until the other worker's build finishes. That is
expected — wait for it, do not bypass it.
## Definition of done — all must actually pass, verified by you, not assumed
1. `~/bookshelf/tasks/gw assembleDebug` exits 0.
2. `~/bookshelf/tasks/gw testDebugUnitTest` exits 0.
3. Real unit tests with real assertions (SPEC: "Do not write assertion-free tests"):
- ISBN-13 checksum: known-valid and known-invalid ISBNs, ISBN-10 conversion,
hyphen/space handling
- MetadataMerger: OL-only, GB-only, both, neither(-> null), and blank-filling
- client JSON parsing against CHECKED-IN SAMPLE JSON FIXTURES, not live network.
Tests must pass offline with no network access.
4. Network code must never be called on the main thread and must fail soft
(return null / empty) rather than throw on timeout or malformed JSON.
## Report back (keep it short — it is read by a token-constrained orchestrator)
- exact pass/fail of the two gradle commands above
- files created, one line each
- the one-line AppContainer wiring snippet for MetadataRepository
- anything in SPEC.md you could NOT satisfy, and why. Do not paper over gaps:
a truthfully reported gap is worth more than a false green.