You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If an entity row's type fields are wrong but its checksum matches the bytes on disk, no amount of re-syncing or re-indexing will repair it. Change detection compares checksums only, so the row is reported unchanged and is never re-parsed. There appears to be no mechanism anywhere that notices a row whose type disagrees with its file.
How we hit it
A markdown note's entity row was replaced by a plain-file row — note_type='file', content_type='text/plain', permalink=NULL, no note_content row, title taken from an Emacs autosave (filed separately as #1537).
The important part for this issue is the reason it was unrepairable. The autosave's bytes were byte-identical to what the note became 16 seconds later, so the corrupt row's checksum and size already matched the real file exactly. Every subsequent scan therefore said:
[CHANGE] Move detection: found 0 moved files
[CHANGE] Delete detection: found 0 deleted files
[CHANGE] Detection complete: 0 new, 0 modified, 0 deleted, 0 moved, N unchanged
Repeated incremental rebuilds changed nothing. This has now happened twice, weeks apart, and on the first occurrence the rebuild attempts were abandoned as ineffective without the cause ever being found.
Observe the row reported as unchanged; edit_note <permalink> still does not resolve.
Now append a single byte to the file, and it repairs itself completely.
Expected Behavior
A sync or rebuild should be able to repair a row that disagrees with its own file. At minimum, a row whose file_path is a markdown path but whose content_type is not text/markdown — or a markdown entity with no note_content row — should be treated as dirty regardless of checksum.
Actual Behavior
The row is permanently invisible to sync. The only repair is to change the file's bytes so the checksum differs.
Worth noting that the repair machinery itself is entirely healthy — it just cannot be triggered. Once the checksum differed, index_markdown_file ran and _apply_markdown_entity_fields() rewrote title, note_type, permalink and content_type on the existing row, in place:
Same entity id, graph intact, no delete and no cascade. A one-byte append did what an unbounded number of rebuilds could not.
Possible Solution
Add a consistency predicate to change detection alongside the checksum comparison — mark a row dirty when runtime_file_path_is_markdown_note(file_path) is true but content_type != 'text/markdown', or when a markdown entity has no note_content row.
Offer a bm sync --force / --repair that ignores checksums for a project or path. Either of these would have let us fix this without resorting to modifying the user's note to provoke a reindex.
Consider a bm doctor-style read-only consistency check, since this class of corruption is silent: read_note kept working the whole time, so nothing surfaced until a write was attempted.
Environment
OS: macOS 26.6.2 (Darwin 25.6.0), arm64
Python: 3.14.7
basic-memory: 0.23.2
Install method: pipenv virtualenv; MCP servers launched by Claude Desktop and Claude Code
Config: local SQLite, semantic_search_enabled: true, index_changes: true, kebab_filenames: false
Bug Description
If an
entityrow's type fields are wrong but itschecksummatches the bytes on disk, no amount of re-syncing or re-indexing will repair it. Change detection compares checksums only, so the row is reportedunchangedand is never re-parsed. There appears to be no mechanism anywhere that notices a row whose type disagrees with its file.How we hit it
A markdown note's entity row was replaced by a plain-file row —
note_type='file',content_type='text/plain',permalink=NULL, nonote_contentrow, title taken from an Emacs autosave (filed separately as #1537).The important part for this issue is the reason it was unrepairable. The autosave's bytes were byte-identical to what the note became 16 seconds later, so the corrupt row's
checksumandsizealready matched the real file exactly. Every subsequent scan therefore said:Repeated incremental rebuilds changed nothing. This has now happened twice, weeks apart, and on the first occurrence the rebuild attempts were abandoned as ineffective without the cause ever being found.
Steps To Reproduce
entityrow whosefile_pathis an existing.mdnote, but withnote_type='file',content_type='text/plain',permalink=NULL, nonote_contentrow — and achecksumthat matches the file on disk. (Either via [BUG] Emacs autosave#note.md#is indexed as a non-markdown resource and can destroy the real note's entity row #1537, or by hand.)unchanged;edit_note <permalink>still does not resolve.Expected Behavior
A sync or rebuild should be able to repair a row that disagrees with its own file. At minimum, a row whose
file_pathis a markdown path but whosecontent_typeis nottext/markdown— or a markdown entity with nonote_contentrow — should be treated as dirty regardless of checksum.Actual Behavior
The row is permanently invisible to sync. The only repair is to change the file's bytes so the checksum differs.
Worth noting that the repair machinery itself is entirely healthy — it just cannot be triggered. Once the checksum differed,
index_markdown_fileran and_apply_markdown_entity_fields()rewrotetitle,note_type,permalinkandcontent_typeon the existing row, in place:Same entity id, graph intact, no delete and no cascade. A one-byte append did what an unbounded number of rebuilds could not.
Possible Solution
runtime_file_path_is_markdown_note(file_path)is true butcontent_type != 'text/markdown', or when a markdown entity has nonote_contentrow.bm sync --force/--repairthat ignores checksums for a project or path. Either of these would have let us fix this without resorting to modifying the user's note to provoke a reindex.bm doctor-style read-only consistency check, since this class of corruption is silent:read_notekept working the whole time, so nothing surfaced until a write was attempted.Environment
semantic_search_enabled: true,index_changes: true,kebab_filenames: false