fix: Prevent deleted projects from being recreated by background sync (#193) - #370
Conversation
…#193) This fix addresses issue #193 where deleted projects would reappear after being removed by the user. The problem occurred in two places: 1. **watch_service.handle_changes()**: Background sync would continue processing file changes for projects that had been deleted from configuration, causing database entries to be recreated for orphaned directories. 2. **project_service.synchronize_projects()**: Project synchronization would re-add projects from the database back to the configuration file, treating the database as the source of truth when it should be the config file. Root cause: When a project was deleted, the directory still existed on disk, and two different mechanisms would resurrect it: - Background sync processing file changes in the deleted project's directory - Project synchronization adding DB-only projects back to config Changes: - watch_service.py: Added check if project exists in config before syncing - project_service.py: Changed synchronize_projects to remove DB-only projects instead of adding them to config (config is source of truth) - test_watch_service.py: Added test_handle_changes_skips_deleted_project - test_project_service.py: Added test_synchronize_projects_removes_db_only_projects This fix ensures config is the single source of truth for project existence, and deleted projects stay deleted even when their directories remain on disk. Signed-off-by: Claude <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
|
Claude finished @phernandez's task —— View job PR Review: Prevent Deleted Projects RecreationI've completed a thorough review of this PR against our team standards. This is an excellent fix for a critical bug! The implementation is solid, well-tested, and addresses the root cause effectively. ✅ Code Quality & StandardsExcellent - All criteria met:
✅ Testing & DocumentationExcellent - Comprehensive test coverage:
✅ Basic Memory ArchitectureStrong architectural consistency:
✅ Security & PerformanceNo concerns identified:
📋 Detailed Code Reviewwatch_service.py (lines 239-248)Strengths:
Minor observations:
project_service.py (lines 363-371)Strengths:
Perfect implementation - this is exactly the right fix. Test Coveragetest_handle_changes_skips_deleted_project (watch_service.py:454-533):
test_synchronize_projects_removes_db_only_projects (project_service.py:1204-1253):
🎯 RecommendationsOptional Improvements (not blocking):
🏆 SummaryLGTM - Approve with confidence! This PR delivers an excellent fix for a production bug: ✅ Root cause addressed: Both resurrection mechanisms fixed The code quality is high, tests are thorough, and the architectural decision (config as source of truth) is sound and well-documented. The optional recommendations above are nice-to-haves for future consideration, not blockers. Recommendation: Merge when ready! 🚀 Review completed against Basic Memory team checklist |
Summary
Fixes issue #193 from basic-memory-cloud where deleted projects would reappear after being removed by the user. This issue affected both local and cloud deployments.
Root Cause
When a project was deleted, the directory still existed on disk, and two different mechanisms would resurrect it:
Evidence from Cloud
Timeline from Logfire for tenant
0a20eb58-970f-ab05-ff49-25a9cdb2179c:The cloud sync worker runs
reconcile_projects_with_config()every 30 seconds, which was callingsynchronize_projects()and re-adding the deleted project back to config from the database.Changes Made
src/basic_memory/sync/watch_service.py(lines 241-251):handle_changes()before processing file changessrc/basic_memory/services/project_service.py(lines 363-371):synchronize_projects()behavior for DB-only projectsTests Added:
test_handle_changes_skips_deleted_projectintests/sync/test_watch_service.pytest_synchronize_projects_removes_db_only_projectsintests/services/test_project_service.pyImpact
This fix ensures that:
reconcile_projects_with_config()function now properly cleans up orphaned DB entriesTest Plan
🤖 Generated with Claude Code