Failure scenario
- Ingest two different source names whose MD5 hashes share the same first eight hexadecimal characters. For example,
collision-source-66887 and collision-source-100206 both have the prefix 0702c97b.
- Give the sources different document content and ingest them sequentially.
- Both ingests report success, but
list_sources() contains only the second source. The first source's chunks are gone while its version-history row remains.
Chunk IDs are derived only from a 32-bit prefix of the source-name hash plus the chunk index. INSERT OR REPLACE treats a colliding source's chunk as the same primary-key row and silently replaces it. The second document therefore corrupts the first document's live knowledge state.
Sites
src/knowledge/store.py:186 truncates the source-name digest to eight hexadecimal characters.
src/knowledge/store.py:245-249 passes that truncated digest into every chunk write.
src/knowledge/store.py:274-285 derives each primary key from the digest and chunk index, then uses INSERT OR REPLACE, allowing a different source with the same prefix to replace the row.
Expected result
Use a collision-resistant source identity in chunk primary keys, or detect and reject an identity collision before replacing rows belonging to another source. Distinct source names must never overwrite one another's chunks.
Failure scenario
collision-source-66887andcollision-source-100206both have the prefix0702c97b.list_sources()contains only the second source. The first source's chunks are gone while its version-history row remains.Chunk IDs are derived only from a 32-bit prefix of the source-name hash plus the chunk index.
INSERT OR REPLACEtreats a colliding source's chunk as the same primary-key row and silently replaces it. The second document therefore corrupts the first document's live knowledge state.Sites
src/knowledge/store.py:186truncates the source-name digest to eight hexadecimal characters.src/knowledge/store.py:245-249passes that truncated digest into every chunk write.src/knowledge/store.py:274-285derives each primary key from the digest and chunk index, then usesINSERT OR REPLACE, allowing a different source with the same prefix to replace the row.Expected result
Use a collision-resistant source identity in chunk primary keys, or detect and reject an identity collision before replacing rows belonging to another source. Distinct source names must never overwrite one another's chunks.