Delivery no longer waits to be told. The scan reads `Instances` and `Reminders`, plans every reminder, posts what has come due and arms one exact alarm for the next — replacing both halves of what the provider used to do for us. Reacting to `EVENT_REMINDER` could not be made reliable, only more hopeful. An app that reacts cannot distinguish "nothing was due" from "the broadcast never came", and AOSP's own unbundled calendar carries three workarounds for OEM providers that retarget it or write the alert row late. Etar's fallback was not the answer either: it replaces the alarm but still reads `CalendarAlerts` for what to show, and it disables itself the moment one real broadcast arrives — useless against a broadcast that arrives with no row behind it. Keeping the old receiver alongside was rejected for the same reason it looks attractive: on a healthy device both paths fire, and there is no honest way to suppress one without the latch we just ruled out. So the provider path goes — `EventReminderReceiver`, `ReminderAlertStore`, `ReminderRecovery` and the `CalendarAlerts` writes with it. Reminder delivery no longer needs WRITE_CALENDAR. One alarm exists at a time, re-planned on every firing, so an edit needs no alarm bookkeeping to stay in sync. Every trigger runs the same idempotent scan: the alarm, boot and package-replace (both wipe pending alarms), clock and timezone changes, a provider change while the app is up, launch, and a daily worker for a device that drops the alarm with nothing to announce it. RECEIVE_BOOT_COMPLETED is new and load-bearing — without it reminders stop dead after a restart. `ReminderAlert.alertId` becomes `key`, derived from the reminder rather than a row id that no longer exists, and the notification tag and PendingIntent request codes ride on it, so a re-posted reminder still replaces itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Documentation map
Where to look for what:
| Document | What it is |
|---|---|
ARCHITECTURE.md |
Orientation tour: principles, layers, navigation, recurring-write / conflict / reminder pipelines, testing |
../CHANGELOG.md |
Release history (Keep a Changelog, SemVer) |
../.planning/ROADMAP.md |
Living roadmap: shipped milestones, current scope, idea backlog |
../.planning/PROJECT.md |
What the project is, stack, naming, infrastructure |
../.planning/REQUIREMENTS.md |
Requirement checklist per milestone |
../.planning/STATE.md |
Snapshot of where development currently stands |
superpowers/specs/ |
The original design spec (2026-06-08) — historical record, not updated |
superpowers/plans/ |
Per-milestone implementation plans with task checklists — historical record of how each slice was built, including provider lessons learned |
../fastlane/metadata/android/ |
Store metadata (single source of truth): descriptions, title, icon, screenshots (DE + EN). Harvested directly by the official F-Droid repo; transformed into the self-hosted repo layout at release time by ../scripts/fastlane_to_fdroid_localized.sh |
../fdroid-metadata/ |
App-level F-Droid control file (*.yml: Categories, License, links) for the self-hosted repo's fdroid update |
fdroid-official/ |
Draft recipe + notes for publishing to the official F-Droid repo (reproducible build + developer-signed binary) |
Conventions: plans and specs under superpowers/ are point-in-time
artifacts of the agentic workflow that built each milestone — they get
status updates but are never rewritten. The .planning/ files are living
documents and should stay current.