Skip to content

feat(heartbeat): deliver durable proactive meeting/reminder notifications with dedup + category controls#1369

Merged
senamakel merged 7 commits intotinyhumansai:mainfrom
YellowSnnowmann:feat/notify-meetings
May 9, 2026
Merged

feat(heartbeat): deliver durable proactive meeting/reminder notifications with dedup + category controls#1369
senamakel merged 7 commits intotinyhumansai:mainfrom
YellowSnnowmann:feat/notify-meetings

Conversation

@YellowSnnowmann
Copy link
Copy Markdown
Contributor

@YellowSnnowmann YellowSnnowmann commented May 8, 2026

Summary

  • Added a heartbeat event planner:

    • Evaluates upcoming meetings, reminders, and urgent relevant events
    • Emits proactive notifications on each tick
  • Added persistent dedup state:

    • heartbeat_state.db
    • Prevents duplicate notifications across:
      • ticks
      • restarts
      • overlapping sources
  • Integrated calendar-aware detection:

    • Google Calendar (Composio)
    • cron/reminder sources
    • urgent/relevant notification signals
  • Added heartbeat notification settings + RPC/controller APIs:

    • settings_get
    • settings_set
    • tick_now
  • Extended notification categories:

    • meetings
    • reminders
    • important
    • Added across Rust core + app settings/UI
  • Made heartbeat alerts durable:

    • Persisted in notification storage
    • In addition to socket push delivery

Problem

  • Existing heartbeat/notification primitives lacked a complete proactive event workflow

  • Upcoming meetings/reminders could be missed:

    • Narrow scheduler timing windows
    • Non-durable delivery paths
  • No dedicated dedup layer:

    • Duplicate sends possible across:
      • restarts
      • overlapping ticks
  • Users lacked controls for proactive notification categories


Solution

Heartbeat Planner

Implemented a dedicated planner that:

  • Collects event candidates from:

    • cron reminder jobs
    • Google Calendar integrations
    • relevant/urgent notification signals
  • Computes staged delivery windows:

    • heads-up
    • final
    • now
  • Records send markers in SQLite:

    • INSERT OR IGNORE
    • Ensures strict deduplication
  • Publishes via:

    • existing core_notification
    • optional proactive external routing

Heartbeat Configuration

Added new HeartbeatConfig settings:

  • notify_meetings
  • notify_reminders
  • notify_relevant_events
  • external_delivery_enabled
  • meeting_lookahead_minutes
  • reminder_lookahead_minutes

RPC / Controller Surface

Added heartbeat endpoints:

  • inspect settings
  • update settings
  • manually trigger planner

Notification Model Updates

Extended notification categories and settings UI to support:

  • meetings
  • reminders
  • important events

Reliability Improvements

  • Widened “due/starting-now” grace windows
  • Persist heartbeat alerts in notifications storage
  • Reduces missed alerts from scheduler cadence

Tradeoffs

  • Calendar detection depends on:

    • active Composio Google Calendar integration
  • Does NOT use:

    • direct webview scraping
  • Favors:

    • explicit integration boundaries
    • cleaner security/data ownership

Submission Checklist

  • Tests

    • Added/updated per docs/TESTING-STRATEGY.md
    • Includes:
      • happy paths
      • failure/edge cases
  • Coverage

    • Diff coverage ≥ 80%
    • Enforced via:
      • .github/workflows/coverage.yml
    • Commands:
      • pnpm test:coverage
      • pnpm test:rust
  • Coverage Matrix

    • Updated in:
      • docs/TEST-COVERAGE-MATRIX.md
    • Or marked N/A where applicable
  • Feature IDs

    • Listed under ## Related
  • Network Dependencies

    • No new external dependencies
    • Uses mock backend per testing strategy
  • Manual Smoke Checklist

    • Updated if release-cut surfaces affected:
      • docs/RELEASE-MANUAL-SMOKE.md
  • Linked Issues

    • Added via:
      • Closes #NNN

Related

  • Closes #NNN

Impact

Platform / Runtime

  • Affects:
    • Rust heartbeat domain
    • notifications domain
    • desktop app notification settings/UI

Performance

  • Small additional heartbeat tick work:

    • source checks
    • dedup DB writes
  • Overhead bounded by:

    • lookahead windows
    • capped queries

Security / Privacy

  • Logging remains metadata-focused:

    • stable IDs
    • source
    • category
    • stage
  • Avoids full private payload logging

  • External proactive delivery requires:

    • explicit heartbeat consent flag

Compatibility / Migration

  • Backward compatible config evolution via defaults

  • Existing notification preferences gain new categories:

    • meetings
    • reminders
    • important

Related

Summary by CodeRabbit

  • New Features

    • Added three notification categories: Meetings, Reminders, Important events (preferences, labels, routing).
    • Proactive heartbeat planner surfaces upcoming calendar events, reminders, and relevant notifications with deduplication, persistence, and configurable lookahead/delivery options.
    • Heartbeat RPC controls: view, update, and trigger planner runs with validated timing clamps.
  • Tests

    • Added/expanded tests for categories, routing, rehydration, planner collection, persistence, dedupe, and delivery logic.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a812b47-8626-4be9-ab52-29a20f8e2d57

📥 Commits

Reviewing files that changed from the base of the PR and between ee43d02 and 36272b5.

📒 Files selected for processing (1)
  • app/src/store/__tests__/notificationSlice.test.ts

📝 Walkthrough

Walkthrough

Adds meetings, reminders, and important notification categories across frontend and backend; implements a heartbeat planner that collects cron reminders, calendar meetings, and relevant notifications, deduplicates via a SQLite store, persists integration notifications, exposes RPCs/schemas, and integrates planner ticks into the heartbeat loop.

Heartbeat Proactive Notifications Feature

Layer / File(s) Summary
Notification Types & Frontend
src/openhuman/notifications/types.rs, app/src/store/notificationSlice.ts, app/src/components/settings/panels/NotificationsPanel.tsx, app/src/pages/Notifications.tsx, app/src/lib/notificationRouter.ts, app/src/lib/notificationRouter.test.ts, app/src/store/__tests__/settingsSlice.test.ts, app/src/store/__tests__/notificationSlice.test.ts
Adds meetings, reminders, important categories; updates enums, preferences, initialState, UI toggles/labels, router mappings, tests, and REHYDRATE backfill.
Heartbeat Config Schema
src/openhuman/config/schema/heartbeat_cron.rs
Adds notify_meetings, notify_reminders, notify_relevant_events, external_delivery_enabled, and meeting/reminder lookahead minute fields with serde defaults and Default initialization.
Planner Types & Utilities
src/openhuman/heartbeat/planner/types.rs, src/openhuman/heartbeat/planner/utils.rs
Adds planner enums/structs (HeartbeatCategory, PendingEvent, PlannedDelivery, PlannerRunSummary) and utilities: sanitize_preview, stable_key, compute_overlap_key.
Event Collectors
src/openhuman/heartbeat/planner/collectors.rs
Adds collectors for cron reminders, calendar meetings (Composio extraction), and recent relevant notifications; computes fingerprints, overlap keys, titles, deep links, and anchor timestamps.
Planning, Persistence & Store
src/openhuman/heartbeat/planner/plan.rs, src/openhuman/heartbeat/planner/persistence.rs, src/openhuman/heartbeat/planner/store.rs
Implements plan_delivery_for_event, persist_heartbeat_alert, and SQLite-backed sent-marker store with mark_sent/prune_old and unit tests.
Planner Core Implementation
src/openhuman/heartbeat/planner/mod.rs
Implements evaluate_and_dispatch to collect events, compute deliveries, deduplicate, persist notifications, publish/internal dispatch, and prune markers; includes unit tests for extraction, windows, dedupe, and behavior.
RPC Handlers & Controller Schemas
src/openhuman/heartbeat/rpc.rs, src/openhuman/heartbeat/schemas.rs
Adds RPC endpoints settings_get, settings_set, tick_now, patch/view types, controller schema registry, and CLI handler wiring; enforces minimums on lookahead/interval fields.
Engine Integration & Exports
src/openhuman/heartbeat/engine.rs, src/openhuman/heartbeat/mod.rs
Runs planner tick at loop start (before sleep), provides run_event_planner_tick helper, and exports planner and rpc modules.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • senamakel

Poem

🐰 I hop on heartbeats to catch meetings near,
Reminders whisper softly in my ear.
I sanitize previews and guard against repeat,
Dedupe keys steady each gentle heartbeat.
Here’s a rabbit’s nudge — small, tidy, and clear.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. 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 accurately summarizes the main change: implementing durable proactive heartbeat notifications with deduplication and category controls for meetings/reminders.
Linked Issues check ✅ Passed All core requirements from issue #1340 are met: heartbeat event detection (meetings, reminders, relevant events), deduplication layer, delivery routing with settings controls, user preferences UI, durable persistence, logging safety, and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing heartbeat planner, notification routing, settings persistence, and category controls. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@YellowSnnowmann YellowSnnowmann marked this pull request as ready for review May 8, 2026 11:06
@YellowSnnowmann YellowSnnowmann requested a review from a team May 8, 2026 11:06
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (1)
src/openhuman/heartbeat/rpc.rs (1)

36-92: ⚡ Quick win

Add stable debug/trace logs around the new heartbeat RPC entrypoints.

These handlers currently rely on the returned RpcOutcome, but the repo guidance for new RPC flows is stronger than that. A couple of [heartbeat][rpc] entry/exit/error logs around settings_get, settings_set, and tick_now would make support and incident triage much easier without logging sensitive payloads.

As per coding guidelines, src/**/*.rs: “Use log / tracing at debug or trace level on RPC entry/exit, error paths, state transitions... include stable prefixes.”

🤖 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 `@src/openhuman/heartbeat/rpc.rs` around lines 36 - 92, Add stable debug/trace
logs with the prefix "[heartbeat][rpc]" at entry and exit (and on errors) for
settings_get, settings_set, and tick_now: log when each RPC is entered (function
name + normalized non-sensitive markers), log successful exit with outcome
summary (no sensitive config fields), and log failures around
config::rpc::load_config_with_timeout(), config.save(), and
planner::evaluate_and_dispatch() including the error string; place logs inside
settings_get, settings_set, and tick_now near the calls to
config::rpc::load_config_with_timeout, config.save, and
planner::evaluate_and_dispatch so you capture start/finish/error for each
operation without emitting sensitive payloads.
🤖 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 `@app/src/store/notificationSlice.ts`:
- Around line 50-58: Add a migrate step to notificationPersistConfig (or handle
in a REHYDRATE extraReducer) that backfills missing keys on rehydration so older
persisted preferences gain meetings, reminders, and important; specifically,
implement a migrate(oldState) that returns Object.assign({}, oldState, {
preferences: Object.assign({ messages: true, agents: true, skills: true, system:
true, meetings: true, reminders: true, important: true }, oldState?.preferences
|| {}) }) (or the equivalent logic in the REHYDRATE handler) so
notificationPersistConfig and the code that checks
state.preferences[item.category] see those keys present after rehydration.

In `@src/openhuman/heartbeat/engine.rs`:
- Around line 45-46: The planner loop currently always calls
run_event_planner_tick() even when config.heartbeat.enabled == false; update the
loop to reload/read the current config and short-circuit (continue/return) when
config.heartbeat.enabled is false so the tick is skipped, i.e., check
config.heartbeat.enabled before invoking run_event_planner_tick(); apply the
same guard wherever run_event_planner_tick() is called later in this file (the
other invocation region around the block noted at 94-111) so planner ticks stop
immediately when heartbeat is disabled.

In `@src/openhuman/heartbeat/planner/mod.rs`:
- Around line 134-179: mark_sent is currently called before
persist_heartbeat_alert, which lets dedupe rows suppress future retries even if
the durable notification write fails; move the durable write ahead of marking.
Specifically: call persist_heartbeat_alert (and ensure it returns an error on
failure) and only call store::mark_sent (or store::mark_sent in the other
similar block) after persist_heartbeat_alert succeeds; on
persist_heartbeat_alert failure do not call mark_sent, increment
summary.deliveries_failed (or appropriate counter) and continue/retry behavior
instead of creating the dedupe marker, and keep publish_core_notification
executed only after both durable persist and mark_sent succeed (or guard
publish_core_notification behind the same success check). Ensure both code paths
referenced (the shown block and the 635-680 duplicate) are updated accordingly.
- Around line 470-499: collect_relevant_notifications currently calls
notifications_store::list with a score cutoff (Some(0.8)) which filters out
low/no-score items before we can check triage_action ("escalate" or "react") or
raw_payload.urgent; change the list call to not apply the importance_score
threshold (pass None for the last argument instead of Some(0.8)) so all
candidate notifications are returned, then keep the existing downstream filters
(provider != "heartbeat", status == Unread, triage_action/raw_payload checks,
and recent received_at) so the planner can surface urgent or action-worthy items
regardless of their score.
- Around line 119-124: The dedupe key is currently source-scoped because it uses
event.fingerprint; replace that with an overlap-scoped identifier so identical
underlying events from multiple sources collide. Add or use a function like
compute_overlap_key(event) (or event.overlap_id / event.occurrence_id if
available) and build the stable_key from format!("{}|{}|{}",
event.category.as_str(), compute_overlap_key(event), plan.stage) instead of
event.fingerprint; apply the same change to the other identical key
constructions (the other occurrences of the same pattern) so deduplication is
based on the overlapping event identity rather than the source-specific
fingerprint.
- Around line 373-407: The parser currently treats all-day events as timed
events because extract_datetime_from_map falls back from start.dateTime to
start.date, producing a 00:00 UTC starts_at; update the logic to skip all-day
entries before creating a PendingEvent for HeartbeatCategory::Meetings by
detecting a start.date field (or by changing extract_datetime_from_map to only
return Some for dateTime and return None for all-day dates). In practice either
(a) modify extract_datetime_from_map to refuse date-only values so starts_at is
None for all-day events, or (b) add an explicit check where starts_at is used
(before constructing PendingEvent in this block and the similar block at
425-467) to continue/skip if map["start"] contains a "date" key, ensuring only
timed events are promoted to HeartbeatCategory::Meetings and anchor_at uses a
real dateTime.
- Around line 18-681: Summary: mod.rs is too large and should be split into
export-focused sibling modules; move collectors, planning, persistence, and
helpers into smaller files and re-export them from mod.rs. Fix: create
collectors.rs and move collect_cron_reminders, collect_calendar_meetings,
collect_relevant_notifications, extract_calendar_events,
collect_calendar_events_recursive, extract_datetime_from_map,
extract_title_from_map, parse_datetime there; create planner.rs (or
planner_core.rs) and move evaluate_and_dispatch, plan_delivery_for_event,
PendingEvent, PlannedDelivery, HeartbeatCategory and PlannerRunSummary there;
create persistence.rs and move persist_heartbeat_alert, stable_key and the
notifications_store/store:: calls there; create utils.rs for sanitize_preview
and any small helpers; update mod.rs to only pub mod and pub use the moved
symbols (e.g., pub use planner::{evaluate_and_dispatch, PlannerRunSummary}; pub
use collectors::collect_*; etc.), and adjust internal imports/paths so functions
like evaluate_and_dispatch still call store::mark_sent and notifications_store
via the new modules; ensure Cargo/Rust visibility (pub(crate)/pub) and
tests/imports are updated accordingly.

In `@src/openhuman/heartbeat/rpc.rs`:
- Around line 52-54: The RPC handler currently writes interval_minutes down to 1
(using interval_minutes.max(1)), which contradicts HeartbeatConfig's documented
5-minute minimum and HeartbeatEngine::run's enforcement; change the assignment
in the patch handling so that when patch.interval_minutes is Some, you store
config.heartbeat.interval_minutes = interval_minutes.max(5) (clamping to 5)
instead of .max(1) so persisted settings match the runtime behavior and
settings_get reports a valid cadence.

---

Nitpick comments:
In `@src/openhuman/heartbeat/rpc.rs`:
- Around line 36-92: Add stable debug/trace logs with the prefix
"[heartbeat][rpc]" at entry and exit (and on errors) for settings_get,
settings_set, and tick_now: log when each RPC is entered (function name +
normalized non-sensitive markers), log successful exit with outcome summary (no
sensitive config fields), and log failures around
config::rpc::load_config_with_timeout(), config.save(), and
planner::evaluate_and_dispatch() including the error string; place logs inside
settings_get, settings_set, and tick_now near the calls to
config::rpc::load_config_with_timeout, config.save, and
planner::evaluate_and_dispatch so you capture start/finish/error for each
operation without emitting sensitive payloads.
🪄 Autofix (Beta)

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: CHILL

Plan: Pro

Run ID: ba0287be-5762-4f39-bcbd-f3e793ef20b2

📥 Commits

Reviewing files that changed from the base of the PR and between 26ff73a and f84f318.

📒 Files selected for processing (13)
  • app/src/components/settings/panels/NotificationsPanel.tsx
  • app/src/lib/notificationRouter.ts
  • app/src/pages/Notifications.tsx
  • app/src/store/__tests__/settingsSlice.test.ts
  • app/src/store/notificationSlice.ts
  • src/openhuman/config/schema/heartbeat_cron.rs
  • src/openhuman/heartbeat/engine.rs
  • src/openhuman/heartbeat/mod.rs
  • src/openhuman/heartbeat/planner/mod.rs
  • src/openhuman/heartbeat/planner/store.rs
  • src/openhuman/heartbeat/rpc.rs
  • src/openhuman/heartbeat/schemas.rs
  • src/openhuman/notifications/types.rs

Comment thread app/src/store/notificationSlice.ts
Comment thread src/openhuman/heartbeat/engine.rs
Comment thread src/openhuman/heartbeat/planner/mod.rs Outdated
Comment thread src/openhuman/heartbeat/planner/mod.rs
Comment thread src/openhuman/heartbeat/planner/mod.rs
Comment thread src/openhuman/heartbeat/planner/mod.rs Outdated
Comment thread src/openhuman/heartbeat/planner/mod.rs Outdated
Comment thread src/openhuman/heartbeat/rpc.rs
…tegories

Add three missing test cases for the new notification categories introduced
in the previous commit. Covers lines 91-92, 94-95, 97-98 of notificationRouter.ts
which were flagged at 0% by diff-cover, bringing changed-line coverage above 80%.
The dedupe key was previously derived from event.fingerprint, which is
source-specific (cron job ID, calendar connection/event ID, notification ID).
This meant the same underlying event surfaced by two different sources
(e.g. a meeting visible in both a cron reminder and a Google Calendar
connection) produced distinct dedupe keys and could generate duplicate
notifications.

Add an overlap_key to PendingEvent computed from category + normalized
title + 15-minute time bucket. Use overlap_key instead of fingerprint
when building the final dedupe hash in evaluate_and_dispatch so identical
events from multiple sources collide on the same key.

Also adds compute_overlap_key() helper to utils.rs and two new unit tests
that verify same-bucket/cross-source collision and different-title/time
separation. Fixes @coderabbitai comment on planner/mod.rs:124.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/openhuman/heartbeat/planner/plan.rs (1)

88-107: 💤 Low value

Consider adding a lower bound for Important events.

The condition now.signed_duration_since(event.anchor_at) <= Duration::minutes(10) only checks the upper bound. An event with anchor_at from hours/days ago would still match. While collectors filter by recency (30 minutes for notifications), this function could be more defensive.

💡 Optional defensive bound
         HeartbeatCategory::Important => {
-            if now.signed_duration_since(event.anchor_at) <= Duration::minutes(10) {
+            let since_anchor = now.signed_duration_since(event.anchor_at);
+            if since_anchor >= Duration::zero() && since_anchor <= Duration::minutes(10) {
                 return Some(PlannedDelivery {
🤖 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 `@src/openhuman/heartbeat/planner/plan.rs` around lines 88 - 107, The Important
branch currently only checks an upper bound using
now.signed_duration_since(event.anchor_at) which allows very old anchors to
match; compute the signed duration once (e.g., let delta =
now.signed_duration_since(event.anchor_at)) and require a lower and upper bound
(for example delta >= Duration::minutes(0) && delta <= Duration::minutes(10))
before returning the PlannedDelivery in HeartbeatCategory::Important so only
items within the recent window are considered; update the condition around the
PlannedDelivery creation accordingly.
🤖 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 `@app/src/store/notificationSlice.ts`:
- Line 1: This file fails Prettier formatting; run the project formatter (e.g.
npm run format from the repo root or prettier --write the source file) to fix
style issues in the notification slice (imports referencing createSlice and type
PayloadAction and the notificationSlice code) and re-commit the formatted file.
- Around line 156-175: The REHYDRATE handler in builder.addCase is incorrectly
checking rehydrateAction.meta?.arg; update the type assertion for the action and
change the filter to use action.key === 'notifications' (the redux-persist
persist key) instead of meta?.arg so the backfill runs; keep the existing logic
that merges payload.preferences into state.preferences (using
initialState.preferences and payload.preferences) so missing keys are filled
(refer to REHYDRATE, rehydrateAction, state.preferences and
initialState.preferences).

In `@src/openhuman/heartbeat/planner/mod.rs`:
- Around line 390-434: The test functions
overlap_key_same_for_cross_source_same_event and
overlap_key_differs_for_different_titles_or_times are misformatted; run rustfmt
(cargo fmt) across the repo or on the Rust sources, reformat the code so
compute_overlap_key usages and the Duration::minutes calls align with project
style, then re-run cargo fmt and cargo check and commit the reformatted changes
(ensuring tests referencing compute_overlap_key and HeartbeatCategory::Meetings
remain unchanged functionally).

In `@src/openhuman/heartbeat/planner/utils.rs`:
- Around line 43-44: The two consecutive assignments to normalized_title need
rustfmt formatting; run `cargo fmt` (or reformat the expression) so the chain is
idiomatically formatted — for example collapse the operations into a single
statement on normalized_title (use
title.to_ascii_lowercase().split_whitespace().collect::<Vec<_>>().join(" ")) and
then run `cargo fmt` and `cargo check` to ensure CI passes; locate the code
around the normalized_title variable in utils.rs to apply this change.

---

Nitpick comments:
In `@src/openhuman/heartbeat/planner/plan.rs`:
- Around line 88-107: The Important branch currently only checks an upper bound
using now.signed_duration_since(event.anchor_at) which allows very old anchors
to match; compute the signed duration once (e.g., let delta =
now.signed_duration_since(event.anchor_at)) and require a lower and upper bound
(for example delta >= Duration::minutes(0) && delta <= Duration::minutes(10))
before returning the PlannedDelivery in HeartbeatCategory::Important so only
items within the recent window are considered; update the condition around the
PlannedDelivery creation accordingly.
🪄 Autofix (Beta)

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: CHILL

Plan: Pro

Run ID: 390034fb-4b2c-49bc-be69-7f6ad033e43a

📥 Commits

Reviewing files that changed from the base of the PR and between 2199b12 and 87feebe.

📒 Files selected for processing (9)
  • app/src/store/notificationSlice.ts
  • src/openhuman/heartbeat/engine.rs
  • src/openhuman/heartbeat/planner/collectors.rs
  • src/openhuman/heartbeat/planner/mod.rs
  • src/openhuman/heartbeat/planner/persistence.rs
  • src/openhuman/heartbeat/planner/plan.rs
  • src/openhuman/heartbeat/planner/types.rs
  • src/openhuman/heartbeat/planner/utils.rs
  • src/openhuman/heartbeat/rpc.rs
✅ Files skipped from review due to trivial changes (1)
  • src/openhuman/heartbeat/planner/types.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/openhuman/heartbeat/rpc.rs

Comment thread app/src/store/notificationSlice.ts
Comment thread app/src/store/notificationSlice.ts
Comment thread src/openhuman/heartbeat/planner/mod.rs
Comment thread src/openhuman/heartbeat/planner/utils.rs Outdated
… notificationSlice

redux-persist sets action.key, not action.meta.arg, so the previous guard
always evaluated undefined !== 'notifications' (true) and returned early,
making the preferences backfill for meetings/reminders/important a no-op
for existing users.
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 8, 2026
@senamakel senamakel merged commit 0a749f5 into tinyhumansai:main May 9, 2026
21 checks passed
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.

Notify users about upcoming meetings and reminders

2 participants