-
Notifications
You must be signed in to change notification settings - Fork 7
feat: add multi-layer memory protection to consolidation engine #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add multi-layer memory protection to consolidation engine #16
Conversation
… engine Implements multi-layer protection to prevent accidental data loss during consolidation, particularly for restored memories. Protection criteria: - Explicit 'protected' flag on memory node - High importance (>= 0.5 by default) - Grace period (90 days for new/restored memories) - Protected memory types (Decision, Insight by default) New environment variables: - CONSOLIDATION_DELETE_THRESHOLD (default: 0.05) - CONSOLIDATION_ARCHIVE_THRESHOLD (default: 0.2) - CONSOLIDATION_GRACE_PERIOD_DAYS (default: 90) - CONSOLIDATION_IMPORTANCE_PROTECTION_THRESHOLD (default: 0.5) - CONSOLIDATION_PROTECTED_TYPES (default: "Decision,Insight") Changes: - consolidation.py: Add _should_protect_memory() method with multi-criteria checks - consolidation.py: Update apply_controlled_forgetting() to respect protection - consolidation.py: Track protected memories in stats alongside deleted/archived - automem/config.py: Add configurable protection threshold variables - app.py: Wire protection config to both MemoryConsolidator instantiations
📝 WalkthroughWalkthroughThe pull request introduces memory protection configuration constants and extends MemoryConsolidator to enforce protection rules during controlled forgetting. Five new configurable parameters (delete_threshold, archive_threshold, grace_period_days, importance_protection_threshold, protected_types) are added to configuration, wired through the application layer, and used to prevent deletion of memories meeting specified protection criteria. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
automem/config.py (1)
32-37: Missing error handling for invalid environment variable values.Unlike
_DECAY_THRESHOLD_RAW(lines 25-28) which strips and checks for empty values before callingfloat(), these new config values will raiseValueErrorif the environment variable is set to an empty or non-numeric string, causing application startup to fail.Consider adding defensive parsing:
-CONSOLIDATION_DELETE_THRESHOLD = float(os.getenv("CONSOLIDATION_DELETE_THRESHOLD", "0.05")) -CONSOLIDATION_ARCHIVE_THRESHOLD = float(os.getenv("CONSOLIDATION_ARCHIVE_THRESHOLD", "0.2")) -CONSOLIDATION_GRACE_PERIOD_DAYS = int(os.getenv("CONSOLIDATION_GRACE_PERIOD_DAYS", "90")) -CONSOLIDATION_IMPORTANCE_PROTECTION_THRESHOLD = float( - os.getenv("CONSOLIDATION_IMPORTANCE_PROTECTION_THRESHOLD", "0.5") -) +_DELETE_THRESHOLD_RAW = os.getenv("CONSOLIDATION_DELETE_THRESHOLD", "0.05").strip() +CONSOLIDATION_DELETE_THRESHOLD = float(_DELETE_THRESHOLD_RAW) if _DELETE_THRESHOLD_RAW else 0.05 + +_ARCHIVE_THRESHOLD_RAW = os.getenv("CONSOLIDATION_ARCHIVE_THRESHOLD", "0.2").strip() +CONSOLIDATION_ARCHIVE_THRESHOLD = float(_ARCHIVE_THRESHOLD_RAW) if _ARCHIVE_THRESHOLD_RAW else 0.2 + +_GRACE_PERIOD_RAW = os.getenv("CONSOLIDATION_GRACE_PERIOD_DAYS", "90").strip() +CONSOLIDATION_GRACE_PERIOD_DAYS = int(_GRACE_PERIOD_RAW) if _GRACE_PERIOD_RAW else 90 + +_IMPORTANCE_THRESHOLD_RAW = os.getenv("CONSOLIDATION_IMPORTANCE_PROTECTION_THRESHOLD", "0.5").strip() +CONSOLIDATION_IMPORTANCE_PROTECTION_THRESHOLD = ( + float(_IMPORTANCE_THRESHOLD_RAW) if _IMPORTANCE_THRESHOLD_RAW else 0.5 +)consolidation.py (1)
141-148: Consider edge case: emptyprotected_typesset.The expression
protected_types or self.PROTECTED_TYPESwill fall back to the class default whenprotected_typesis an empty set (sinceset()is falsy). If an empty set is passed intentionally to disable type-based protection, it would be ignored.If disabling type protection via an empty set should be supported:
- self.protected_types = protected_types or self.PROTECTED_TYPES + self.protected_types = protected_types if protected_types is not None else self.PROTECTED_TYPESIf the current behavior (always having at least the default protected types) is intentional, consider documenting this.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
app.py(3 hunks)automem/config.py(1 hunks)consolidation.py(6 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
app.py
📄 CodeRabbit inference engine (CLAUDE.md)
app.py: Use Flask for the main API server (port 8001) with request validation and orchestration
Implement 13 API endpoints covering core memory operations (POST /memory, GET /recall, PATCH /memory/, DELETE /memory/, GET /memory/by-tag), relationship management (POST /associate), consolidation (POST /consolidate, GET /consolidate/status), health checks (GET /health), enrichment (GET /enrichment/status, POST /enrichment/reprocess), analysis (GET /analyze), and startup recall (GET /startup-recall)
Expose enrichment metrics at GET /enrichment/status including processed counts, last success/error, queue depth, and inflight jobs
Combine vector similarity, keyword match, tag overlap, and recency in recall scoring
Support authentication via Bearer token, X-API-Key header, or query parameter
Files:
app.py
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Use black for Python code formatting
Use flake8 for Python linting
**/*.py: Use Python with type hints. Indent 4 spaces; line length 100 (Black).
Use snake_case for module and function names in Python.
Use PascalCase for class names in Python.
Use UPPER_SNAKE_CASE for constants in Python.
Format code with Black (line length 100) and organize imports with Isort (profile=black).
Lint with Flake8 and ensure CI passes before committing.
Add or adjust tests for new endpoints, stores, or utils; maintain comprehensive test coverage.
Files:
app.pyautomem/config.pyconsolidation.py
consolidation.py
📄 CodeRabbit inference engine (CLAUDE.md)
consolidation.py: Implement consolidation engine (consolidation.py) with four biological memory patterns: Decay (hourly exponential relevance updates), Creative (REM-like processing hourly), Clustering (semantic grouping every 6 hours), and Forgetting (archive low-importance daily)
Use ConsolidationScheduler to manage consolidation intervals with configurable values via environment variables
Run consolidation in background threads without blocking API requests
Use exponential decay with fractional-day intervals for memory relevance updates in Decay consolidation task
Use CONSOLIDATION_DECAY_IMPORTANCE_THRESHOLD to skip truly low-importance items during decay consolidation
Files:
consolidation.py
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: verygoodplugins/automem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:34:12.678Z
Learning: Applies to consolidation.py : Implement consolidation engine (consolidation.py) with four biological memory patterns: Decay (hourly exponential relevance updates), Creative (REM-like processing hourly), Clustering (semantic grouping every 6 hours), and Forgetting (archive low-importance daily)
📚 Learning: 2025-12-02T05:34:12.678Z
Learnt from: CR
Repo: verygoodplugins/automem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:34:12.678Z
Learning: Applies to consolidation.py : Implement consolidation engine (consolidation.py) with four biological memory patterns: Decay (hourly exponential relevance updates), Creative (REM-like processing hourly), Clustering (semantic grouping every 6 hours), and Forgetting (archive low-importance daily)
Applied to files:
app.pyautomem/config.pyconsolidation.py
📚 Learning: 2025-12-02T05:34:12.678Z
Learnt from: CR
Repo: verygoodplugins/automem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:34:12.678Z
Learning: Applies to consolidation.py : Use ConsolidationScheduler to manage consolidation intervals with configurable values via environment variables
Applied to files:
app.pyautomem/config.py
📚 Learning: 2025-12-02T05:34:12.678Z
Learnt from: CR
Repo: verygoodplugins/automem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:34:12.678Z
Learning: Applies to app.py : Implement 13 API endpoints covering core memory operations (POST /memory, GET /recall, PATCH /memory/<id>, DELETE /memory/<id>, GET /memory/by-tag), relationship management (POST /associate), consolidation (POST /consolidate, GET /consolidate/status), health checks (GET /health), enrichment (GET /enrichment/status, POST /enrichment/reprocess), analysis (GET /analyze), and startup recall (GET /startup-recall)
Applied to files:
app.py
📚 Learning: 2025-12-02T05:34:12.678Z
Learnt from: CR
Repo: verygoodplugins/automem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:34:12.678Z
Learning: Applies to consolidation.py : Use CONSOLIDATION_DECAY_IMPORTANCE_THRESHOLD to skip truly low-importance items during decay consolidation
Applied to files:
app.pyautomem/config.pyconsolidation.py
📚 Learning: 2025-12-02T05:34:12.678Z
Learnt from: CR
Repo: verygoodplugins/automem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:34:12.678Z
Learning: Applies to consolidation.py : Run consolidation in background threads without blocking API requests
Applied to files:
app.py
📚 Learning: 2025-12-02T05:34:12.678Z
Learnt from: CR
Repo: verygoodplugins/automem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T05:34:12.678Z
Learning: Applies to consolidation.py : Use exponential decay with fractional-day intervals for memory relevance updates in Decay consolidation task
Applied to files:
automem/config.pyconsolidation.py
🧬 Code graph analysis (2)
app.py (1)
consolidation.py (1)
MemoryConsolidator(99-881)
consolidation.py (1)
automem/utils/time.py (1)
_parse_iso_datetime(12-27)
🔇 Additional comments (9)
automem/config.py (1)
38-42: LGTM!The protected types parsing is well-implemented with proper handling of empty strings, whitespace trimming, and the use of
frozensetfor immutability. The default values align with the class-levelPROTECTED_TYPESconstant inconsolidation.py.app.py (3)
123-128: LGTM!The new protection configuration constants are properly imported and well-documented with a descriptive comment.
1474-1482: LGTM!The scheduler builder correctly passes all protection configuration parameters to
MemoryConsolidator, ensuring that scheduled consolidation tasks will respect the configured protection rules.
2672-2680: LGTM!The manual consolidation endpoint is correctly wired with the same protection parameters as the scheduler, ensuring consistent behavior between scheduled and on-demand consolidation.
consolidation.py (5)
107-113: LGTM!The docstring clearly documents the four protection layers, making the feature's behavior transparent to developers.
189-229: LGTM!The multi-layer protection logic is well-structured with clear priority ordering. Each protection layer is properly documented with a descriptive reason string returned for logging/debugging.
One minor observation: the grace period calculation assumes timezone-aware datetimes. Since
current_timecomes fromdatetime.now(timezone.utc)and_parse_iso_datetimehandles timezone conversion for ISO strings with 'Z' suffix, this should work correctly for properly formatted timestamps.
542-560: LGTM!The protection check is correctly integrated before deletion logic. Protected memories are properly tracked in stats, logged at DEBUG level per-memory, and skipped via
continue. The protection summary at INFO level provides good operational visibility.Note: Archiving (lines 591-611) doesn't check protection, which appears intentional since archiving is non-destructive and memories can be restored. If this is the intended behavior, consider adding a brief comment to clarify.
501-537: LGTM!The stats structure is properly extended to track protected memories, and the query correctly fetches the new
protectedandprotected_reasonfields. The defensivelen(row) > Nchecks ensure backward compatibility with result sets that might not include all fields.
626-636: LGTM!The protection summary logging is well-designed: it only logs when protection was actually activated, avoiding log noise, while providing comprehensive metrics for operational monitoring.
Summary
Implements "Hybrid #6" memory protection strategy in the consolidation engine to prevent accidental deletion of important memories.
Protection Layers
protected: trueon Memory nodesEnvironment Variables
CONSOLIDATION_DELETE_THRESHOLD(default: 0.05)CONSOLIDATION_ARCHIVE_THRESHOLD(default: 0.2)CONSOLIDATION_GRACE_PERIOD_DAYS(default: 90)CONSOLIDATION_IMPORTANCE_PROTECTION_THRESHOLD(default: 0.5)CONSOLIDATION_PROTECTED_TYPES(default: Decision,Insight)Test plan
🤖 Generated with Claude Code