huskies: merge 538_bug_done_archived_sweep_never_fires_because_stage_done_projection_uses_utc_now_instead_of_real_merged_at_timestamp
This commit is contained in:
@@ -349,6 +349,7 @@ pub(crate) fn sweep_done_to_archived(done_retention: Duration) {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
slog!("[watcher] sweep: promoted {story_id} → 6_archived/");
|
||||
}
|
||||
@@ -1125,4 +1126,78 @@ mod tests {
|
||||
"item should be archived with zero retention"
|
||||
);
|
||||
}
|
||||
|
||||
/// Prove that the sweep reads `merged_at` from the CRDT (not `Utc::now()`).
|
||||
///
|
||||
/// This test sets `merged_at` to 10 seconds in the past and uses a 5-second
|
||||
/// retention. If the sweep were still using `Utc::now()` as the start time
|
||||
/// (the original bug), the elapsed time would be ~0 and the item would NOT
|
||||
/// be swept. With the fix, the item is swept because 10s > 5s retention.
|
||||
#[test]
|
||||
fn sweep_uses_crdt_merged_at_not_utc_now() {
|
||||
crate::db::ensure_content_store();
|
||||
|
||||
let ten_seconds_ago =
|
||||
(chrono::Utc::now() - chrono::Duration::seconds(10)).timestamp() as f64;
|
||||
|
||||
// Write item in 5_done with an explicit past merged_at timestamp.
|
||||
crate::crdt_state::write_item(
|
||||
"9883_story_sweep_merged_at",
|
||||
"5_done",
|
||||
Some("merged_at test"),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(ten_seconds_ago),
|
||||
);
|
||||
|
||||
// 5-second retention: item is 10s old → should be swept.
|
||||
sweep_done_to_archived(Duration::from_secs(5));
|
||||
|
||||
let items = crate::pipeline_state::read_all_typed();
|
||||
let item = items
|
||||
.iter()
|
||||
.find(|i| i.story_id.0 == "9883_story_sweep_merged_at");
|
||||
assert!(
|
||||
item.is_some_and(|i| matches!(i.stage, crate::pipeline_state::Stage::Archived { .. })),
|
||||
"item with merged_at 10s ago should be archived with 5s retention"
|
||||
);
|
||||
}
|
||||
|
||||
/// Prove that an item with merged_at NEWER than done_retention is NOT swept.
|
||||
#[test]
|
||||
fn sweep_keeps_item_newer_than_retention() {
|
||||
crate::db::ensure_content_store();
|
||||
|
||||
let one_second_ago =
|
||||
(chrono::Utc::now() - chrono::Duration::seconds(1)).timestamp() as f64;
|
||||
|
||||
crate::crdt_state::write_item(
|
||||
"9884_story_sweep_recent",
|
||||
"5_done",
|
||||
Some("recent merged_at test"),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(one_second_ago),
|
||||
);
|
||||
|
||||
// 1-hour retention: item is only 1s old → should NOT be swept.
|
||||
sweep_done_to_archived(Duration::from_secs(3600));
|
||||
|
||||
let items = crate::pipeline_state::read_all_typed();
|
||||
let item = items
|
||||
.iter()
|
||||
.find(|i| i.story_id.0 == "9884_story_sweep_recent");
|
||||
assert!(
|
||||
item.is_some_and(|i| matches!(i.stage, crate::pipeline_state::Stage::Done { .. })),
|
||||
"item with merged_at 1s ago should stay in Done with 1-hour retention"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user