test(notify): anchor dedupe keys to today — CI is red on every PR because a date aged out - #207
test(notify): anchor dedupe keys to today — CI is red on every PR because a date aged out#207abdulsaheel wants to merge 1 commit into
Conversation
The 6 failures in notification_dedupe_test are a TIME BOMB, not a regression.
Nothing in the code changed: the calendar did.
The suite builds date-PREFIXED dedupe keys from a hardcoded `2026-07-23`, and
`FiredKeyStore` prunes dated flags older than `retentionDays` (14). While that
date was recent the keys stayed inside the window and the guard deduped
correctly. Once it aged past 14 days, every key was pruned the moment it was
written, so the second and third emit fired again:
same dedupeKey fires the OS notification exactly once
Expected: <1> Actual: <3>
main passed CI on 2026-08-04, when the date was 12 days old. It has been
failing since the window closed, on the same commit, with no code change and
nothing to point at.
Proved it directly before fixing: substituting today's date into the
unmodified file on origin/main turns all 15 tests green.
Fix is to anchor to `todayLabel()` (already imported here) plus a
`_dayLabelOffset` helper for the next-day case, so the keys sit inside the
retention window permanently -- which is the condition the dedupe guard is
actually specified against. No lib/ change; the guard itself was always correct.
Full suite on this branch: 1201 passing, 0 failing.
WHY THIS MATTERS BEYOND THE 6 TESTS: `flutter test --concurrency=1` is exactly
what test.yml runs, so from the moment that window closed EVERY open PR's CI
went red regardless of content. This unblocks them all.
Worth a follow-up: other suites hardcode dates too (ai_briefing_test,
day_nav_test, readiness_freeze_test, core_screens_test,
sleep_profile_policy_test, db_storage_hygiene_test). Most are not
retention-sensitive, but any test whose subject prunes or windows on age has
the same failure mode latent in it.
📝 WalkthroughWalkthroughThe notification dedupe tests now generate date labels and dedupe keys from today and tomorrow. Existing coverage remains for persistence, permissions, categories, quiet hours, concurrency, retention, and high-stress alerts. ChangesNotification dedupe test updates
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/notification_dedupe_test.dart`:
- Around line 80-87: Update the test label initialization around _today,
_tomorrow, and _dayLabelOffset to capture a single DateTime value, derive both
offsets from that timestamp, and reuse the canonical todayLabel formatter from
lib/data/day_label.dart. Remove the manual formatting in _dayLabelOffset while
preserving the expected today and tomorrow labels.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 28b68b73-480d-4557-bccc-5a4655fd164b
📒 Files selected for processing (1)
test/notification_dedupe_test.dart
| final String _tomorrow = _dayLabelOffset(1); | ||
|
|
||
| String _dayLabelOffset(int days) { | ||
| final d = DateTime.now().add(Duration(days: days)); | ||
| return '${d.year.toString().padLeft(4, '0')}-' | ||
| '${d.month.toString().padLeft(2, '0')}-' | ||
| '${d.day.toString().padLeft(2, '0')}'; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Derive both labels from one timestamp and the canonical formatter.
_dayLabelOffset calls DateTime.now() independently from _today. If initialization crosses local midnight, _tomorrow can skip a calendar day. The manual formatter can also diverge from todayLabel in lib/data/day_label.dart at Line [24].
Capture one DateTime and derive both labels with todayLabel.
Proposed fix
-final String _today = todayLabel();
-final String _tomorrow = _dayLabelOffset(1);
+final _testNow = DateTime.now();
+final String _today = todayLabel(_testNow);
+final String _tomorrow = _dayLabelOffset(_testNow, 1);
-String _dayLabelOffset(int days) {
- final d = DateTime.now().add(Duration(days: days));
- return '${d.year.toString().padLeft(4, '0')}-'
- '${d.month.toString().padLeft(2, '0')}-'
- '${d.day.toString().padLeft(2, '0')}';
-}
+String _dayLabelOffset(DateTime base, int days) =>
+ todayLabel(DateTime(base.year, base.month, base.day + days));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/notification_dedupe_test.dart` around lines 80 - 87, Update the test
label initialization around _today, _tomorrow, and _dayLabelOffset to capture a
single DateTime value, derive both offsets from that timestamp, and reuse the
canonical todayLabel formatter from lib/data/day_label.dart. Remove the manual
formatting in _dayLabelOffset while preserving the expected today and tomorrow
labels.
This is currently blocking CI on every open PR. Nothing is wrong with any of them, and nothing is wrong with
lib/— the calendar advanced.What happened
notification_dedupe_testbuilds date-prefixed dedupe keys from a hardcoded2026-07-23.FiredKeyStoreprunes dated flags older thanretentionDays(14). While that date was recent the keys stayed inside the window and the guard deduped correctly. Once it aged past 14 days, every key was pruned the instant it was written, so the second and third emit fired again:mainpassed CI on 2026-08-04, when that date was 12 days old. It has been failing ever since the window closed — on the same commit, with no code change and nothing to point at.Proof before fix
Substituting today's date into the unmodified file on
origin/mainturns all 15 tests green. That isolates the cause completely: the guard was never broken.The fix
Anchor to
todayLabel()(already imported in this file) plus a small_dayLabelOffsethelper for the next-day case, so the keys sit inside the retention window permanently — which is the condition the dedupe guard is actually specified against.No
lib/change. Full suite on this branch: 1201 passing, 0 failing.Why it matters beyond these 6 tests
flutter test --concurrency=1is exactly whattest.ymlruns. From the moment that window closed, every open PR's CI went red regardless of content. Merging this unblocks all of them.Follow-up worth considering
Other suites hardcode dates too —
ai_briefing_test,day_nav_test,readiness_freeze_test,core_screens_test,sleep_profile_policy_test,db_storage_hygiene_test. Most aren't retention-sensitive, but any test whose subject prunes or windows on age carries the same failure mode latent. A lint or a sharedtodayLabel()-based fixture helper would close the class.Also note: fork PRs are currently sitting at
action_required— they need "Approve and run workflows" before any of them can show a green check.Summary by CodeRabbit