Skip to content

reindex can find missing embeddings but not stale ones #199

Description

@RobertSigmundsson

Problem Statement

smem reindex can re-embed the neurons that have no vector (--missing-only, the default) or every neuron in the brain (--all). There is nothing in between, and the gap matters because the failure mode that most needs re-embedding leaves the vector field populated, not empty.

When a neuron's content is replaced but its embedding is not recomputed, the row ends up holding a vector that describes the previous text. --missing-only cannot see it, because the field is not missing. The only remedy on offer is --all, which re-embeds the entire brain to fix a handful of rows - on a large brain that is a long, costly job, and on a metered embedding provider it is a bill.

Proposed Solution

A third mode that identifies rows whose stored vector no longer matches their current content: re-embed the content, compare the result against the stored vector, and only write when they diverge beyond a threshold.

smem reindex --stale                    # report and fix drifted vectors
smem reindex --stale --dry-run          # report only: how many, which
smem reindex --stale --threshold 0.98   # cosine below this counts as stale

Use Case

The practical one: after any episode where content was updated through a path that did not refresh the derived fields, an operator wants to know whether their brain is affected and repair only what is. Today the honest answer is "re-embed everything and hope", which is expensive enough that people will skip it and keep a quietly wrong index.

A dry run is useful on its own, even without the repair - it answers "is my recall index actually describing my current content?", which is not answerable today.

Alternatives Considered

  • --all. Correct but disproportionate; cost scales with brain size rather than with damage.
  • Reactive detection at recall time. Would spread the embedding cost into the query path, which seems worse than an explicit maintenance command.
  • Nothing. Defensible if you consider the write paths authoritative, though it leaves no way to verify that.

Additional Context

This came out of the follow-up discussion on #166, where the same shape of problem was fixed at one write site. A --stale mode is the general safety net for the class rather than a fix for any one call site: it does not care how the vector came to disagree with the content.

Cost note worth weighing: --stale re-embeds everything it inspects in order to compare, so a full-brain --stale sweep costs roughly what --all costs in provider calls, and saves the writes rather than the embeddings. The saving is real for a targeted run or a dry run, and honest to state up front rather than have someone discover it.


No urgency on this one - filing it while it is fresh, measured on v3.8.0 (ae8e8743).
Thanks for the recent run of releases; it makes it easy to check ideas against a current tree.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions