fix(rag): stop hard-deleting shared chunks; wire soft-delete cleanup#520
Open
abdulrafey1 wants to merge 13 commits into
Open
Conversation
Introduce HTTP-agnostic whitelist domain exceptions and register their type->status mappings in the API layer, dropping the inline try/except from the route handlers. The service now owns the IntegrityError race translation (rollback + log + re-raise). Closes #494.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
delete_by_source hard-deleted DocumentChunk rows by source_name, which would destroy chunks that other documents still share (chunks are deduped by content hash). It had no production callers and bypassed the reference-counted cleanup in sparkth/rag/cleanup.py, which is the sanctioned deletion path and already preserves shared chunks. Refs #456. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Soft-deletes a DriveFile and its linked Document so the RAG cleanup job can collect the file's orphaned chunks while preserving shared ones. Single home for the delete->cleanup wiring used by the file/folder delete paths. Refs #456. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deleting a drive file now soft-deletes its linked Document, so the RAG cleanup job collects the file's orphaned chunks instead of leaving them forever. Refs #456. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deleting a folder now soft-deletes each contained file's Document, so the RAG cleanup job collects their orphaned chunks. Refs #456. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When a file disappears from Drive during folder refresh, its Document is now soft-deleted alongside the DriveFile, so the RAG cleanup job collects its orphaned chunks. Completes the delete->cleanup wiring. Refs #456. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Strengthen test_delete_soft_deletes_linked_documents to seed two files with linked Documents so the delete loop's multi-file behavior is actually verified, matching the test's plural intent. Refs #456. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
abdulrafey1
force-pushed
the
rafey/migrate-permission-routes-to-central-exception-management
branch
from
July 10, 2026 09:18
e470e1c to
7d45971
Compare
hamza-56
approved these changes
Jul 12, 2026
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.
Closes: [RAG] ChunkStoreService.delete_by_source deletes chunk rows instead of only their links
What
Stop
delete_by_sourcefrom hard-deletingDocumentChunkrows shared across documents, and wire every Google Drive delete path to soft-delete its linkedDocumentso the reference-counted RAG cleanup job actually runs.Changes
delete_by_sourcechunk deletionsoft_delete_drive_filehelperBackground
ChunkStoreService.delete_by_sourceissuedDELETE FROM rag_document_chunks WHERE source_name = .... Because ingestion deduplicates chunks by content hash, oneDocumentChunkrow can be linked (viaDocumentChunkLink) to several documents — so hard-deleting on one document's removal would destroy chunks other documents still share. The method had no production callers and bypassed the sanctioned reference-counted cleanup insparkth/rag/cleanup.py.It was removed rather than rewritten: an inline unlink-only rewrite (as originally proposed on the issue) would instead leak orphaned chunks forever, because
cleanup.pyonly discovers chunks reachable through soft-deleted documents' links.The sanctioned path is soft-delete driven — soft-delete a
Document, and thecleanup_deleted_documentsjob removes that document's links and deletes only chunks with no remaining link to a live document (shared chunks preserved). That chain was dormant because the Google Drive delete routes soft-deleted theDriveFilebut never its linkedDocument. This PR adds one helper,soft_delete_drive_file, and routes all threeDriveFilesoft-delete sites (delete_file,delete_folder, folder-sync removal) through it. EachDriveFileowns its ownDocument, so soft-deleting the file's ownDocumentis safe — chunk sharing is ref-counted at the chunk-link level by the cleanup job.How to Test
make test.backend.pytest→ all pass (1369).uv run pytest tests/rag/test_cleanup.py sparkth/plugins/googledrive/tests/test_routes.py sparkth/plugins/googledrive/tests/test_utils.py -v→ green (shared-chunk survival + all three wired delete paths + helper unit tests).grep -rn "delete_by_source" sparkth/ tests/→ no matches.make mypy(strict, clean) andmake lint.backend(clean).Document+ chunks exist,DELETEthe file, confirmDocument.is_deletedbecomesTrue, then runmake rag-cleanup— the document's links are removed and only chunks with no remaining live-document link are deleted; a chunk shared with another live document survives.Notes
rafey/migrate-permission-routes-to-central-exception-managementand targets it (notmain); GitHub will auto-close [RAG] ChunkStoreService.delete_by_source deletes chunk rows instead of only their links #456 once the change reachesmain.ChunkStoreService.get_sourcesis also dead code; and the cleanup job (cleanup_deleted_documents) is only exposed viamake rag-cleanup— it is not yet wired to a deployed schedule.This PR description was written with the assistance of an LLM (Claude).