Skip to content

[BUG] - User profile bugs: indefinite accumulation + AI cleanup partial selection data loss #237

Description

@evilhikari

Description

Two related bugs in the user profile system:

  1. Profile items (preferences, patterns, workflows) accumulate indefinitely — automatic decay is ineffective and AI cleanup is never auto-triggered.
  2. AI cleanup with partial selection permanently deletes all unselected items.

Steps to Reproduce

Bug 1:

  1. Use opencode-mem for an extended period (hundreds of prompts)
  2. Check user-profiles.db — item count only increases over time
  3. Changelogs across all versions show only additions, never removals

Bug 2:

  1. Open the opencode-mem web UI → User Profile page
  2. Select only a few items out of many
  3. Click "AI Cleanup" with partial selection
  4. Click "Apply"
  5. All unselected items are permanently deleted

Expected Behavior

Bug 1: Stale/low-confidence items should be automatically removed based on userProfileStaleDays and related config. AI cleanup should run periodically without manual intervention.

Bug 2: AI cleanup with partial selection should only modify selected items. Unselected items should be preserved.

Actual Behavior

Bug 1: decayItems() only removes items where alpha <= 2 && ageDays > 30 (hardcoded, user-profile-manager.js L346). Since alpha increments on every merge (combined.alpha += other.alpha || 1 L646, combined.alpha = (existingItem.alpha || 1) + top1Score * 1.0 L738), most items surpass alpha > 2 after 2-3 merges and can never be removed. Of the three config options, userProfileStaleDays and userProfileMinEvidenceForRetention are loaded but never referenced anywhere in the service code; userProfileConfidenceDecayDays IS referenced, but only by syncConfidence() (L1036) for confidence half-life decay — not for item removal decisions. AI cleanup (aiCleanupProfile) is only available via manual HTTP API call (api-handlers.js L874/L877), never triggered during profile learning (performUserProfileLearning() in user-memory-learning.js has no cleanup call).

Bug 2: handleAICleanup (api-handlers.js L855) with non-empty includeIds calls filterProfileForCleanup() (L872) which filters the profile down to only selected items, then aiCleanupProfileFromIndexed() builds originalById from that filtered set. rebuildProfileUsing() (user-profile/ai-cleanup.js L270) preserves unmentioned items via unmentionedIds (L397-429), but that set is derived only from originalById.values() — so unselected items (never in the indexed set) are invisible to the preservation logic. handleApplyCleanup() (L901) then replaces the entire profile with the cleaned subset (L1002), permanently losing every unselected item.

Location

Bug 1:

  • File: dist/services/user-profile/user-profile-manager.js
  • Function: decayItems() — Lines 330-357 (hardcoded check at L346)
  • Also: dist/services/user-memory-learning.jsperformUserProfileLearning() never calls aiCleanupProfile()

Bug 2:

  • File: dist/services/user-profile/ai-cleanup.js (note: under user-profile/, not services/ root)
  • Functions: filterProfileForCleanup() (L70-78), rebuildProfileUsing() (L270-431)
  • Also: dist/services/api-handlers.js (note: under services/ root, not web-server/)
  • Functions: handleAICleanup() (L855), handleApplyCleanup() (L901)

Impact

Bug 1: Profile grows unbounded over time, degrading AI context quality and increasing token cost.

Bug 2: Data loss — users lose their entire profile history when trying to clean up a small subset of items. No undo.

Suggested Fixes

Bug 1: Use config values in decay logic instead of hardcoded constants. Auto-trigger AI cleanup periodically during profile learning.

Bug 2: Pass full profileData to rebuildProfileUsing() as originalById, while only sending selected items to AI. This lets unmentionedIds correctly preserve unselected items (verified: the unmentionedIds loop at L402-429 walks originalById.values() and would retain every id not in keptIds/mapping.removed — with the full profile as originalById, unselected items fall into this set and are preserved).

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