Both directions synced data but rendered nothing:
- Web reader <- devices: highlights painted no overlay. Device pushes
resolve their start xpointer exactly (text-search anchored by the
selection) but the end conversion carries no context and fell back
to a document-start CFI (epubcfi .../1:0) — a garbage range end.
When the start resolved exactly, the end is now derived from it:
same node, character offset advanced by the selection's UTF-16
length (extendCFIByLength). Same repair when SERVING to devices,
where old web highlights (no end anchor) and converted range CFIs
both collapsed pos1 onto pos0 (extendXPointerByLength on the
xpointer form) — KOReader drew zero-width highlights.
- Colors: KOReader paints from a fixed name set (Blitbuffer
HIGHLIGHT_COLORS), the web uses hex swatches; neither understood
the other, so device colors fell back to defaults and web hex drew
nothing useful on devices. Both boundaries now translate: ingest
maps names to hex (default #ffd54f), GetMetadata maps hex to names
(default yellow) — per-datatype edits re-push with the editing
side's color, which LWW then propagates. SyncBookmarks endpoint
aligned to the same mapping and default.