|
1 | 1 | --- |
2 | 2 | title: 'SPEC-20: Simplified Project-Scoped Rclone Sync' |
3 | 3 | date: 2025-01-27 |
4 | | -status: Draft |
| 4 | +updated: 2025-01-28 |
| 5 | +status: Implemented |
5 | 6 | priority: High |
6 | 7 | goal: Simplify cloud sync by making it project-scoped, safe by design, and closer to native rclone commands |
7 | 8 | parent: SPEC-8 |
@@ -1019,11 +1020,15 @@ rm -rf ~/basic-memory-cloud-sync/ |
1019 | 1020 | - [x] Create `project.py`: Add `project bisync` command |
1020 | 1021 | - [x] Create `project.py`: Add `project check` command |
1021 | 1022 | - [x] Create `project.py`: Add `project ls` command |
| 1023 | +- [x] Create `project.py`: Add `project bisync-reset` command |
1022 | 1024 | - [x] Import rclone_commands module and get_mount_info helper |
1023 | | -- [ ] Update `project list` to show sync status (optional) |
1024 | | -- [ ] Update `cloud/core_commands.py`: Simplify `cloud setup` command (optional) |
1025 | | -- [ ] Add helper functions: `get_all_sync_projects()`, `get_project_by_name()` (optional) |
1026 | | -- [ ] Write integration tests for new commands (deferred) |
| 1025 | +- [x] Update `project list` to show local sync paths in cloud mode |
| 1026 | +- [x] Update `project list` to conditionally show columns based on config |
| 1027 | +- [x] Update `project remove` to clean up local directories and bisync state |
| 1028 | +- [x] Add automatic database sync trigger after file sync operations |
| 1029 | +- [x] Add path normalization to prevent S3 mount point leakage |
| 1030 | +- [x] Update `cloud/core_commands.py`: Simplified `cloud setup` command |
| 1031 | +- [x] Write unit tests for `project add --local-path` (4 tests passing) |
1027 | 1032 |
|
1028 | 1033 | ### Phase 5: Cleanup ✅ |
1029 | 1034 | - [x] Remove `mount_commands.py` (entire file) |
@@ -1053,23 +1058,154 @@ rm -rf ~/basic-memory-cloud-sync/ |
1053 | 1058 | - [x] Update tests to remove references to deprecated functionality |
1054 | 1059 | - [x] All typecheck errors resolved |
1055 | 1060 |
|
1056 | | -### Phase 6: Documentation |
1057 | | -- [ ] Update `docs/cloud-cli.md` with new workflow |
1058 | | -- [ ] Add migration guide for existing users |
1059 | | -- [ ] Update command reference |
1060 | | -- [ ] Add troubleshooting section |
1061 | | -- [ ] Update SPEC-8 with "Superseded by SPEC-20" note |
1062 | | -- [ ] Add examples for common workflows |
1063 | | - |
1064 | | -### Testing & Validation |
1065 | | -- [ ] Test Scenario 1: New user setup |
1066 | | -- [ ] Test Scenario 2: Multiple projects |
1067 | | -- [ ] Test Scenario 3: Project without sync |
1068 | | -- [ ] Test Scenario 4: Integrity check |
1069 | | -- [ ] Test Scenario 5: Safety features (max delete) |
1070 | | -- [ ] Verify performance targets (setup < 30s, sync < 5s) |
1071 | | -- [ ] Test migration from SPEC-8 implementation |
| 1061 | +### Phase 6: Documentation ✅ |
| 1062 | +- [x] Update `docs/cloud-cli.md` with new workflow |
| 1063 | +- [x] Add troubleshooting section for empty directory issues |
| 1064 | +- [x] Add troubleshooting section for bisync state corruption |
| 1065 | +- [x] Document `bisync-reset` command usage |
| 1066 | +- [x] Update command reference with all new commands |
| 1067 | +- [x] Add examples for common workflows |
| 1068 | +- [ ] Add migration guide for existing users (deferred - no users on old system yet) |
| 1069 | +- [ ] Update SPEC-8 with "Superseded by SPEC-20" note (deferred) |
1072 | 1070 |
|
| 1071 | +### Testing & Validation ✅ |
| 1072 | +- [x] Test Scenario 1: New user setup (manual testing complete) |
| 1073 | +- [x] Test Scenario 2: Multiple projects (manual testing complete) |
| 1074 | +- [x] Test Scenario 3: Project without sync (manual testing complete) |
| 1075 | +- [x] Test Scenario 4: Integrity check (manual testing complete) |
| 1076 | +- [x] Test Scenario 5: bisync-reset command (manual testing complete) |
| 1077 | +- [x] Test cleanup on remove (manual testing complete) |
| 1078 | +- [x] Verify all commands work end-to-end |
| 1079 | +- [x] Document known issues (empty directory bisync limitation) |
| 1080 | +- [ ] Automated integration tests (deferred) |
| 1081 | +- [ ] Test migration from SPEC-8 implementation (N/A - no users yet) |
| 1082 | + |
| 1083 | +## Implementation Notes |
| 1084 | + |
| 1085 | +### Key Improvements Added During Implementation |
| 1086 | + |
| 1087 | +**1. Path Normalization (Critical Bug Fix)** |
| 1088 | + |
| 1089 | +**Problem:** Files were syncing to `/app/data/app/data/project/` instead of `/app/data/project/` |
| 1090 | + |
| 1091 | +**Root cause:** |
| 1092 | +- S3 bucket contains projects directly (e.g., `basic-memory-llc/`) |
| 1093 | +- Fly machine mounts bucket at `/app/data/` |
| 1094 | +- API returns paths like `/app/data/basic-memory-llc` (mount point + project) |
| 1095 | +- Rclone was using this full path, causing path doubling |
| 1096 | + |
| 1097 | +**Solution (three layers):** |
| 1098 | +- API side: Added `normalize_project_path()` in `project_router.py` to strip `/app/data/` prefix |
| 1099 | +- CLI side: Added defensive normalization in `project.py` commands |
| 1100 | +- Rclone side: Updated `get_project_remote()` to strip prefix before building remote path |
| 1101 | + |
| 1102 | +**Files modified:** |
| 1103 | +- `src/basic_memory/api/routers/project_router.py` - API normalization |
| 1104 | +- `src/basic_memory/cli/commands/project.py` - CLI normalization |
| 1105 | +- `src/basic_memory/cli/commands/cloud/rclone_commands.py` - Rclone remote path construction |
| 1106 | + |
| 1107 | +**2. Automatic Database Sync After File Operations** |
| 1108 | + |
| 1109 | +**Enhancement:** After successful file sync or bisync, automatically trigger database sync via API |
| 1110 | + |
| 1111 | +**Implementation:** |
| 1112 | +- After `project sync`: POST to `/{project}/project/sync` |
| 1113 | +- After `project bisync`: POST to `/{project}/project/sync` + update config timestamps |
| 1114 | +- Skip trigger on `--dry-run` |
| 1115 | +- Graceful error handling with warnings |
| 1116 | + |
| 1117 | +**Benefit:** Files and database stay in sync automatically without manual intervention |
| 1118 | + |
| 1119 | +**3. Enhanced Project Removal with Cleanup** |
| 1120 | + |
| 1121 | +**Enhancement:** `bm project remove` now properly cleans up local artifacts |
| 1122 | + |
| 1123 | +**Behavior with `--delete-notes`:** |
| 1124 | +- ✓ Removes project from cloud API |
| 1125 | +- ✓ Deletes cloud files |
| 1126 | +- ✓ Removes local sync directory |
| 1127 | +- ✓ Removes bisync state directory |
| 1128 | +- ✓ Removes `cloud_projects` config entry |
| 1129 | + |
| 1130 | +**Behavior without `--delete-notes`:** |
| 1131 | +- ✓ Removes project from cloud API |
| 1132 | +- ✗ Keeps local files (shows path in message) |
| 1133 | +- ✓ Removes bisync state directory (cleanup) |
| 1134 | +- ✓ Removes `cloud_projects` config entry |
| 1135 | + |
| 1136 | +**Files modified:** |
| 1137 | +- `src/basic_memory/cli/commands/project.py` - Enhanced `remove_project()` function |
| 1138 | + |
| 1139 | +**4. Bisync State Reset Command** |
| 1140 | + |
| 1141 | +**New command:** `bm project bisync-reset <project>` |
| 1142 | + |
| 1143 | +**Purpose:** Clear bisync state when it becomes corrupted (e.g., after mixing dry-run and actual runs) |
| 1144 | + |
| 1145 | +**What it does:** |
| 1146 | +- Removes all bisync metadata from `~/.basic-memory/bisync-state/{project}/` |
| 1147 | +- Forces fresh baseline on next `--resync` |
| 1148 | +- Safe operation (doesn't touch files) |
| 1149 | +- Also runs automatically on project removal |
| 1150 | + |
| 1151 | +**Files created:** |
| 1152 | +- Added `bisync-reset` command to `src/basic_memory/cli/commands/project.py` |
| 1153 | + |
| 1154 | +**5. Improved UI for Project List** |
| 1155 | + |
| 1156 | +**Enhancements:** |
| 1157 | +- Shows "Local Path" column in cloud mode for projects with sync configured |
| 1158 | +- Conditionally shows/hides columns based on config: |
| 1159 | + - Local Path: only in cloud mode |
| 1160 | + - Default: only when `default_project_mode` is True |
| 1161 | +- Uses `no_wrap=True, overflow="fold"` to prevent path truncation |
| 1162 | +- Applies path normalization to prevent showing mount point details |
| 1163 | + |
| 1164 | +**Files modified:** |
| 1165 | +- `src/basic_memory/cli/commands/project.py` - Enhanced `list_projects()` function |
| 1166 | + |
| 1167 | +**6. Documentation of Known Issues** |
| 1168 | + |
| 1169 | +**Issue documented:** Rclone bisync limitation with empty directories |
| 1170 | + |
| 1171 | +**Problem:** "Empty prior Path1 listing. Cannot sync to an empty directory" |
| 1172 | + |
| 1173 | +**Explanation:** Bisync creates listing files that track state. When both directories are completely empty, these listing files are considered invalid. |
| 1174 | + |
| 1175 | +**Solution documented:** Add at least one file (like README.md) before running `--resync` |
| 1176 | + |
| 1177 | +**Files updated:** |
| 1178 | +- `docs/cloud-cli.md` - Added troubleshooting sections for: |
| 1179 | + - Empty directory issues |
| 1180 | + - Bisync state corruption |
| 1181 | + - Usage of `bisync-reset` command |
| 1182 | + |
| 1183 | +### Rclone Flag Fix |
| 1184 | + |
| 1185 | +**Bug fix:** Incorrect rclone flag causing sync failures |
| 1186 | + |
| 1187 | +**Error:** `unknown flag: --filters-file` |
| 1188 | + |
| 1189 | +**Fix:** Changed `--filters-file` to correct flag `--filter-from` in both `project_sync()` and `project_bisync()` functions |
| 1190 | + |
| 1191 | +**Files modified:** |
| 1192 | +- `src/basic_memory/cli/commands/cloud/rclone_commands.py` |
| 1193 | + |
| 1194 | +### Test Coverage |
| 1195 | + |
| 1196 | +**Unit tests added:** |
| 1197 | +- `tests/cli/test_project_add_with_local_path.py` - 4 tests for `--local-path` functionality |
| 1198 | + - Test with local path saves to config |
| 1199 | + - Test without local path doesn't save to config |
| 1200 | + - Test tilde expansion in paths |
| 1201 | + - Test nested directory creation |
| 1202 | + |
| 1203 | +**Manual testing completed:** |
| 1204 | +- All 10 project commands tested end-to-end |
| 1205 | +- Path normalization verified |
| 1206 | +- Database sync trigger verified |
| 1207 | +- Cleanup on remove verified |
| 1208 | +- Bisync state reset verified |
1073 | 1209 |
|
1074 | 1210 | ## Future Enhancements (Out of Scope) |
1075 | 1211 |
|
|
0 commit comments