The defect
ApiService.getLibraries() and getLibraryItems() return emptyList() on every failure path: non-2xx response, null body, and any thrown exception (timeout, parse failure). SyncManager.syncLibraries() then swallows exceptions with no logging.
The result is that four different situations produce one identical observable outcome, a blank shelf with nothing in the log:
- the server returned an HTTP error
- the request timed out
- the response failed to parse
- the library genuinely has no books
A user reporting "my shelf will not sync" cannot be told which one they hit, and neither can the log.
A second, user-facing variant: getLibraryItems paginates 100 items at a time and breaks out of the loop on a failed page. A fetch that dies on page 3 saves the first 200 books and reports complete success, so a silently truncated shelf looks like a complete one.
Why it matters beyond logging
The home screen's recently-played query is not scoped to a library, while the library grid is. Progress sync fetches in-progress items individually and succeeds cheaply. So when the library fetch fails, the user sees exactly the books they are partway through and nothing else, with no error anywhere. That is a confusing failure to be on the receiving end of and an unanswerable one to receive as a bug report.
Work already done
Branch diagnostics/sync-visibility (local, not pushed), commit 2eba33e:
RemoteResult with Ok / Partial / Failed, replacing the empty-list return, with logging on each failure branch. Partial covers the truncated-pagination case.
SyncManager records what the last sync produced, with counts and failure reason kept separate so an empty shelf never reads as a failure.
- The in-app bug report body gains: app mode, selected library id, stored library and book counts (total, and within the selected library), and the last sync result.
25 new tests, 448 green. Verified on device: the report body renders the new fields correctly in Local mode.
Remaining
The defect
ApiService.getLibraries()andgetLibraryItems()returnemptyList()on every failure path: non-2xx response, null body, and any thrown exception (timeout, parse failure).SyncManager.syncLibraries()then swallows exceptions with no logging.The result is that four different situations produce one identical observable outcome, a blank shelf with nothing in the log:
A user reporting "my shelf will not sync" cannot be told which one they hit, and neither can the log.
A second, user-facing variant:
getLibraryItemspaginates 100 items at a time andbreaks out of the loop on a failed page. A fetch that dies on page 3 saves the first 200 books and reports complete success, so a silently truncated shelf looks like a complete one.Why it matters beyond logging
The home screen's recently-played query is not scoped to a library, while the library grid is. Progress sync fetches in-progress items individually and succeeds cheaply. So when the library fetch fails, the user sees exactly the books they are partway through and nothing else, with no error anywhere. That is a confusing failure to be on the receiving end of and an unanswerable one to receive as a bug report.
Work already done
Branch
diagnostics/sync-visibility(local, not pushed), commit 2eba33e:RemoteResultwithOk/Partial/Failed, replacing the empty-list return, with logging on each failure branch.Partialcovers the truncated-pagination case.SyncManagerrecords what the last sync produced, with counts and failure reason kept separate so an empty shelf never reads as a failure.25 new tests, 448 green. Verified on device: the report body renders the new fields correctly in Local mode.
Remaining
syncLibrariesgained aCancellationExceptionrethrow that is not test-backed. The same broadcatch (Exception)still sits insideApiServiceand was deliberately left alone.