feat(9.14.9b): shell-side item alerts — reminders fire with the app closed#108
Merged
Conversation
…h the app closed 9.14.9 shipped due/scheduled task alerts and event reminders in-window only (a 30s tick inside the app renderer); nothing fired once the window closed. This hosts the same alerts in the main process on the existing automations SchedulerService — one fire mechanism product-wide: - main/automations/item-alerts.ts (pure): Task/v1 + Event/v1 entity rows → one-shot alert registrations, mirroring the app-side semantics (midnight→09:00 task instants, deadline-wins collisions, per-offset event reminders, base-occurrence recurrence fidelity) with dedupe keys replicating the SDK reminderDedupeKey shape. - AutomationsHost routes item-alert fires to a new optional postAlert port; wiring derives alerts in hydrateFromEntities, re-derives on Task/Event writes, reconciles stale ids; index.ts posts through the shared UiNotifyHost under the SOURCE app id, so the (appId, dedupeKey) window collapses duplicates when an app window is also open. - Calendar now passes due.dedupeKey in its in-app notify (Tasks already did) so that collapse actually engages. - e2e: provision a due task without ever opening Tasks, restart the shell, assert the notification lands attributed to io.brainstorm.tasks. Alerts missed while the shell was closed do not back-fire — the scheduler recomputes from now on vault open, the same posture as Reminder/v1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the gap 9.14.9 left: due/scheduled task alerts and calendar event reminders ran on a 30s tick inside the app renderer, so nothing fired once the window closed. This hosts the same alerts in the main process on the existing automations
SchedulerService— one fire mechanism product-wide, no new scheduling logic.How it works
main/automations/item-alerts.ts(pure, +14 tests):Task/v1+Event/v1entity rows → one-shot alert registrations, mirroring the app-side semantics (midnight→09:00 task instants, deadline-wins same-instant collision, per-offset event reminders, base-occurrence recurrence fidelity). Dedupe keys replicate the SDKreminderDedupeKeyshape.AutomationsHostgains an optionalpostAlertport and routes item-alert fires to it (+4 wiring tests: fire w/ source appId+dedupeKey, event offset fire, live unregister on task completion, exactly-once).hydrateFromEntities, re-derives on any Task/Event write (coalesced, same path as automation-entity writes), reconciles stale ids, and stays host-designation-gated — no multi-device double-fire.index.tsposts through the sharedUiNotifyHostunder the source app's id (io.brainstorm.tasks/io.brainstorm.calendar), so when an app window is open and both schedulers fire, the host's(appId, dedupeKey)window collapses the duplicate. Calendar's in-app notify now passesdue.dedupeKey(Tasks already did).Posture notes
nowon vault open — same asReminder/v1; a catch-up pass is a possible follow-up).entities.read:*;postAlertis main-internal; DND/mute/dedupe all enforced by the existing notify host; titles are never persisted (registry stores only ids + fire configs).Verification
bun run verifygreen; full suite 14,636 passed (one FTS stress-budget flake under concurrent-run load, passes solo in 17s).tests/e2e/specs/item-alerts.spec.ts, passes in 1.1m): boot 1 provisions a task with a timed dueAt without ever opening Tasks; boot 2 just reopens the vault — the notification lands in the history attributed toio.brainstorm.taskswithin a drain tick. Also proves the alert derives from persisted state across a restart.Plan: harness
docs/implementation-plan.md9.14.9b ✅ (merged) — 0.1.9 scope row 1 of 2.🤖 Generated with Claude Code