Skip to content

feat(rag): Ask this book on mobile — user books + on-demand index (AI-027 mobile)#390

Merged
mrviduus merged 1 commit into
mainfrom
feat/mobile-ask-this-book
Jun 23, 2026
Merged

feat(rag): Ask this book on mobile — user books + on-demand index (AI-027 mobile)#390
mrviduus merged 1 commit into
mainfrom
feat/mobile-ask-this-book

Conversation

@mrviduus

Copy link
Copy Markdown
Owner

Makes "Ask this book" actually work in the mobile app (PM → architect → engineer → adversarial QA → fix cycle). Scope B1+B2; streaming + multi-turn are a follow-up.

Why

The mobile AskSheet was wired for catalog editions only, and even there it looked broken because nothing triggered on-demand indexing (the catalog has 0 chunks). On the user's own uploaded books — the priority surface — the Ask button didn't render at all (explainBookId is undefined for user books). This closes both gaps.

What

  • User-book Ask (priority). AskSheet now takes an AskTarget {kind:'edition'|'userbook', id} and routes POST /books/{id}/ask vs POST /me/books/{id}/ask. The user-book reader source sets the target with the user-book id; showAsk is true for both kinds. Explain wiring untouched.
  • On-demand index gating. On open: GET …/index → if not Ready, POST …/index then poll, showing an "Indexing this book…" state; the composer enables only when Ready. A fresh upload / 0-chunk catalog book no longer returns a confusing "couldn't find this in the book."
  • Robustness (from QA): poll stops and shows the sign-in CTA on a real 401 (no silent 5-min spin); a stall-based timeout (90s with no forward progress in embeddedCount) replaces the flat 5-min cap, so large books keep indexing while they advance but a genuinely stuck job still fails.
  • JSON one-shot answers this slice (SSE streaming via expo/fetch + multi-turn/starters = next slice).

Contract / safety

  • Shared packages/shared/src/api/rag.ts is additive — catalog ask(editionId, …) signature unchanged; web has its own ask.ts and imports only shared types, so no web regression. Index status strings (NotIndexed|Indexing|Ready|Failed) and BookIndexStatusDto verified byte-for-byte against the backend.
  • AbortController cancels in-flight ask on close; polling cleaned up on unmount.

Verification

  • apps/mobile tsc --noEmit clean; packages/shared vitest 149 green; web tsc unaffected.
  • Adversarial QA confirmed the user-book wiring (the priority) and contract match.
  • On-device validation owed: real upload → prepare → Ready → grounded answer + citation jump; large-book indexing past 5 min keeps going; 401 mid-poll → sign-in.

CHANGELOG updated (AI-027 mobile).

🤖 Generated with Claude Code

…-027 mobile)

Wire "Ask this book" into the mobile reader for BOTH catalog editions and the
user's OWN uploaded books (previously hidden — explainBookId undefined on user
books, contradicting user-books-first). AskSheet takes an AskTarget {kind,id};
routes catalog /books/{id}/ask vs user /me/books/{id}/ask. On-demand index
gating: GET status -> prepare -> poll until Ready, with "Indexing…" state, so a
0-chunk/fresh book no longer looks broken. JSON one-shot (streaming = follow-up).

Robustness: stop polling + show sign-in on 401 (no silent spin); stall-based
timeout (90s no forward progress) instead of a flat 5min cap so large books keep
indexing while advancing. Shared rag.ts additive (catalog ask() unchanged; web
unaffected). 149 shared tests green, mobile tsc clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mrviduus mrviduus merged commit bb38faa into main Jun 23, 2026
5 checks passed
@mrviduus mrviduus deleted the feat/mobile-ask-this-book branch June 23, 2026 02:29
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