Skip to content

[bug] Superseded/archived memory vectors are never pruned and crowd live rows out of the recall candidate window #1886

Description

@yyhhyyyyyy

Summary

markSuperseded and archive never remove the row's vector from the per-agent DuckDB store; only permanent deleteMemory does (managementService.ts:268). The vector query candidate window is only topK * 2 (default 12, retrievalService.ts:150,214), and recall drops matches whose authoritative SQLite row is superseded/archived/conflicted after the store query (retrievalService.ts:219-228). Dead vectors therefore permanently consume candidate slots.

Consolidation (UPDATE/SUPERSEDE merges) keeps producing superseded rows, so the dead-vector share grows with normal usage and vector recall quality decays over time. The only rebuild path today is an embedding model/dimension change (reindex).

Note: docs/issues/memory-recall-hot-path-keyword-recall/spec.md explicitly deferred 'DuckDB vacuum/orphan vector cleanup' as a non-goal; this issue is the follow-up that revisits that decision for the slot-starvation effect (the correctness of excluding archived rows is not in question).

Severity

P2 — progressive recall-quality degradation proportional to write churn; no recovery path short of switching embedding models.

Fix direction

Two prongs: (1) inline self-healing — when recall's post-filter drops a dead match, fire a background deleteVectorsForMemoryIds for those ids; (2) a capped maintenance sweep that prunes vectors for embedded-but-dead rows and clears their embedding columns so restore/absorb re-embeds cleanly.

SDD doc: docs/issues/memory-audit-hardening/ (spec.md + plan.md + tasks.md)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions