=== L-search attempts=1 quota_waits=0 hard_fails=0 === cost=$10.452535 turns=157 err=? --- result (tail) --- ange, verified by the untouched `RetryPolicyTest` still passing. - **"Retry" re-runs both sources**, not just the failed one. The spec's "while still showing the OTHER source's results" is satisfied by the *resting* UI state (a failure line next to the other source's live results), but tapping Retry re-submits the whole query rather than re-querying only the failed source. A per-source-only retry would need to retain raw hit lists per source across a partial re-fetch; I judged the added state-machine complexity wasn't worth it for this pass. - **In-flight cancellation doesn't abort the underlying OkHttp call** — cancelling the ViewModel job discards the result but the blocking `.execute()` call finishes on its IO thread regardless (same limitation the existing ISBN-lookup clients already have; not something new). - **"In your library" section uses a horizontally-scrolling row of the existing card**, not a full grid, to avoid nesting a scrollable grid inside the outer vertically-scrolling search-results column (a real Compose layout hazard). "Online" results are a plain (non-lazy) `Column` of rows for the same reason — acceptable given result counts are capped at ~20/source before dedupe. ### Out of scope / noticed but not touched - The pre-existing Paparazzi rendering quirk where the search/filter/sort toolbar row renders as a thin unlabeled bar (visible in both the old `library-populated` and my new search-results screenshots) — confirmed pre-existing by comparing against the baseline `library-populated-light.png`, not something I introduced or was asked to fix. - `BookDao.search`/`BookRepository.search` are now unused by the library screen but left in place — not deleted, since the task only authorized touching them if I chose the SQL route, which I didn't.