feat(tomesync): builds 32+33 — clock-offset guard, pull strategy, state file, device search, author axis, status write-back#122
Merged
Conversation
…ate file (build 32) Tier-3 of the teardown adoption arc: the three S-sized correctness/hygiene gaps, as one plugin build. Clock-offset guard (the silent highlight-swallowing class): - Web create/edit/delete stamp LWW keys with the SERVER clock; on a device whose clock runs behind, those stamps sit in the device's future and outrank every later local change (a re-highlight after a web delete just vanished until the clocks crossed). - The plugin now stamps device_time on annotation syncs; the server marks stamps it minted itself (server_minted, additive columns on annotations + annotation_tombstones) and shifts exactly those into the requesting device's clock frame — in the tombstone/LWW comparisons and in the response. Device-minted stamps pass through verbatim (cross-device skew stays the documented accepted edge). A device upsert winning a row clears the flag; bumped web-edit stamps inherit the frame they were bumped from. - Device side: future stamps are scrubbed from local annotations + baseline before diffing (annotation and baseline clamped to the same value, so no spurious re-push), and incoming stamps are clamped to the device clock before compare/store. Old plugins keep the previous behavior. Pull-conflict strategy (kosync muscle memory): - "Server position is ahead" / "Server position is behind" settings, each prompt / silent / never. Defaults preserve historic behavior (forward silent, backward never). The prompt is deferred 1.5s off the open path — a ConfirmBox at open time would eat the Profiles auto-exec dispatch exactly like the InfoMessage layout-reset bug. Jump mechanics extracted to _gotoServerPosition (shared by silent + prompt, xpointer-shape guard intact). Dedicated state file: - The seven data tables (book_map, pending_sessions, adopt_pending, repair_map, annot_baseline, rating_baseline, pending_ratings) move out of G_reader_settings — which KOReader parses at every boot and which these tables bloat unboundedly — into settings/tomesync_state.lua (write-through LuaSettings). Migration is crash-safe (new file flushed before old keys deleted; marker branch re-deletes leftovers). Per-book state is pruned for books no longer on disk; pending queues are never pruned (owed to the server); baseline pruning is delete-safe by construction. tomesync_update stays in G_reader_settings — the frozen shim reads it. Verification: 868 tests green (10 new server clock-offset tests, 12 new impl contract tests; two legacy contract tests updated to the new storage location). Emulator round-trip on the showcase: real pre-existing state migrated (6 keys moved, global file cleaned, dead paths pruned), both settings submenus render with correct defaults, annotation sync round-trips 200 with device_time/server_time. luajit-compile check in CI via test_impl_compiles_under_luajit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ite-back (build 33)
The three M-sized catalog gaps from the teardown, as one plugin build.
Search from the device:
- "Search library…" atop the series browser: submit-based InputDialog (the
right call on e-ink) with the last searches one tap away; results land in
the shared drill-down list. Server: GET /tome-sync/search?q= — LIKE terms
over title/author/series (all must match), visibility-gated, capped at 50
with the true total reported.
Author browse axis:
- "Browse by author" — the natural way into standalone books, which the
series browser lumps into one No Series bucket. GET /tome-sync/authors
(+ __unknown__ bucket) and /tome-sync/author-books?author= (query param:
author names contain slashes). Mixed lists prefix rows with each book's
own series and file downloads by the book's own identity — a book with a
series lands under it, standalones under book-type/author, same as the
No Series flow.
Read-status write-back:
- Hold any book row (series/author/search list) → unread/reading/read via
PUT /tome-sync/status/{book_id}. A deliberate user action, so it writes
status directly — unlike telemetry, which only ever suggests status via
the sticky rule. Lists show "· reading/read" markers next to the existing
on-device marker (book entries now carry per-user status; additive).
Plus the series N+1 fix: /tome-sync/series ran one first-book query per
series; now a single ordered query with an unchanged response shape. The
volume-list serializer is shared (_book_entry) across series/author/search.
Verification: 877 tests green (9 new endpoint tests incl. visibility +
status upsert + the 50-cap). Emulator round-trip on the showcase: search
"good guys" → 16 series-prefixed results with real status markers; status
dialog PUT → 200 and the DB row flips; authors menu renders with correct
counts. luajit compile check green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Owner
Author
|
Closed pending hands-on testing — opened prematurely; will reopen once the branch is verified on dev/emulator. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two sequential plugin builds from the teardown adoption arc, stacked because plugin builds are monotonic.
Build 32 — hygiene batch (
b18aa3d)device_timeon annotation syncs; the server marks the stamps it minted itself (server_minted, additive columns) and shifts exactly those into the requesting device's frame — in comparisons and responses. Device side scrubs/clamps future stamps. Cross-device skew stays the documented accepted edge; old plugins keep prior behavior.G_reader_settings(parsed by KOReader every boot, growing with the library) intotomesync_state.lua, with a crash-safe migration and pruning for books no longer on disk.tomesync_updatestays global — the frozen shim reads it.Build 33 — catalog batch (
92f564c)GET /tome-sync/search(LIKE terms over title/author/series, visibility-gated, capped at 50 with true total).PUT /tome-sync/status/{id}; lists show status markers next to the on-device marker./tome-sync/seriesran one first-book query per series; now a single ordered query, same response shape.Verification