Skip to content

feat(rag): Ask this book — on-demand indexing P2 (user-uploaded books)#384

Merged
mrviduus merged 1 commit into
mainfrom
rag-ondemand-p2-userbooks
Jun 19, 2026
Merged

feat(rag): Ask this book — on-demand indexing P2 (user-uploaded books)#384
mrviduus merged 1 commit into
mainfrom
rag-ondemand-p2-userbooks

Conversation

@mrviduus

Copy link
Copy Markdown
Owner

Extends "Ask this book" to user-uploaded books — the priority (users read their own uploads; the button was previously hidden for mode==='userbook').

Per-user isolation is a hard requirement and was the QA focus:

  • New isolated user_chapter_chunk table (NOT polymorphic with catalog chapter_chunk), denormalized user_id + user_book_id; every retrieval SQL branch (vector NN + lexical FTS) filters on both. Owner-scoped endpoints 404 for a foreign id (no existence leak). FK cascade purges chunks when a book is deleted.
  • UserBook gains rag_* fields; BookChunkingService.ChunkUserBookAsync; ChapterEmbeddingWorker second poll on the same OpenAI drain; IRagService.RetrieveUserBookAsync (shared RRF helper). No spoiler gate for user books (full-book retrieval over your own doc).
  • POST/GET /me/books/{id}/index + POST /me/books/{id}/ask; GET /me/books/{id} detail gains ragStatus/counts. Migration AddUserBookRagIndex.
  • Web: askTarget abstraction routes userbook → /me/books/{id}/...; catalog path unchanged.

architect → backend + frontend → adversarial QA on isolation (verdict SHIP) — both SQL branches scope to the owner, no cross-corpus union, P3 DELETE owner-scope applied. 855 unit + 559 web tests green; solution + web build clean.

🤖 Generated with Claude Code

Extends Ask to user-uploaded books (the priority — users read their own uploads).
Per-user ISOLATION is a hard requirement.

- New ISOLATED user_chapter_chunk table (NOT polymorphic), denormalized user_id +
  user_book_id; retrieval filters BOTH in every SQL branch (vector + lexical).
- UserBook gains rag_* fields; BookChunkingService.ChunkUserBookAsync; worker
  second poll over user_chapter_chunk on the SAME OpenAI drain, flips Ready.
- IRagService.RetrieveUserBookAsync (shared RRF helper, byte-identical fusion).
- UserBookRagContextService: NO spoiler gate (your own doc -> full-book retrieval).
- Owner-scoped POST/GET /me/books/{id}/index + POST /me/books/{id}/ask (404 non-owner).
  Atomic claim WHERE user_id=@uid; clears chunks (filtered by user_id too) before
  re-chunk; rate-limited.
- GET /me/books/{id} detail gains ragStatus/counts.
- Web: askTarget abstraction unhides Ask for mode=userbook -> /me/books/{id}/...;
  catalog path unchanged.
- Migration AddUserBookRagIndex (user_chapter_chunk + HNSW/GIN/(user_id,user_book_id)
  + cascade FKs from user_books AND user_chapters).

architect -> backend+frontend -> adversarial QA on ISOLATION (verdict SHIP; both
SQL branches filter user_id+user_book_id, owner-404, FK-cascade purge, no cross-
corpus; P3 DELETE owner-scope applied). 855 unit + 559 web green; build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mrviduus mrviduus merged commit 6a682db into main Jun 19, 2026
5 checks passed
@mrviduus mrviduus deleted the rag-ondemand-p2-userbooks branch June 19, 2026 06:08
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