Skip to content

feat(tomesync): library sweep — adopt closed books (build 34)#125

Merged
bndct-devops merged 1 commit into
mainfrom
feat/tomesync-sweep
Jul 5, 2026
Merged

feat(tomesync): library sweep — adopt closed books (build 34)#125
bndct-devops merged 1 commit into
mainfrom
feat/tomesync-sweep

Conversation

@bndct-devops

Copy link
Copy Markdown
Owner

The last teardown item, unblocked by build 27's hash matching: a "Sync closed books" menu action that adopts state from books TomeSync has never synced — read before Tome existed, sideloaded, or opened under another launcher.

Plugin (build 34)

  • Walks the home folder for supported books not in book_map that have a sidecar; mtime-gated against an ack-gated ledger (tomesync_sweep in the state file) — interrupting loses nothing, and re-runs only touch books whose sidecar changed. Chunked (5/tick) off the UI path; a server failure mid-run stops cleanly with honest counts.
  • Each chunk: util.partialMD5 per file → POST /tome-sync/match-hashes (batch) → matches enter book_map (a sweep match is a full resolve — positions, annotations and ratings all start working for that book) → the sidecar is read via DocSettings:open on the closed book and adopted: summary.status → read/reading, summary.rating/note, percent_finished, last_xpointer. "abandoned" stays unmapped; layout-only sidecars ledger as done.

Server

  • POST /tome-sync/match-hashes — batch partial-MD5 → book id (500/call), visibility-filtered: an invisible book is indistinguishable from an unmatched hash.
  • POST /tome-sync/sweep/{book_id}fill gaps only: status applies only over unread/absent (never downgrades curation), rating/review only when none exists, a position row only when none exists. A closed book's stale sidecar can never clobber live sync state. Returns exactly what was taken.

Verification

  • 918 tests green (13 new: batch matching + visibility, the fill-gap invariants incl. granular fills and idempotence, generated-impl contracts). luajit compile check green.
  • Emulator round-trip vs the showcase: an orphaned closed book with a crafted sidecar was hash-matched and adopted end-to-end (server rows: status=read, rating=4, review, 42% position); the visibility filter first correctly rejected a hash pointing at a nonexistent book id; an immediate re-run adopted nothing (ledger no-op).
  • Real-Kindle pass planned post-merge (also covers builds 32/33, which were emulator-only).

The last teardown item, unblocked by build 27's hash matching: a "Sync
closed books" menu action that adopts state from books TomeSync has never
synced (pre-Tome history, other launchers, sideloads).

Plugin:
- Walk home_dir for supported books not in book_map that have a sidecar;
  mtime-gated against an ack-gated ledger (tomesync_sweep in the state
  file), so interrupting loses nothing and re-runs only touch books whose
  sidecar changed. Chunked (5/tick) off the UI path via scheduleIn; a
  server failure mid-run stops cleanly with honest counts.
- Each chunk: util.partialMD5 per file → POST /tome-sync/match-hashes
  (batch) → matches enter book_map (a sweep match is a full resolve —
  positions/annotations/ratings all start working for that book) → adopt
  the sidecar via DocSettings:open on the CLOSED book (summary.status →
  read/reading, summary.rating/note, percent_finished, last_xpointer).
  "abandoned" stays unmapped; bare layout-only sidecars ledger as done.

Server:
- POST /tome-sync/match-hashes: batch partial-MD5 → book id (500 cap),
  visibility-filtered — an invisible book is indistinguishable from an
  unmatched hash.
- POST /tome-sync/sweep/{book_id}: FILL GAPS ONLY. Status applies only
  over unread/absent (never downgrades curation), rating/review only when
  none exists, position row only when none exists — a closed book's stale
  sidecar can never clobber live sync state. Returns what was actually
  taken. Sweep prune added to _pruneState.

Verification: 918 tests green (13 new: batch matching + visibility, the
fill-gap invariants incl. granular fills and idempotence, impl contracts).
Emulator round-trip vs the showcase: an orphaned closed book with a
crafted sidecar matched by hash and adopted end-to-end (status=read,
rating=4, review, 42% position on the server); the visibility filter
correctly rejected a hash pointing at a nonexistent book id first, and an
immediate re-run adopted nothing (ledger no-op). luajit compile green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bndct-devops bndct-devops merged commit a222427 into main Jul 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant