Improve Literal import fidelity: infer read + carry the added date - #515
Merged
Merged
Conversation
Two mapping fixes so imported books reflect the real library: - Infer `read` for a book Literal reports as unshelved (`NONE` → null) that has a rating or review — a review means it was read, so it shouldn't import as "Not tracked" (with the rating/review orphaned). Shelved books keep their real status; an inferred-read book takes its finish date from the review. - Carry Literal's shelf-added date onto the item's `createdAt`, so imported books sit at their true place in the timeline instead of all at import time. Safe: no account-scoped logic reads item.createdAt (only sort/sweep ordering). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
All reported issues were addressed across 9 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Strengthen the rating-only inferred-read test to assert finishedAt is taken from the review's createdAt (distinct from the shelf date), covering the stated behaviour. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
addedAt is the date an item entered the library — equals createdAt for items captured in abode, but imports back-date it to the source's own "added" date so imported items slot into their historical place. createdAt stays the truthful row-creation time. Migration adds added_at (default now()) then backfills existing rows from created_at so their timeline position is preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The importer now sets addedAt to the source's added date (Literal's reading-state createdAt) instead of overloading the item's createdAt. createdAt reverts to the truthful row-creation time. Falls back to the column default (now) when the source has no added date. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dashboard now sorts by addedAt (keyset cursor + orderBy in the items API and SSR first page) and the item card's "Saved" label reads addedAt, so back-dated imports appear in their historical place. The shared cursor codec keys on addedAt. Search exposes added_at on its results for the same card display. For non-import items addedAt equals createdAt, so existing items are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the library-timeline ordering into a single ITEM_TIMELINE_ORDER_BY constant plus itemTimelineCursorWhere/itemTimelineCursor helpers in query.ts, and route both the items API and the dashboard SSR first page through them. Previously the orderBy and keyset cursor were hand-copied across three places, any of which could silently revert to createdAt. Add an integration test that inserts items with createdAt and addedAt deliberately inverted and asserts the listing (and cursor keyset) follow addedAt — so a regression back to createdAt fails regardless of how the query is written. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 14 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
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.
What & why
Literal→abode mapping fidelity so imported books reflect the real library, plus a dedicated column and guardrail for the "added" date so it's honest and can't silently regress (backend: adapter + writer + timeline read path).
Infer
readfor reviewed-but-unshelved books. Literal reports some books asNONE(unshelved) while still keeping a rating/review on them (e.g. Wild at Heart — 4.5★ + a review, statusNONE). We mappedNONE → null("Not tracked") while the rating/review imported from a separate query — so they landed as untracked books with an orphaned rating/review. A review means the book was read, so we now inferreadwhen aNONE/unshelved book has a rating or review (and take its finish date from the review). Books already on a shelf keep their real status; a mid-read review still staysreading.Carry the Literal added date via a dedicated
addedAtcolumn. Imported books record Literal's shelf-added date in a newItem.addedAtcolumn, and the dashboard timeline sorts (and the item card's "Saved" label reads) byaddedAt— so imports sit at their true place in the timeline instead of piling at import time.addedAtequalscreatedAtfor everything captured in abode (existing rows are backfilled), so only back-dated imports move;createdAtstays the truthful row-creation time. Includes a migration that addsadded_at(defaultnow()) and backfills existing rows fromcreated_at.Guardrail against regressing the sort. The timeline ordering and keyset cursor are centralized in one
ITEM_TIMELINE_ORDER_BYconstant (+itemTimelineCursorWhere/itemTimelineCursorhelpers) used by both the items API and the dashboard SSR page — previously three hand-copied blocks, any of which could revert tocreatedAt. An integration test inserts items withcreatedAt/addedAtdeliberately inverted and asserts the listing and cursor keyset followaddedAt, so a regression back tocreatedAtfails regardless of how the query is written.Checklist
captureServerException, or N/A — N/ANotes
kind=book+meta.importSource="literal"for the user is the clean way).Item.addedAtand backfills existing rows tocreated_at; runs on deploy.🤖 Generated with Claude Code