Skip to content

Commit 1d0b885

Browse files
pimpinclaude
andcommitted
Remove document touch step - test natural resurrection with reset checkpoint
Remove STEP 7 (document modification) from the resurrection test to validate the BC-994 scenario as it should occur in production: document resurrection WITHOUT any local modification. Changes: - Removed document touch/modification before reset checkpoint - Renumbered STEP 8-14 to STEP 7-13 for consistency - Updated README to clarify no modification occurs - Document should resurrect naturally when reset checkpoint is used Scenario: - Document exists in cblite (unchanged since creation) - Document was deleted from central, tombstone purged - Reset checkpoint causes cblite to re-evaluate all docs - Document is pushed to central WITHOUT oldDoc - Sync function detects: !oldDoc && updatedAt > 1h → soft_delete This validates whether reset checkpoint alone is sufficient to trigger document resurrection, which is the actual BC-994 scenario. If the document is not pushed without modification, this will reveal a limitation of the reset checkpoint mechanism that needs to be addressed differently. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 316876f commit 1d0b885

File tree

2 files changed

+23
-32
lines changed

2 files changed

+23
-32
lines changed

examples/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,18 @@ $ cargo run --features=enterprise --example tombstone_resurrection_test
158158
**Test scenario:**
159159
1. Create doc with updatedAt=NOW, replicate to central, STOP replication
160160
2. Delete doc from central only (cblite keeps it)
161-
3. Wait 65 minutes for tombstone purge + compact
161+
3. Wait 65 minutes for tombstone purge + compact CBS + SGW
162162
4. Verify central tombstone purged
163-
5. Restart replication with reset checkpoint → doc resurrects
163+
5. Restart replication with reset checkpoint → doc resurrects (NO modification to doc)
164164
6. Verify sync function routes to "soft_deleted" channel
165165
7. Verify auto-purge removes doc from cblite
166166
8. Wait 6 minutes for TTL expiry + compact
167167
9. Verify doc purged from central
168168

169+
**Note**: The document is NOT modified before resurrection. The reset checkpoint
170+
alone should cause cblite to re-push the document to central where it will be
171+
detected as a resurrection by the sync function (no oldDoc + updatedAt > 1h).
172+
169173
**Report location**: `test_results/test_run_<timestamp>_<commit_sha>/`
170174

171175
**Sync function logic tested** (from billeo-engine PR #7672):

examples/tombstone_resurrection_test.rs

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -213,21 +213,8 @@ fn main() {
213213
},
214214
);
215215

216-
// STEP 7: Prepare for replication reset - Touch document to force push
217-
reporter.log("STEP 7: Preparing document for replication reset...");
218-
reporter.log(" Touching doc1 to ensure it will be pushed during reset checkpoint...");
219-
220-
// Modify document slightly to trigger a change
221-
{
222-
let mut doc = get_doc(&db_cblite, "doc1").unwrap();
223-
let mut props = doc.mutable_properties();
224-
props.at("_resurrection_test").put_bool(true);
225-
db_cblite.save_document(&mut doc).unwrap();
226-
reporter.log(" ✓ Document modified to trigger replication\n");
227-
}
228-
229-
// STEP 8: Restart replication with RESET CHECKPOINT
230-
reporter.log("STEP 8: Restarting replication with RESET CHECKPOINT...");
216+
// STEP 7: Restart replication with RESET CHECKPOINT
217+
reporter.log("STEP 7: Restarting replication with RESET CHECKPOINT...");
231218
reporter.log(" This simulates a fresh sync where cblite will push doc1 back to central.");
232219
reporter.log(&format!(
233220
" doc1's updatedAt ({}) is now > 1 hour old",
@@ -279,8 +266,8 @@ fn main() {
279266
}
280267
}
281268

282-
// STEP 9: Verify auto-purge in cblite (non-blocking)
283-
reporter.log("STEP 9: Checking if doc1 was auto-purged from cblite...");
269+
// STEP 8: Verify auto-purge in cblite (non-blocking)
270+
reporter.log("STEP 8: Checking if doc1 was auto-purged from cblite...");
284271
reporter.log(" doc1 should be auto-purged because it was routed to 'soft_deleted' channel");
285272
reporter.log(" (user only has access to 'channel1')\n");
286273

@@ -296,8 +283,8 @@ fn main() {
296283
}
297284
}
298285

299-
// STEP 10: Check if doc exists in central with soft_deleted routing
300-
reporter.log("STEP 10: Checking if doc1 exists in central...");
286+
// STEP 9: Check if doc exists in central with soft_deleted routing
287+
reporter.log("STEP 9: Checking if doc1 exists in central...");
301288
reporter.log(" Querying SGW admin API...");
302289
let doc_in_central = check_doc_exists_in_central("doc1");
303290

@@ -343,28 +330,28 @@ fn main() {
343330
reporter.log(" ⚠ Could not retrieve _sync xattr to verify channel routing\n");
344331
}
345332

346-
// STEP 11: Wait for TTL expiry (5 minutes) + compact
347-
reporter.log("STEP 11: Waiting 6 minutes for TTL expiry (5 min TTL + margin)...");
333+
// STEP 10: Wait for TTL expiry (5 minutes) + compact
334+
reporter.log("STEP 10: Waiting 6 minutes for TTL expiry (5 min TTL + margin)...");
348335
for minute in 1..=6 {
349336
reporter.log(&format!(" [{minute}/6] Waiting..."));
350337
std::thread::sleep(std::time::Duration::from_secs(60));
351338
}
352339
reporter.log("✓ Wait complete\n");
353340

354-
// STEP 12: Compact CBS
355-
reporter.log("STEP 12: Compacting CBS bucket (to trigger TTL purge)...");
341+
// STEP 11: Compact CBS
342+
reporter.log("STEP 11: Compacting CBS bucket (to trigger TTL purge)...");
356343
compact_cbs_bucket();
357344
std::thread::sleep(std::time::Duration::from_secs(5));
358345
reporter.log("✓ CBS compaction triggered\n");
359346

360-
// STEP 13: Compact SGW
361-
reporter.log("STEP 13: Compacting SGW database...");
347+
// STEP 12: Compact SGW
348+
reporter.log("STEP 12: Compacting SGW database...");
362349
compact_sgw_database();
363350
std::thread::sleep(std::time::Duration::from_secs(5));
364351
reporter.log("✓ SGW compaction complete\n");
365352

366-
// STEP 14: Verify doc purged from central (TTL expired)
367-
reporter.log("STEP 14: Checking if doc1 was purged from central (TTL expired)...");
353+
// STEP 13: Verify doc purged from central (TTL expired)
354+
reporter.log("STEP 13: Checking if doc1 was purged from central (TTL expired)...");
368355
reporter.log(" Querying SGW admin API...");
369356
let still_in_central = check_doc_exists_in_central("doc1");
370357

@@ -374,13 +361,13 @@ fn main() {
374361
reporter.log(" ⚠ doc1 STILL in central (TTL purge may need more time)\n");
375362
}
376363

377-
let state14 = get_sync_xattr("doc1");
378-
let notes14 = if still_in_central {
364+
let state13 = get_sync_xattr("doc1");
365+
let notes13 = if still_in_central {
379366
vec!["Document STILL in central (TTL may not have expired yet)".to_string()]
380367
} else {
381368
vec!["Document successfully purged from central after TTL expiry".to_string()]
382369
};
383-
reporter.checkpoint("STEP_14_AFTER_TTL_PURGE", state14, notes14);
370+
reporter.checkpoint("STEP_13_AFTER_TTL_PURGE", state13, notes13);
384371

385372
repl_reset.stop(None);
386373

0 commit comments

Comments
 (0)