Failure scenarios
Concurrent identical sources bypass document dedup
- Start with an empty knowledge store.
- Concurrently call
KnowledgeStore.ingest("same content", "source-a") and KnowledgeStore.ingest("same content", "source-b").
- Both calls return
1 and list_sources() contains both sources, even though sequential ingestion rejects the second document as an exact duplicate.
The exact- and near-duplicate queries run before either caller acquires the write lock, so both callers observe an empty store. The lock serializes only the later delete/write/version block and cannot restore the promised deduplication invariant.
Concurrent updates use stale version metadata
- Start with an empty knowledge store.
- Concurrently ingest different content under the same source name.
- Both calls return success, but both version rows are recorded with
action = "create" and diff_summary = "initial version"; the second committed version should be an update with a diff against the version it replaced.
Each caller reads old_content and computes is_update before entering the write lock. The second caller therefore records metadata from a state that ceased to be current before its write began.
Sites
src/knowledge/store.py:190-221 performs document deduplication outside the write lock.
src/knowledge/store.py:223-225 captures the old source content and update/create decision outside the write lock.
src/knowledge/store.py:241-257 serializes only the destructive write and then records version metadata derived from the stale pre-lock read.
Expected result
Make deduplication and the old-version read/decision part of the same serialized transaction as replacement, so each successful ingest validates against the state immediately preceding its own commit and records truthful version metadata.
Failure scenarios
Concurrent identical sources bypass document dedup
KnowledgeStore.ingest("same content", "source-a")andKnowledgeStore.ingest("same content", "source-b").1andlist_sources()contains both sources, even though sequential ingestion rejects the second document as an exact duplicate.The exact- and near-duplicate queries run before either caller acquires the write lock, so both callers observe an empty store. The lock serializes only the later delete/write/version block and cannot restore the promised deduplication invariant.
Concurrent updates use stale version metadata
action = "create"anddiff_summary = "initial version"; the second committed version should be an update with a diff against the version it replaced.Each caller reads
old_contentand computesis_updatebefore entering the write lock. The second caller therefore records metadata from a state that ceased to be current before its write began.Sites
src/knowledge/store.py:190-221performs document deduplication outside the write lock.src/knowledge/store.py:223-225captures the old source content and update/create decision outside the write lock.src/knowledge/store.py:241-257serializes only the destructive write and then records version metadata derived from the stale pre-lock read.Expected result
Make deduplication and the old-version read/decision part of the same serialized transaction as replacement, so each successful ingest validates against the state immediately preceding its own commit and records truthful version metadata.