feat(me): add 30-day mention age cutoff to filter stale @-mentions
Previously, query_mentioned_in returned mentions from any time in the entity's history as long as the entity was still open (or recently closed). This caused noise: a mention from 6 months ago on a still-open issue would appear in the dashboard indefinitely. Now the SQL filters notes by created_at > mention_cutoff_ms, defaulting to 30 days. The recency_cutoff (7 days) still governs closed/merged entity visibility — this new cutoff governs mention note age on open entities. Signature change: query_mentioned_in gains a mention_cutoff_ms parameter. All existing test call sites updated. Two new tests verify the boundary: - mentioned_in_excludes_old_mention_on_open_issue (45-day mention filtered) - mentioned_in_includes_recent_mention_on_open_issue (5-day mention kept)
This commit is contained in:
@@ -946,7 +946,7 @@ fn mentioned_in_finds_mention_on_unassigned_issue() {
|
||||
);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert_eq!(results.len(), 1);
|
||||
assert_eq!(results[0].entity_type, "issue");
|
||||
assert_eq!(results[0].iid, 42);
|
||||
@@ -964,7 +964,7 @@ fn mentioned_in_excludes_assigned_issue() {
|
||||
insert_note_at(&conn, 200, disc_id, 1, "bob", false, "hey @alice", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert!(results.is_empty(), "should exclude assigned issues");
|
||||
}
|
||||
|
||||
@@ -979,7 +979,7 @@ fn mentioned_in_excludes_authored_issue() {
|
||||
insert_note_at(&conn, 200, disc_id, 1, "bob", false, "hey @alice", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert!(results.is_empty(), "should exclude authored issues");
|
||||
}
|
||||
|
||||
@@ -995,7 +995,7 @@ fn mentioned_in_finds_mention_on_non_authored_mr() {
|
||||
insert_note_at(&conn, 200, disc_id, 1, "bob", false, "cc @alice", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert_eq!(results.len(), 1);
|
||||
assert_eq!(results[0].entity_type, "mr");
|
||||
assert_eq!(results[0].iid, 99);
|
||||
@@ -1012,7 +1012,7 @@ fn mentioned_in_excludes_authored_mr() {
|
||||
insert_note_at(&conn, 200, disc_id, 1, "bob", false, "@alice thoughts?", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert!(results.is_empty(), "should exclude authored MRs");
|
||||
}
|
||||
|
||||
@@ -1028,7 +1028,7 @@ fn mentioned_in_excludes_reviewer_mr() {
|
||||
insert_note_at(&conn, 200, disc_id, 1, "charlie", false, "@alice fyi", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert!(
|
||||
results.is_empty(),
|
||||
"should exclude MRs where user is reviewer"
|
||||
@@ -1052,7 +1052,7 @@ fn mentioned_in_includes_recently_closed_issue() {
|
||||
insert_note_at(&conn, 200, disc_id, 1, "bob", false, "hey @alice", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert_eq!(results.len(), 1, "recently closed issue should be included");
|
||||
assert_eq!(results[0].state, "closed");
|
||||
}
|
||||
@@ -1074,7 +1074,7 @@ fn mentioned_in_excludes_old_closed_issue() {
|
||||
insert_note_at(&conn, 200, disc_id, 1, "bob", false, "hey @alice", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert!(results.is_empty(), "old closed issue should be excluded");
|
||||
}
|
||||
|
||||
@@ -1099,7 +1099,7 @@ fn mentioned_in_attention_needs_attention_when_unreplied() {
|
||||
// alice has NOT replied
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert_eq!(results.len(), 1);
|
||||
assert_eq!(results[0].attention_state, AttentionState::NeedsAttention);
|
||||
}
|
||||
@@ -1126,7 +1126,7 @@ fn mentioned_in_attention_awaiting_when_replied() {
|
||||
insert_note_at(&conn, 201, disc_id, 1, "alice", false, "looks good", t2);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert_eq!(results.len(), 1);
|
||||
assert_eq!(results[0].attention_state, AttentionState::AwaitingResponse);
|
||||
}
|
||||
@@ -1147,7 +1147,7 @@ fn mentioned_in_project_filter() {
|
||||
insert_note_at(&conn, 201, disc_b, 2, "bob", false, "@alice", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[1], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[1], recency_cutoff, 0).unwrap();
|
||||
assert_eq!(results.len(), 1);
|
||||
assert_eq!(results[0].project_path, "group/repo-a");
|
||||
}
|
||||
@@ -1166,7 +1166,7 @@ fn mentioned_in_deduplicates_multiple_mentions_same_entity() {
|
||||
insert_note_at(&conn, 201, disc_id, 1, "charlie", false, "@alice +1", t2);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert_eq!(results.len(), 1, "should deduplicate to one entity");
|
||||
}
|
||||
|
||||
@@ -1190,10 +1190,47 @@ fn mentioned_in_rejects_false_positive_email() {
|
||||
);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff).unwrap();
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, 0).unwrap();
|
||||
assert!(results.is_empty(), "email-like text should not match");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mentioned_in_excludes_old_mention_on_open_issue() {
|
||||
let conn = setup_test_db();
|
||||
insert_project(&conn, 1, "group/repo");
|
||||
insert_issue(&conn, 10, 1, 42, "someone");
|
||||
let disc_id = 100;
|
||||
insert_discussion(&conn, disc_id, 1, None, Some(10));
|
||||
// Mention from 45 days ago — outside 30-day mention window
|
||||
let t = now_ms() - 45 * 24 * 3600 * 1000;
|
||||
insert_note_at(&conn, 200, disc_id, 1, "bob", false, "hey @alice", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let mention_cutoff = now_ms() - 30 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, mention_cutoff).unwrap();
|
||||
assert!(
|
||||
results.is_empty(),
|
||||
"mentions older than 30 days should be excluded"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mentioned_in_includes_recent_mention_on_open_issue() {
|
||||
let conn = setup_test_db();
|
||||
insert_project(&conn, 1, "group/repo");
|
||||
insert_issue(&conn, 10, 1, 42, "someone");
|
||||
let disc_id = 100;
|
||||
insert_discussion(&conn, disc_id, 1, None, Some(10));
|
||||
// Mention from 5 days ago — within 30-day window
|
||||
let t = now_ms() - 5 * 24 * 3600 * 1000;
|
||||
insert_note_at(&conn, 200, disc_id, 1, "bob", false, "hey @alice", t);
|
||||
|
||||
let recency_cutoff = now_ms() - 7 * 24 * 3600 * 1000;
|
||||
let mention_cutoff = now_ms() - 30 * 24 * 3600 * 1000;
|
||||
let results = query_mentioned_in(&conn, "alice", &[], recency_cutoff, mention_cutoff).unwrap();
|
||||
assert_eq!(results.len(), 1, "recent mentions should be included");
|
||||
}
|
||||
|
||||
// ─── Helper Tests ──────────────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user