Skip to content

Remove notifications when they no longer apply - #98

Merged
scosman merged 1 commit into
mainfrom
scosman/close_notifiations
Oct 2, 2026
Merged

scosman merged 1 commit into
mainfrom
scosman/close_notifiations

Conversation

@scosman

@scosman scosman commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

Biscotti posted calendar and "Meeting detected" notifications at .timeSensitive priority and never removed calendar ones. This PR removes each notification (on screen and in Notification Center) when it no longer applies.

  • C1 — calendar notifications expire at start + 5 min. The time is fixed at post time; calendar refreshes do not cancel it. If the Mac wakes after start + 5 min, the late notification is not posted.
  • C2 — a recording start removes all calendar notifications, from any start path.
  • D1 — "Meeting detected" is removed when the call ends (the detector's per-app .stopped signal: mic released for 8 s), in all run states.
  • L1 — launch cleanup. Stale "Meeting detected" notifications are removed; calendar notifications older than 5 min are removed; newer ones get an expiry timer. Countdown notifications are not touched.

Notification priority is unchanged.

Spec: specs/projects/notification_cleanup/

Implementation notes

  • Notifications: .meetingStarting carries start: Date (written to userInfo); new deliveredNotifications() seam + DeliveredNotification; new cancelMeetingStarting(eventKey:), cancelAllMeetingStarting(), cancelAdHocDetected(bundleID:), deliveredOfferNotifications().
  • AppCore: separate expiry-task map (not tied to calendar timer refresh), pure shouldPostCalendarNotification and launchNotificationCleanupPlan helpers.
  • Test fakes now model delivery.

Test plan

  • make precommit-checks (format, lint, 2804 tests) green
  • 28 new unit tests (NotificationsTests/NotificationCleanupTests.swift, AppCoreTests/NotificationCleanupTests.swift)
  • Manual on hardware: calendar notification disappears 5 min after start; "Meeting detected" disappears ~8 s after the call ends; relaunch clears stale notifications

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Calendar meeting notifications are removed five minutes after the meeting starts, including after app relaunch, and are no longer sent if that window has passed.
    • Starting a recording clears meeting notifications, and “Meeting detected” notifications are removed when detection stops.
    • Expired and ad-hoc notifications are cleaned up at launch.

Notifications module:
- Add start: Date to .meetingStarting and write eventStart to userInfo
- Add DeliveredNotification value type and deliveredNotifications() seam
  on NotificationCenterProviding
- Add cancelMeetingStarting(eventKey:), cancelAllMeetingStarting(),
  cancelAdHocDetected(bundleID:), deliveredOfferNotifications() to
  NotificationService
- Both test fakes now model delivery (track delivered list, replace on
  same identifier, filter on remove)

AppCore wiring:
- C1: handleCalendarTimerFired guards with shouldPostCalendarNotification
  (skips post when now >= start + 300s) and schedules an expiry timer
  that removes the notification after 5 minutes
- C2: startRecording cancels all expiry tasks and calls
  cancelAllMeetingStarting to clear calendar notifications
- D1: handleDetectionStopped (now async) calls
  cancelAdHocDetected(bundleID:) for the stopped app
- L1: cleanUpStaleNotificationsOnLaunch queries delivered notifications,
  applies launchNotificationCleanupPlan (pure), removes stale ones
  immediately, and schedules expiry for fresh ones

Deviation from spec: calendarNotificationLifetime constant lives in an
extension (calendar-start timers) rather than the class body, because
the class body was at the 250-line SwiftLint type_body_length limit.
The constant is nonisolated static let, so this is semantically
identical.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 578345de-e02c-4963-9882-436ec072df16

📥 Commits

Reviewing files that changed from the base of the PR and between d80e69c and e816063.

📒 Files selected for processing (20)
  • Packages/BiscottiKit/Sources/AppCore/AppCore.swift
  • Packages/BiscottiKit/Sources/AppCore/PreviewAppCore.swift
  • Packages/BiscottiKit/Sources/Notifications/LiveNotificationCenter.swift
  • Packages/BiscottiKit/Sources/Notifications/NotificationCenterProviding.swift
  • Packages/BiscottiKit/Sources/Notifications/NotificationIdentifiers.swift
  • Packages/BiscottiKit/Sources/Notifications/NotificationKind.swift
  • Packages/BiscottiKit/Sources/Notifications/NotificationService.swift
  • Packages/BiscottiKit/Tests/AppCoreTests/NotificationCleanupTests.swift
  • Packages/BiscottiKit/Tests/BiscottiTestSupport/CoreFixture.swift
  • Packages/BiscottiKit/Tests/NotificationsTests/CancelAdHocTests.swift
  • Packages/BiscottiKit/Tests/NotificationsTests/ContentConstructionTests.swift
  • Packages/BiscottiKit/Tests/NotificationsTests/FakeNotificationCenter.swift
  • Packages/BiscottiKit/Tests/NotificationsTests/ForegroundPresentationTests.swift
  • Packages/BiscottiKit/Tests/NotificationsTests/NotificationCleanupTests.swift
  • Packages/BiscottiKit/Tests/NotificationsTests/RequestIdentifierTests.swift
  • specs/projects/notification_cleanup/architecture.md
  • specs/projects/notification_cleanup/functional_spec.md
  • specs/projects/notification_cleanup/implementation_plan.md
  • specs/projects/notification_cleanup/phase_plans/phase_1.md
  • specs/projects/notification_cleanup/project_overview.md

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.


📝 Walkthrough

Walkthrough

The change adds APIs to query and cancel delivered notifications. AppCore uses them to expire calendar meeting notifications and remove ad-hoc notifications at defined lifecycle events. Tests and specifications cover the notification service and AppCore cleanup behavior.

Changes

Notification cleanup

Layer / File(s) Summary
Delivered-notification contracts and service operations
Packages/BiscottiKit/Sources/Notifications/*, Packages/BiscottiKit/Sources/AppCore/PreviewAppCore.swift, Packages/BiscottiKit/Tests/NotificationsTests/*, Packages/BiscottiKit/Tests/BiscottiTestSupport/CoreFixture.swift, specs/projects/notification_cleanup/architecture.md
The notification provider returns delivered-notification snapshots. Meeting-start notifications carry their start time, and NotificationService parses delivered offers and cancels matching notifications. Live, preview, and test notification centers implement delivered-notification querying. Tests cover cancellation, parsing, timestamp storage, and updated meeting-start inputs.
AppCore expiry and cleanup lifecycle
Packages/BiscottiKit/Sources/AppCore/AppCore.swift, Packages/BiscottiKit/Tests/AppCoreTests/NotificationCleanupTests.swift, specs/projects/notification_cleanup/architecture.md, specs/projects/notification_cleanup/functional_spec.md, specs/projects/notification_cleanup/implementation_plan.md, specs/projects/notification_cleanup/phase_plans/phase_1.md, specs/projects/notification_cleanup/project_overview.md
AppCore skips calendar notifications at or after their five-minute expiry and schedules removal for posted notifications. At launch, it removes delivered ad-hoc and expired meeting notifications and schedules removal for fresh meeting notifications. Recording start removes meeting notifications, and detection stop removes the stopped app’s ad-hoc notification. Tests and specifications cover these cases.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant AppCore
  participant NotificationService
  participant NotificationCenterProviding
  AppCore->>NotificationService: Query delivered offer notifications
  NotificationService->>NotificationCenterProviding: Query delivered notifications
  NotificationCenterProviding-->>NotificationService: Return delivered notification snapshots
  NotificationService-->>AppCore: Return parsed meeting and ad-hoc offers
  AppCore->>NotificationService: Cancel expired meeting or ad-hoc notifications
  AppCore->>AppCore: Schedule expiry for fresh meeting notifications
Loading

Merge Risk: ⚪ Minimal · up to e8160

The notification cleanup changes are mergeable after normal checks. Expiry scheduling supports sleep/wake behavior; manual hardware testing remains useful but does not establish a blocking defect.

Security Architecture Review

Security architecture risk: 🔵 Low · up to e8160

The change reduces stale notification exposure and keeps cleanup within this app’s notifications. No newly expanded access or verified security regression was established. Concurrent delivery and cancellation remain an uncertainty in the cleanup guarantee.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed — The cleanup adapter operates on this app’s notification collection. Bulk calendar cancellation selects meeting-start payloads, and the typed offer reader excludes countdown and unknown kinds; the reviewed cleanup operations do not select other applications’ notifications.

Trust Boundaries and Controls

  • observed — Presentation retains its authorization check. Event keys and bundle IDs select exact identifiers within distinct meeting-start and ad-hoc namespaces rather than serving as arbitrary platform deletion identifiers. Delivered payload parsing accepts only recognized offers with their required identity fields.

Resilience and Maintainability Implications

  • inferred — The recording-start terminal cleanup is not demonstrably atomic with notification publication. It cancels existing expiry tasks and then snapshots delivered calendar notifications; accepted but not-yet-delivered requests could be omitted. Concurrent presentation can also finish after cleanup. Per-identifier removal and post-presentation expiry scheduling mitigate some interleavings, but do not prove the immediate removal guarantee. This is a limitation of the new cleanup control, not an established increase over the previous stale-notification exposure.

Hardening Proposals

  • proposed — If immediate removal on recording start must be a strict privacy guarantee, coordinate publication and cleanup using lifecycle generations and known in-flight identifiers, reconcile requests completing after cancellation, and retain expiry ownership until removal is resolved.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.54% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 71 functions across 15 files. (5 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the pull request's main change: removing obsolete notifications when they no longer apply.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 22.54% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 71 functions across 15 files. (5 skipped: 5 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@scosman
scosman merged commit 8a97312 into main Oct 2, 2026
4 checks passed
@scosman
scosman deleted the scosman/close_notifiations branch October 2, 2026 02:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant