fix(db): make insert_documentation an upsert (closes #48) - #52
Closed
nelsonmfinda wants to merge 1 commit into
Closed
nelsonmfinda wants to merge 1 commit into
nelsonmfinda wants to merge 1 commit into
Conversation
This was referenced May 12, 2026
Owner
|
Verified locally: 114 tests pass, upsert behaves correctly (same doc_id on re seed, One non blocking thing worth knowing about the embeddings file bloat on repeated re seeds is in #55, alongside consolidated feedback for your other three PRs. Suggested a unified PR over there if you want to avoid the cli.py conflicts between #49 / #51 / #54. |
Owner
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.
Summary
Fix #48: re-seeding the same corpus name no longer raises
sqlite3.IntegrityError.db.insert_documentationnow upserts the documentations row viaINSERT ... ON CONFLICT(name) DO UPDATE ... RETURNING id, then clears and rewrites that doc's sections (cascadingquery_cache, FTS5 'delete' protocol onsections_fts). Embedding writes are deferred until after the SQLitecommit, so a rollback never leaves
embeddings.npyahead of the DB.While in there:
_get_connectionnow setsPRAGMA foreign_keys = ONon every connection. Without this,ON DELETE CASCADEwas a silent no-op everywhere exceptinit_db, leaving orphanrows after deletes. The upsert depends on the cascade; every other delete path benefits too.
Related issue
Closes #48.
Type of change
How it was tested
pytest -q
742 passed, 1 skipped
8 tests in
TestInsertDocumentationUpsert:query_cachecascade-pruned (stalesection_idremoved)created_atpreserved across re-seed;doc_idstable;updated_atadvancestmp_pathand never touches the repo's realdata/embeddings.npyI haven't run a live
king-scrape <url> --name X --yestwice end-to-end in this PR, but the unit tests cover the pre-fix repro precisely. Happy to do a live run as part of review if youwant.
Checklist
pytest)docs/and/orREADME.mdif behavior changed (no public-surface change; CHANGELOG entry added)Additional notes
A few choices worth flagging:
king-scraperuns against the same name.ON CONFLICT(name) DO UPDATEis one statement, gets the writer lock, and removes the race. Same form preservescreated_atand keepsdoc_idstable, which is what callers caching the ID would expect._generate_and_save_embeddingwrites toembeddings.npyandsection_mapping.json, which are not part of the SQLite transaction. If a rollback fired with the previous shape, the numpy file would race ahead of the DB. Now we stage(section_id, content)tuples during the transaction and flush afterconn.commit(). CHANGELOG describes the boundary explicitly: atomic at the SQLite level, embeddings deferred.PRAGMA foreign_keys = ONin_get_connection. Pre-existing latent bug separate from [Bug] seed_one re-seed fails on UNIQUE constraint #48, surfaces here because the upsert depends on cascade. Worth a one-timekctx doctor-style check on existing dbs to verify they have no orphan rows from before this fix; out of scope for this PR.embeddings.npy. Not a correctness bug because cascade-deleted IDs are never queried, but the file grows on every re-seed. Worth a follow-up issue (prune on upsert, or rebuild via akctx reindexcommand); not a blocker for the bug fix.temp_dbfixture extended to patchEMBEDDINGS_PATH+SECTION_MAPPING_PATHand reset_embeddings/_section_id_to_idx. Without this, any future test that loads the embedding model would silently write to the real repo'sdata/. Latent today, fixed now.