Skip to content

Regular (non-.md) files are indexed with a NULL permalink #1182

Description

@jope-bm

Summary

batch_indexer._upsert_regular_file computes a permalink for a regular (non-markdown) file and then discards it, creating the entity without one. Every non-.md file — Dockerfile, scripts/*.py, images — is therefore indexed with permalink = NULL.

src/basic_memory/indexing/batch_indexer.py (~line 441):

if existing is None:
    await self.entity_service.resolve_permalink(file.path, skip_conflict_check=True)  # result discarded
    entity = Entity(
        note_type="file",
        file_path=file.path,
        checksum=checksum,
        title=Path(file.path).name,
        ...                                    # no permalink=
    )

The resolve_permalink() call reads as unintentional rather than deliberate: the value is computed and thrown away. sync_service should be checked for the same pattern.

Why it matters

A permalink is an entity's stable address, used by memory:// references, wikilinks, and permalink-keyed lookups. Because these rows have none, every consumer must treat permalink as optional — and a consumer that didn't previously produced a hard failure when deleting a non-markdown file (tracked privately; that specific delete path has since been fixed by making the delete/live-update contract permalink-optional).

Honest scoping: this is a latent-consistency issue, not a live user-facing bug. Nothing is known to be broken today; the value of fixing it is removing a class of "assumed permalink exists" defects at the source instead of guarding each consumer.

Suggested fix

  1. Assign the resolved permalink when indexing a regular file (stop discarding it). Audit sync_service for the same pattern.
  2. Decide the backfill question for existing NULL rows — new rows having permalinks while old ones don't is its own inconsistency. (Observed in one deployment: ~114 note_type=file rows, all NULL, alongside a stray note_type=canvas row, so the assumption is not strictly limited to note_type=file.)
  3. Regression test: index a non-.md file → assert a permalink is stored → delete it → assert deleted and not resurrected.

Not purely additive. Giving regular files real permalinks changes data shape (permalink-keyed routing, search, wikilink resolution) and interacts with permalink-collision handling, so it warrants a deliberate decision rather than a drive-by change.

Open questions

  • Are non-markdown files excluded from full-text search because they lack a permalink, or by design independently of it? Observed but not determined.
  • Should regular files get a permalink at all, or is NULL the intended design and the resolve_permalink() call simply dead code to remove? Either resolution is coherent; the current state — computing a value and discarding it — is not.

Moved from the private Cloud tracker (basicmachines-co/basic-memory-cloud#1536), which holds the production evidence, the original failure report, and the verification that the delete path is fixed. Details omitted here because this repository is public.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcloudBasic Memory ClouddocumentationImprovements or additions to documentationduplicateThis issue or pull request already existsenhancementNew feature or requestgood first issueGood for newcomershelp wantedExtra attention is neededinvalidThis doesn't seem rightquestionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions