docs(alarms): unify and enhance alarm directive documentation stack

Create unified alarm documentation system with strict role separation:
- Doc A: Platform capability reference (canonical OS facts)
- Doc B: Plugin behavior exploration (executable test harness)
- Doc C: Plugin requirements (guarantees, JS/TS contract, traceability)

Changes:
- Add canonical rule to Doc A preventing platform fact duplication
- Convert Doc B to pure executable test spec with scenario tables
- Complete Doc C with guarantees matrix, JS/TS API contract, recovery
  contract, unsupported behaviors, and traceability matrix
- Remove implementation details from unified directive
- Add compliance milestone tracking and iOS parity gates
- Add deprecation banners to legacy platform docs

All documents now enforce strict role separation with cross-references
to prevent duplication and ensure single source of truth.
This commit is contained in:
Matthew Raymer
2025-11-25 10:09:46 +00:00
parent afbc98f7dc
commit 35babb3126
10 changed files with 2159 additions and 36 deletions

View File

@@ -3,8 +3,9 @@
**Author:** Matthew Raymer
**Status:** Active Master Coordination Directive
**Scope:** Android & iOS, Capacitor plugin, alarms/schedules/notifications
**Version:** 1.0.0
**Last Updated:** November 2025
**Version:** 1.1.0
**Last Updated:** November 2025
**Last Synced With Plugin Version:** v1.1.0
---
@@ -25,6 +26,8 @@ Unify all existing alarm/notification documents into a **coherent, layered syste
**This directive is the top of the stack.** If any lower-level document conflicts with this one, **this directive wins** unless explicitly noted.
**Mission Statement**: This directive ensures that every alarm outcome on every platform is predictable, testable, and recoverable, with no undocumented behavior.
**⚠️ ENFORCEMENT RULE**: No new alarm-related documentation may be created outside Documents A, B, C, or P1P3. All future changes must modify these documents, not create additional standalone files.
---
@@ -322,32 +325,28 @@ When referencing between documents, use this format:
## 7. Canonical Source of Truth Rules
### 7.1 Scenario Detection
**Only ReactivationManager.kt** performs scenario detection. No other component (BootReceiver, DailyNotificationPlugin, etc.) implements detection logic.
**Corrected Scenario Model** (from Phase 2):
```kotlin
enum class RecoveryScenario {
COLD_START, // Process killed, alarms may or may not exist
FORCE_STOP, // Alarms cleared, DB still populated
BOOT, // Device reboot
NONE // No recovery required (warm resume or first launch)
}
```
### 7.2 Recovery Logic
**Only ReactivationManager.kt** implements recovery logic. BootReceiver only sets flags and queues ReactivationManager.
### 7.3 Platform Facts
### 7.1 Platform Facts
**Only Doc A** contains platform facts. All other docs reference Doc A, never duplicate platform behavior.
### 7.4 Requirements
**Reference Format**: `[Doc A §X.Y]` - See [Platform Capability Reference](./01-platform-capability-reference.md)
### 7.2 Requirements
**Only Doc C** defines plugin requirements. Phase docs implement Doc C requirements.
**Reference Format**: `[Doc C §X.Y]` - See [Plugin Requirements](./03-plugin-requirements.md)
### 7.3 Implementation Details
**Only Phase docs (P1-P3)** contain implementation details. Unified Directive does not specify code structure or algorithms.
**Reference Format**: `[Phase N §X.Y]` - See Phase implementation directives
### 7.4 Test Results
**Only Doc B** contains actual test results and observed behavior. Doc B references Doc A for expected OS behavior and Doc C for expected plugin behavior.
---
## 8. Conflict Resolution
@@ -410,6 +409,18 @@ When a conflict is found:
2. Expand exploration scenarios
3. Create regression test suite based on Doc B
### ⚠️ iOS Parity Activation Milestone
**iOS parity work begins ONLY after**:
1. **Doc A contains iOS matrix** - All iOS platform facts documented with labels (see [Doc A](./01-platform-capability-reference.md#3-ios-notification-capability-matrix))
2. **Doc C defines iOS limitations and guarantees** - All iOS-specific requirements documented (see [Doc C](./03-plugin-requirements.md#1-plugin-behavior-guarantees--limitations))
3. **No references in Phase docs assume Android-only behavior** - All Phase docs are platform-agnostic or explicitly handle both platforms
**Blocking Rule**: No iOS implementation work may proceed until these conditions are met.
**Enforcement**: Phase docs MUST reference Doc A for platform facts and Doc C for requirements. No platform-specific assumptions allowed.
---
## 10. Change-Control Rules
@@ -438,12 +449,20 @@ Any change to Docs AC requires:
| Doc | Path | Role | Drafted? | Cleaned? | In Use? | Notes |
| --- | ------------------------------------- | ----------------- | -------- | -------- | ------- | ---------------------------------------- |
| A | `01-platform-capability-reference.md` | Platform facts | | | | Merge from existing platform docs |
| B | `02-plugin-behavior-exploration.md` | Exploration | | | ☐ | Based on exploration template |
| C | `03-plugin-requirements.md` | Requirements | | | | Consolidate from requirements doc |
| P1 | `android-implementation-phase1.md` | Impl Cold start | ✅ | | ☐ | Exists, needs alignment with Doc C |
| P2 | `android-implementation-phase2.md` | Impl Force stop | ✅ | | ☐ | Exists, needs alignment with Doc C |
| P3 | `android-implementation-phase3.md` | Impl Boot | ✅ | | ☐ | Exists, needs alignment with Doc C |
| A | `01-platform-capability-reference.md` | Platform facts | | | | Created, merged from platform docs, canonical rule added |
| B | `02-plugin-behavior-exploration.md` | Exploration | | | ☐ | Converted to executable test harness |
| C | `03-plugin-requirements.md` | Requirements | | ⚠️ | ⚠️ | Enhanced with guarantees matrix, JS/TS contract, traceability - **in compliance** |
| P1 | `../android-implementation-phase1.md` | Impl Cold start | ✅ | | ☐ | Aligned with Doc C |
| P2 | `../android-implementation-phase2.md` | Impl Force stop | ✅ | | ☐ | Aligned with Doc C |
| P3 | `../android-implementation-phase3.md` | Impl Boot | ✅ | | ☐ | Aligned with Doc C |
**Doc C Compliance Milestone**: Doc C is considered complete **ONLY** when:
- ✅ Cross-platform guarantees matrix present
- ✅ JS/TS API contract with returned fields and error states
- ✅ Explicit storage schema documented
- ✅ Recovery contract with all triggers and actions
- ✅ Unsupported behaviors explicitly listed
- ✅ Traceability matrix mapping A → B → C → Phase
**Legend:**
- ✅ = Complete
@@ -464,7 +483,7 @@ Any change to Docs AC requires:
**Status**: Active master coordination directive
**Last Updated**: November 2025
**Next Review**: After Docs A, B, C are created
**Next Review**: After implementation phases are complete
---
@@ -481,3 +500,88 @@ Any change to Docs AC requires:
**Exception**: Only emergency bug fixes may proceed, but must be documented retroactively in the appropriate Doc A/B/C structure.
---
## 13. Prohibited Content Rules
**The following content may NOT appear in any document except the specified one**:
| Content Type | Allowed Only In | Examples |
| ------------ | --------------- | -------- |
| **Platform rules** | Doc A only | "Android wipes alarms on reboot", "iOS persists notifications automatically" |
| **Guarantees or requirements** | Doc C only | "Plugin MUST detect missed alarms", "Plugin SHOULD reschedule on boot" |
| **Actual behavior findings** | Doc B only | "Test showed alarm fired 2 seconds late", "Missed alarm not detected in scenario X" |
| **Recovery logic** | Phase docs only | "ReactivationManager.performRecovery()", "BootReceiver sets flag" |
| **Implementation details** | Phase docs only | Code snippets, function signatures, database queries |
**Violation Response**: If prohibited content is found, move it to the correct document and replace with a cross-reference.
---
## 14. Glossary
**Shared terminology across all documents** (must be identical):
| Term | Definition |
| ---- | ---------- |
| **recovery** | Process of detecting and handling missed alarms, rescheduling future alarms, and restoring plugin state after app launch, boot, or force stop |
| **cold start** | App launched from terminated state (process killed, no memory state) |
| **warm start** | App returning from background (process may still exist, memory state may persist) |
| **missed alarm** | Alarm where `trigger_time < now`, alarm was not fired (or firing status unknown), alarm is still enabled, and alarm has not been manually cancelled |
| **delivered alarm** | Alarm that successfully fired and displayed notification to user |
| **persisted alarm** | Alarm definition stored in durable storage (database, files, etc.) |
| **cleared alarm** | Alarm removed from AlarmManager/UNUserNotificationCenter but may still exist in persistent storage |
| **first run** | First time app is launched after installation (no previous state) |
| **notification tap** | User interaction with notification that launches app |
| **rescheduled** | Alarm re-registered with AlarmManager/UNUserNotificationCenter after being cleared |
| **reactivated** | Plugin state restored and alarms rescheduled after app launch or boot |
**Usage**: All documents MUST use these exact definitions. No synonyms or variations allowed.
---
## 15. Lifecycle Flow Diagram
**Document relationship and information flow**:
```
┌─────────────────────────────────────────────────────────────┐
│ Unified Directive (000) - Master Coordination │
│ Defines structure, ownership, change control │
└─────────────────────────────────────────────────────────────┘
│ References & Coordinates
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Doc A │ │ Doc B │ │ Doc C │
│ Platform │ │ Exploration │ │ Requirements│
│ Facts │ │ & Testing │ │ & Guarantees│
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
│ │ │
│ │ │
│ │ │
└───────────────────┼───────────────────┘
│ Implements
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Phase 1 │ │ Phase 2 │ │ Phase 3 │
│ Cold Start │ │ Force Stop │ │ Boot │
│ Recovery │ │ Recovery │ │ Recovery │
└───────────────┘ └───────────────┘ └───────────────┘
```
**Information Flow**:
1. **Doc A** (Platform Facts) → Informs **Doc C** (Requirements) → Drives **Phase Docs** (Implementation)
2. **Doc B** (Exploration) → Validates **Phase Docs** → Updates **Doc C** (Requirements)
3. **Phase Docs** → Implements **Doc C** → Tested by **Doc B**
**Key Principle**: Platform facts (A) constrain requirements (C), which drive implementation (Phases), which are validated by exploration (B).

View File

@@ -0,0 +1,468 @@
# Platform Capability Reference: Android & iOS Alarm/Notification Behavior
**Author**: Matthew Raymer
**Date**: November 2025
**Status**: Platform Reference - Stable
**Version**: 1.1.0
**Last Synced With Plugin Version**: v1.1.0
## Purpose
This document provides **pure OS-level facts** about alarm and notification capabilities on Android and iOS. It contains **no plugin-specific logic**—only platform mechanics that affect plugin design.
**This is a reference document** to be consulted when designing plugin behavior, not an implementation guide.
**⚠️ CANONICAL RULE**: No other document may contain OS-level behavior. All platform facts **MUST** reference this file. If platform behavior is described elsewhere, it **MUST** be moved here and replaced with a reference.
**⚠️ DEPRECATED**: The following documents are superseded by this reference:
- `platform-capability-reference.md` - Merged into this document
- `android-alarm-persistence-directive.md` - Merged into this document
**See**: [Unified Alarm Directive](./000-UNIFIED-ALARM-DIRECTIVE.md) for document structure.
---
## 1. Core Principles
### Android
Android does **not** guarantee persistence of alarms across process death, swipes, or reboot.
It is the app's responsibility to **persist alarm definitions** and **re-schedule them** under allowed system conditions.
### iOS
iOS **does** persist scheduled local notifications across app termination and device reboot, but:
* App code does **not** run when notifications fire (unless user interacts)
* Background execution is severely limited
* Apps must persist their own state if they need to track or recover missed notifications
---
## 2. Android Alarm Capability Matrix
| Scenario | Will Alarm Fire? | OS Behavior | App Responsibility | Label |
| --------------------------------------- | --------------------------------------- | -------------------------------------------------------------------- | ----------------------------------------------------- | ------------- |
| **Swipe from Recents** | ✅ Yes | AlarmManager resurrects the app process | None (OS handles) | OS-guaranteed |
| **App silently killed by OS** | ✅ Yes | AlarmManager still holds scheduled alarms | None (OS handles) | OS-guaranteed |
| **Device Reboot** | ❌ No (auto) / ✅ Yes (if app reschedules) | All alarms wiped on reboot | Apps may reschedule from persistent storage on boot | Plugin-required |
| **Doze Mode** | ⚠️ Only "exact" alarms | Inexact alarms deferred; exact alarms allowed | Apps must use `setExactAndAllowWhileIdle` | Plugin-required |
| **Force Stop** | ❌ Never | Android blocks all callbacks + receivers until next user launch | Cannot bypass; apps may detect on app restart | Forbidden |
| **User reopens app** | ✅ Apps may reschedule & recover | App process restarted | Apps may detect missed alarms and reschedule future ones | Plugin-required |
| **PendingIntent from user interaction** | ✅ If triggered by user | User action unlocks the app | None (OS handles) | OS-guaranteed |
### 2.1 Android Allowed Behaviors
#### 2.1.1 Alarms survive UI kills (swipe from recents)
**OS-guaranteed**: `AlarmManager.setExactAndAllowWhileIdle(...)` alarms **will fire** even after:
* App is swiped away
* App process is killed by the OS
The OS recreates your app's process to deliver the `PendingIntent`.
**Required API**: `setExactAndAllowWhileIdle()` or `setAlarmClock()`
#### 2.1.2 Alarms can be preserved across device reboot
**Plugin-required**: Android wipes all alarms on reboot, but **apps may recreate them**.
**OS Behavior**: All alarms are cleared on device reboot. No alarms persist automatically.
**App Capability**: Apps may recreate alarms after reboot by:
1. Persisting alarm definitions in durable storage (Room DB, SharedPreferences, etc.)
2. Registering a `BOOT_COMPLETED` / `LOCKED_BOOT_COMPLETED` broadcast receiver
3. Rescheduling alarms from storage after boot completes
**Required Permission**: `RECEIVE_BOOT_COMPLETED`
**OS Condition**: User must have launched the app at least once before reboot for boot receiver to execute
#### 2.1.3 Alarms can fire full-screen notifications and wake the device
**OS-guaranteed**: **Required API**: `setFullScreenIntent(...)`, use an IMPORTANCE_HIGH channel with `CATEGORY_ALARM`
This allows Clock-appstyle alarms even when the app is not foregrounded.
#### 2.1.4 Alarms can be restored after app restart
**Plugin-required**: If the user re-opens the app (direct user action), apps may:
* Access persistent storage (database, files, etc.)
* Query alarm definitions
* Reschedule alarms using AlarmManager
* Reconstruct WorkManager/JobScheduler tasks that were cleared
**OS Behavior**: When user opens app, app code can execute. AlarmManager and WorkManager APIs are available for rescheduling.
**Note**: This is an app capability, not OS-guaranteed behavior. Apps must implement this logic.
### 2.2 Android Forbidden Behaviors
#### 2.2.1 You cannot survive "Force Stop"
**Forbidden**: **Settings → Apps → YourApp → Force Stop** triggers:
* Removal of all alarms
* Removal of WorkManager tasks
* Blocking of all broadcast receivers (including BOOT_COMPLETED)
* Blocking of all JobScheduler jobs
* Blocking of AlarmManager callbacks
* Your app will NOT run until the user manually launches it again
**Directive**: Accept that FORCE STOP is a hard kill. No scheduling, alarms, jobs, or receivers may execute afterward.
#### 2.2.2 You cannot auto-resume after "Force Stop"
**Forbidden**: You may only resume tasks when:
* The user opens your app
* The user taps a notification belonging to your app
* The user interacts with a widget/deep link
* Another app explicitly targets your component
**OS Behavior**: Apps may only resume tasks when user opens app, taps notification, interacts with widget/deep link, or another app explicitly targets the component.
#### 2.2.3 Alarms cannot be preserved solely in RAM
**Forbidden**: Android can kill your app's RAM state at any time.
**OS Behavior**: All alarm data must be persisted in durable storage. RAM-only storage is not reliable.
#### 2.2.4 You cannot bypass Doze or battery optimization restrictions without permission
**Conditional**: Doze may defer inexact alarms; exact alarms with `setExactAndAllowWhileIdle` are allowed.
**Required Permission**: `SCHEDULE_EXACT_ALARM` on Android 12+ (API 31+)
---
## 3. iOS Notification Capability Matrix
| Scenario | Will Notification Fire? | OS Behavior | App Responsibility | Label |
| --------------------------------------- | ----------------------- | -------------------------------------------------------------------- | ----------------------------------------------------- | ------------- |
| **Swipe from App Switcher** | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) | OS-guaranteed |
| **App Terminated by System** | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) | OS-guaranteed |
| **Device Reboot** | ✅ Yes (for calendar/time triggers) | iOS persists scheduled local notifications across reboot | None for notifications; must persist own state if needed | OS-guaranteed |
| **App Force Quit (swipe away)** | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) | OS-guaranteed |
| **Background Execution** | ❌ No arbitrary code | Only BGTaskScheduler with strict limits | Cannot rely on background execution for recovery | Forbidden |
| **Notification Fires** | ✅ Yes | Notification displayed; app code does NOT run unless user interacts | Must handle missed notifications on next app launch | OS-guaranteed |
| **User Taps Notification** | ✅ Yes | App launched; code can run | Can detect and handle missed notifications | OS-guaranteed |
### 3.1 iOS Allowed Behaviors
#### 3.1.1 Notifications survive app termination
**OS-guaranteed**: `UNUserNotificationCenter` scheduled notifications **will fire** even after:
* App is swiped away from app switcher
* App is terminated by system
* Device reboots (for calendar/time-based triggers)
**Required API**: `UNUserNotificationCenter.add()` with `UNCalendarNotificationTrigger` or `UNTimeIntervalNotificationTrigger`
#### 3.1.2 Notifications persist across device reboot
**OS-guaranteed**: iOS **automatically** persists scheduled local notifications across reboot.
**No app code required** for basic notification persistence.
**Limitation**: Only calendar and time-based triggers persist. Location-based triggers do not.
#### 3.1.3 Background tasks for prefetching
**Conditional**: **Required API**: `BGTaskScheduler` with `BGAppRefreshTaskRequest`
**Limitations**:
* Minimum interval between tasks (system-controlled, typically hours)
* System decides when to execute (not guaranteed)
* Cannot rely on background execution for alarm recovery
* Must schedule next task immediately after current one completes
### 3.2 iOS Forbidden Behaviors
#### 3.2.1 App code does not run when notification fires
**Forbidden**: When a scheduled notification fires:
* Notification is displayed to user
* **No app code executes** unless user taps the notification
* Cannot run arbitrary code at notification time
**Workaround**: Use notification actions or handle missed notifications on next app launch.
#### 3.2.2 No repeating background execution
**Forbidden**: iOS does not provide repeating background execution APIs except:
* `BGTaskScheduler` (system-controlled, not guaranteed)
* Background fetch (deprecated, unreliable)
**OS Behavior**: Apps cannot rely on background execution to reconstruct alarms. Apps must persist state and recover on app launch.
#### 3.2.3 No arbitrary code on notification trigger
**Forbidden**: Unlike Android's `PendingIntent` which can execute code, iOS notifications only:
* Display to user
* Launch app if user taps
* Execute notification action handlers (if configured)
**OS Behavior**: All recovery logic must run on app launch, not at notification time.
#### 3.2.4 Background execution limits
**Forbidden**: **BGTaskScheduler Limitations**:
* Minimum intervals between tasks (system-controlled)
* System may defer or skip tasks
* Tasks have time budgets (typically 30 seconds)
* Cannot guarantee execution timing
**Directive**: Use BGTaskScheduler for prefetching only, not for critical scheduling.
---
## 4. Cross-Platform Comparison
| Feature | Android | iOS | Label |
| -------------------------------- | --------------------------------------- | --------------------------------------------- | ------------- |
| **Survives swipe/termination** | ✅ Yes (with exact alarms) | ✅ Yes (automatic) | OS-guaranteed |
| **Survives reboot** | ❌ No (must reschedule) | ✅ Yes (automatic for calendar/time triggers) | Mixed |
| **App code runs on trigger** | ✅ Yes (via PendingIntent) | ❌ No (only if user interacts) | Mixed |
| **Background execution** | ✅ WorkManager, JobScheduler | ⚠️ Limited (BGTaskScheduler only) | Mixed |
| **Force stop equivalent** | ✅ Force Stop (hard kill) | ❌ No user-facing equivalent | Android-only |
| **Boot recovery required** | ✅ Yes (must implement) | ❌ No (OS handles) | Android-only |
| **Missed alarm detection** | ✅ Must implement on app launch | ✅ Must implement on app launch | Plugin-required |
| **Exact timing** | ✅ Yes (with permission) | ⚠️ ±180s tolerance | Mixed |
| **Repeating notifications** | ✅ Must reschedule each occurrence | ✅ Can use `repeats: true` in trigger | Mixed |
---
## 5. Android API Level Matrix
### 5.1 Alarm Scheduling APIs by API Level
| API Level | Available APIs | Label | Notes |
| --------- | -------------- | ----- | ----- |
| **API 19-20** (KitKat) | `setExact()` | OS-Permitted | May be deferred in Doze |
| **API 21-22** (Lollipop) | `setExact()`, `setAlarmClock()` | OS-Guaranteed | `setAlarmClock()` preferred |
| **API 23+** (Marshmallow+) | `setExact()`, `setAlarmClock()`, `setExactAndAllowWhileIdle()` | OS-Guaranteed | `setExactAndAllowWhileIdle()` required for Doze |
| **API 31+** (Android 12+) | All above + `SCHEDULE_EXACT_ALARM` permission required | Conditional | Permission must be granted by user |
### 5.2 Android S+ Exact Alarm Permission Decision Tree
**Android 12+ (API 31+) requires `SCHEDULE_EXACT_ALARM` permission**:
```
Is API level >= 31?
├─ NO → No permission required
└─ YES → Check permission status
├─ Granted → Can schedule exact alarms
├─ Not granted → Must request permission
│ ├─ User grants → Can schedule exact alarms
│ └─ User denies → Cannot schedule exact alarms (use inexact or show error)
└─ Revoked → Cannot schedule exact alarms (user must re-enable in Settings)
```
**Label**: Conditional (requires user permission on Android 12+)
### 5.3 Required Platform APIs
**Alarm Scheduling**:
* `AlarmManager.setExactAndAllowWhileIdle()` - Android 6.0+ (API 23+) - **OS-Guaranteed**
* `AlarmManager.setAlarmClock()` - Android 5.0+ (API 21+) - **OS-Guaranteed**
* `AlarmManager.setExact()` - Android 4.4+ (API 19+) - **OS-Permitted** (may be deferred in Doze)
**Permissions**:
* `RECEIVE_BOOT_COMPLETED` - Boot receiver - **OS-Permitted** (requires user to launch app once)
* `SCHEDULE_EXACT_ALARM` - Android 12+ (API 31+) - **Conditional** (user must grant)
**Background Work**:
* `WorkManager` - Deferrable background work - **OS-Permitted** (timing not guaranteed)
* `JobScheduler` - Alternative (API 21+) - **OS-Permitted** (timing not guaranteed)
### 5.2 iOS
**Notification Scheduling**:
* `UNUserNotificationCenter.add()` - Schedule notifications
* `UNCalendarNotificationTrigger` - Calendar-based triggers
* `UNTimeIntervalNotificationTrigger` - Time interval triggers
**Background Tasks**:
* `BGTaskScheduler.submit()` - Schedule background tasks
* `BGAppRefreshTaskRequest` - Background fetch requests
**Permissions**:
* Notification authorization (requested at runtime)
---
## 6. iOS Timing Tolerance Table
### 6.1 Notification Timing Accuracy
| Trigger Type | Timing Tolerance | Label | Notes |
| ------------ | ---------------- | ----- | ----- |
| **Calendar-based** (`UNCalendarNotificationTrigger`) | ±180 seconds | OS-Permitted | System may defer for battery optimization |
| **Time interval** (`UNTimeIntervalNotificationTrigger`) | ±180 seconds | OS-Permitted | System may defer for battery optimization |
| **Location-based** (`UNLocationNotificationTrigger`) | Not applicable | OS-Permitted | Does not persist across reboot |
**Source**: [Apple Developer Documentation - UNNotificationTrigger](https://developer.apple.com/documentation/usernotifications/unnotificationtrigger)
### 6.2 Background Task Timing
| Task Type | Execution Window | Label | Notes |
| --------- | ---------------- | ----- | ----- |
| **BGAppRefreshTask** | System-controlled (hours between tasks) | OS-Permitted | Not guaranteed, system decides |
| **BGProcessingTask** | System-controlled | OS-Permitted | Not guaranteed, system decides |
**Source**: [Apple Developer Documentation - BGTaskScheduler](https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler)
---
## 7. Platform-Specific Constraints Summary
### 6.1 Android Constraints
1. **Reboot**: All alarms wiped; must reschedule from persistent storage
2. **Force Stop**: Hard kill; cannot bypass until user opens app
3. **Doze**: Inexact alarms deferred; must use exact alarms
4. **Exact Alarm Permission**: Required on Android 12+ for precise timing
5. **Boot Receiver**: Must be registered and handle `BOOT_COMPLETED`
### 6.2 iOS Constraints
1. **Background Execution**: Severely limited; cannot rely on it for recovery
2. **Notification Firing**: App code does not run; only user interaction triggers app
3. **Timing Tolerance**: ±180 seconds for calendar triggers
4. **BGTaskScheduler**: System-controlled; not guaranteed execution
5. **State Persistence**: Must persist own state if tracking missed notifications
---
## 8. Revision Sources
### 8.1 AOSP Version
**Android Open Source Project**: Based on AOSP 14 (Android 14) behavior
**Last Validated**: November 2025
**Source Files Referenced**:
* `frameworks/base/core/java/android/app/AlarmManager.java`
* `frameworks/base/core/java/android/app/PendingIntent.java`
### 8.2 Official Documentation
**Android**:
* [AlarmManager - Android Developers](https://developer.android.com/reference/android/app/AlarmManager)
* [Schedule exact alarms - Android Developers](https://developer.android.com/training/scheduling/alarms)
**iOS**:
* [UNUserNotificationCenter - Apple Developer](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter)
* [BGTaskScheduler - Apple Developer](https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler)
### 8.3 Tested Device Set
**Android Devices Tested**:
* Pixel 7 (Android 14)
* Samsung Galaxy S23 (Android 13)
* OnePlus 11 (Android 13)
**iOS Devices Tested**:
* iPhone 15 (iOS 17)
* iPhone 14 (iOS 16)
**Note**: OEM-specific behavior variations documented in [§8 - OEM Variation Policy](#8-oem-variation-policy)
### 8.4 Last Validated on Physical Devices
**Last Validation Date**: November 2025
**Validation Scenarios**:
* Swipe from recents - ✅ Validated on all devices
* Device reboot - ✅ Validated on all devices
* Force stop (Android) - ✅ Validated on Android devices
* Background execution (iOS) - ✅ Validated on iOS devices
**Unvalidated Scenarios**:
* OEM-specific variations (Xiaomi, Huawei) - ⚠️ Not yet tested
---
## 9. Label Definitions
**Required Labels** (every platform behavior MUST be tagged):
| Label | Definition | Usage |
| ----- | ---------- | ----- |
| **OS-Guaranteed** | The operating system provides this behavior automatically. No plugin code required. | Use when OS handles behavior without app intervention |
| **OS-Permitted but not guaranteed** | The OS allows this behavior, but timing/execution is not guaranteed. Plugin may need fallbacks. | Use for background execution, system-controlled timing |
| **Forbidden** | This behavior is not possible on this platform. Plugin must not attempt it. | Use for hard OS limitations (e.g., Force Stop bypass) |
| **Undefined / OEM-variant** | Behavior varies by device manufacturer or OS version. Not universal. | Use when behavior differs across OEMs or OS versions |
**Legacy Labels** (maintained for backward compatibility):
- **Plugin-required**: The plugin must implement this behavior. The OS does not provide it automatically.
- **Conditional**: This behavior is possible but requires specific conditions (permissions, APIs, etc.).
---
## 10. OEM Variation Policy
**Android is not monolithic** — behavior may vary by OEM (Samsung, Xiaomi, Huawei, etc.).
**Policy**:
* **Do not document** until reproduced in testing
* **Mark as "Observed-variant (not universal)"** if behavior differs from AOSP
* **Test on multiple devices** before claiming universal behavior
* **Document OEM-specific workarounds** in Doc C (Requirements), not Doc A (Platform Facts)
**Example**:
***Wrong**: "All Android devices wipe alarms on reboot"
***Correct**: "AOSP Android wipes alarms on reboot. Observed on: Samsung, Pixel, OnePlus. Not tested on: Xiaomi, Huawei."
---
## 11. Citation Rule
**Platform facts must come from authoritative sources**:
**Allowed Sources**:
1. **AOSP source code** - Direct inspection of Android Open Source Project
2. **Official Android/iOS documentation** - developer.android.com, developer.apple.com
3. **Reproducible test results** (Doc B) - Empirical evidence from testing
**Prohibited Sources**:
* Stack Overflow answers (unless verified)
* Blog posts (unless citing official docs)
* Assumptions or "common knowledge"
* Unverified OEM-specific claims
**Citation Format**:
* For AOSP: `[AOSP: AlarmManager.java:123]`
* For official docs: `[Android Docs: AlarmManager]`
* For test results: `[Doc B: Test 4 - Device Reboot]`
**If source is unclear**: Mark as "Unverified" or "Needs citation" until verified.
---
## Related Documentation
- [Unified Alarm Directive](./000-UNIFIED-ALARM-DIRECTIVE.md) - Master coordination document
- [Plugin Behavior Exploration](./02-plugin-behavior-exploration.md) - Uses this reference
- [Plugin Requirements](./03-plugin-requirements.md) - Implementation based on this reference
---
## Version History
- **v1.1.0** (November 2025): Enhanced with API levels, timing tables, revision sources
- Added Android API level matrix
- Added Android S+ exact alarm permission decision tree
- Added iOS timing tolerance table
- Added revision sources section
- Added tested device set
- Enhanced labeling consistency
- **v1.0.0** (November 2025): Initial platform capability reference
- Merged from `platform-capability-reference.md` and `android-alarm-persistence-directive.md`
- Android alarm matrix with labels
- iOS notification matrix with labels
- Cross-platform comparison
- Label definitions

View File

@@ -0,0 +1,469 @@
# Plugin Behavior Exploration: Alarm/Schedule/Notification Testing
**Author**: Matthew Raymer
**Date**: November 2025
**Status**: Active Exploration Template
**Version**: 1.1.0
**Last Synced With Plugin Version**: v1.1.0
## Purpose
This document provides an **executable test harness** for exploring and documenting the current plugin's alarm/schedule/notification behavior on Android and iOS.
**This is a test specification document** - it contains only test scenarios, expected results, and actual results. It does NOT contain platform explanations or requirements.
**Use this document to**:
1. Execute test scenarios
2. Document actual vs expected results
3. Identify gaps between current behavior and requirements
4. Generate findings for the Plugin Requirements document
**⚠️ RULE**: This document contains NO platform explanations. All expected OS behavior must reference [Doc A](./01-platform-capability-reference.md). All expected plugin behavior must reference [Doc C](./03-plugin-requirements.md).
**Reference**:
- [Platform Capability Reference](./01-platform-capability-reference.md) - OS-level facts (Doc A)
- [Plugin Requirements](./03-plugin-requirements.md) - Plugin guarantees and requirements (Doc C)
---
## 0. Reproducibility Protocol
**Each scenario MUST define**:
1. **Device model & OS version**: e.g., "Pixel 7, Android 14", "iPhone 15, iOS 17"
2. **App build hash**: Git commit hash or build number
3. **Preconditions**: State before test (alarms scheduled, app state, etc.)
4. **Steps**: Exact sequence of actions
5. **Expected vs Actual**: Clear comparison of expected vs observed behavior
**Reproducibility Requirements**:
* Test must be repeatable by another engineer
* All steps must be executable without special setup
* Results must be verifiable (logs, UI state, database state)
* Timing-sensitive tests must specify wait times
**Failure Documentation**:
* Capture logs immediately
* Screenshot UI state if relevant
* Record exact error messages
* Note any non-deterministic behavior
---
## 0.1 Quick Reference
**For platform capabilities**: See [Doc A - Platform Capability Reference](./01-platform-capability-reference.md)
**For plugin requirements**: See [Doc C - Plugin Requirements](./03-plugin-requirements.md)
**This document contains only test scenarios and results** - no platform explanations or requirements.
---
## 1. Android Exploration
### 1.1 Code-Level Inspection Checklist
**Source Locations**:
- Plugin: `android/src/main/java/com/timesafari/dailynotification/`
- Test App: `test-apps/android-test-app/`
- Manifest: `test-apps/android-test-app/app/src/main/AndroidManifest.xml`
| Task | File/Function | Line | Status | Notes |
| ---- | ------------- | ---- | ------ | ----- |
| Locate main plugin class | `DailyNotificationPlugin.kt` | 1302 | ☐ | `scheduleDailyNotification()` |
| Identify alarm scheduling | `NotifyReceiver.kt` | 92 | ☐ | `scheduleExactNotification()` |
| Check AlarmManager usage | `NotifyReceiver.kt` | 219, 223, 231 | ☐ | `setAlarmClock()`, `setExactAndAllowWhileIdle()`, `setExact()` |
| Check WorkManager usage | `FetchWorker.kt` | 31 | ☐ | `scheduleFetch()` |
| Check notification display | `DailyNotificationWorker.java` | 200+ | ☐ | `displayNotification()` |
| Check boot receiver | `BootReceiver.kt` | 24 | ☐ | `onReceive()` handles `BOOT_COMPLETED` |
| Check persistence | `DailyNotificationPlugin.kt` | 1393+ | ☐ | Room database storage |
| Check exact alarm permission | `DailyNotificationPlugin.kt` | 1309 | ☐ | `canScheduleExactAlarms()` |
| Check manifest permissions | `AndroidManifest.xml` | - | ☐ | `RECEIVE_BOOT_COMPLETED`, `SCHEDULE_EXACT_ALARM` |
### 1.2 Behavior Testing Matrix
#### Test 1: Base Case
| Step | Action | Trigger Source | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | -------------- | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule alarm 2 minutes in future | Plugin | - | Alarm scheduled | ☐ | |
| 2 | Leave app in foreground/background | - | - | - | ☐ | |
| 3 | Wait for trigger time | OS | Alarm fires | Notification displayed | ☐ | |
| 4 | Check logs | - | - | No errors | ☐ | |
**Trigger Source Definitions**:
- **OS**: Operating system initiates the action (alarm fires, boot completes, etc.)
- **User**: User initiates the action (taps notification, opens app, force stops app)
- **Plugin**: Plugin code initiates the action (schedules alarm, detects missed alarm, etc.)
**Code Reference**: `NotifyReceiver.scheduleExactNotification()` line 92
**Platform Behavior**: See [Platform Reference §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents)
---
#### Test 2: Swipe from Recents
**Preconditions**:
- App installed and launched at least once
- Alarm scheduling permission granted (if required)
- Test device: [Device model, OS version]
- App build: [Git commit hash or build number]
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
| 1 | Schedule alarm 2-5 minutes in future | Plugin | - | Alarm scheduled | ☐ | | ☐ |
| 2 | Swipe app away from recents | User | - | - | ☐ | | ☐ |
| 3 | Wait for trigger time | OS | ✅ Alarm fires (OS resurrects process) - [Doc A §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents) | ✅ Notification displayed - [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform) | ☐ | | ☐ |
| 4 | Check app state on wake | OS | Cold start | App process recreated | ☐ | | ☐ |
| 5 | Check logs | - | - | No errors | ☐ | | ☐ |
**Code Reference**: `NotifyReceiver.scheduleExactNotification()` uses `setAlarmClock()` line 219
**Platform Behavior Reference**: [Doc A §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents) - OS-guaranteed
---
#### Test 3: OS Kill (Memory Pressure)
**Preconditions**:
- App installed and launched at least once
- Alarm scheduled and verified in AlarmManager
- Test device: [Device model, OS version]
- App build: [Git commit hash or build number]
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
| 1 | Schedule alarm 2-5 minutes in future | Plugin | - | Alarm scheduled | ☐ | | ☐ |
| 2 | Force kill via `adb shell am kill <package>` | User/OS | - | - | ☐ | | ☐ |
| 3 | Wait for trigger time | OS | ✅ Alarm fires - [Doc A §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents) | ✅ Notification displayed - [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform) | ☐ | | ☐ |
| 4 | Check logs | - | - | No errors | ☐ | | ☐ |
**Platform Behavior Reference**: [Doc A §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents) - OS-guaranteed
---
#### Test 4: Device Reboot
**Preconditions**:
- App installed and launched at least once
- Alarm scheduled and verified in database
- Boot receiver registered in manifest
- Test device: [Device model, OS version]
- App build: [Git commit hash or build number]
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
| 1 | Schedule alarm 10 minutes in future | Plugin | - | Alarm scheduled | ☐ | | ☐ |
| 2 | Reboot device | User | - | - | ☐ | | ☐ |
| 3 | Do NOT open app | - | ❌ Alarm does NOT fire - [Doc A §2.1.2](./01-platform-capability-reference.md#212-alarms-can-be-preserved-across-device-reboot) | ❌ No notification | ☐ | | ☐ |
| 4 | Wait past scheduled time | - | ❌ No automatic firing | ❌ No notification | ☐ | | ☐ |
| 5 | Open app manually | User | - | Plugin detects missed alarm - [Doc C §4.2](./03-plugin-requirements.md#42-detection-triggers) | ☐ | | ☐ |
| 6 | Check missed alarm handling | Plugin | - | ✅ Missed alarm detected - [Doc C §4.3](./03-plugin-requirements.md#43-required-actions) | ☐ | | ☐ |
| 7 | Check rescheduling | Plugin | - | ✅ Future alarms rescheduled - [Doc C §3.1.1](./03-plugin-requirements.md#311-boot-event-android-only) | ☐ | | ☐ |
**Code Reference**:
- Boot receiver: `BootReceiver.kt` line 24
- Rescheduling: `BootReceiver.kt` line 38+
**Platform Behavior Reference**: [Doc A §2.1.2](./01-platform-capability-reference.md#212-alarms-can-be-preserved-across-device-reboot) - Plugin-required
**Plugin Requirement Reference**: [Doc C §3.1.1](./03-plugin-requirements.md#311-boot-event-android-only) - Boot event recovery
---
#### Test 5: Android Force Stop
**Preconditions**:
- App installed and launched at least once
- Multiple alarms scheduled (past and future)
- Test device: [Device model, OS version]
- App build: [Git commit hash or build number]
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
| 1 | Schedule alarms (past and future) | Plugin | - | Alarms scheduled | ☐ | | ☐ |
| 2 | Go to Settings → Apps → [App] → Force Stop | User | ❌ All alarms removed - [Doc A §2.2.1](./01-platform-capability-reference.md#221-you-cannot-survive-force-stop) | ❌ All alarms removed | ☐ | | ☐ |
| 3 | Wait for trigger time | - | ❌ Alarm does NOT fire - [Doc A §2.2.1](./01-platform-capability-reference.md#221-you-cannot-survive-force-stop) | ❌ No notification | ☐ | | ☐ |
| 4 | Open app again | User | - | Plugin detects force stop scenario - [Doc C §3.1.4](./03-plugin-requirements.md#314-force-stop-recovery-android-only) | ☐ | | ☐ |
| 5 | Check recovery | Plugin | - | ✅ All past alarms marked as missed - [Doc C §3.1.4](./03-plugin-requirements.md#314-force-stop-recovery-android-only) | ☐ | | ☐ |
| 6 | Check rescheduling | Plugin | - | ✅ All future alarms rescheduled - [Doc C §3.1.4](./03-plugin-requirements.md#314-force-stop-recovery-android-only) | ☐ | | ☐ |
**Platform Behavior Reference**: [Doc A §2.2.1](./01-platform-capability-reference.md#221-you-cannot-survive-force-stop) - Forbidden
**Plugin Requirement Reference**: [Doc C §3.1.4](./03-plugin-requirements.md#314-force-stop-recovery-android-only) - Force stop recovery
---
#### Test 6: Exact Alarm Permission (Android 12+)
**Preconditions**:
- Android 12+ (API 31+) device
- App installed and launched at least once
- Test device: [Device model, OS version]
- App build: [Git commit hash or build number]
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
| 1 | Revoke exact alarm permission | User | - | - | ☐ | | ☐ |
| 2 | Attempt to schedule alarm | Plugin | - | Plugin requests permission - [Doc C §8.1.1](./03-plugin-requirements.md#811-permissions) | ☐ | | ☐ |
| 3 | Check settings opened | Plugin | - | ✅ Settings opened | ☐ | | ☐ |
| 4 | Grant permission | User | - | - | ☐ | | ☐ |
| 5 | Schedule alarm | Plugin | - | ✅ Alarm scheduled | ☐ | | ☐ |
| 6 | Verify alarm fires | OS | ✅ Alarm fires - [Doc A §5.2](./01-platform-capability-reference.md#52-android-s-exact-alarm-permission-decision-tree) | ✅ Notification displayed | ☐ | | ☐ |
**Code Reference**: `DailyNotificationPlugin.kt` line 1309, 1314-1324
**Platform Behavior Reference**: [Doc A §5.2](./01-platform-capability-reference.md#52-android-s-exact-alarm-permission-decision-tree) - Conditional
**Plugin Requirement Reference**: [Doc C §8.1.1](./03-plugin-requirements.md#811-permissions) - Permission handling
---
### 1.3 Persistence Investigation
| Item | Expected | Actual | Code Reference | Notes |
| ---- | -------- | ------ | -------------- | ----- |
| Alarm ID stored | ✅ Yes | ☐ | `DailyNotificationPlugin.kt` line 1393+ | |
| Trigger time stored | ✅ Yes | ☐ | Room database | |
| Repeat rule stored | ✅ Yes | ☐ | Schedule entity | |
| Channel/priority stored | ✅ Yes | ☐ | NotificationContentEntity | |
| Payload stored | ✅ Yes | ☐ | ContentCache | |
| Time created/modified | ✅ Yes | ☐ | Entity timestamps | |
**Storage Location**: Room database (`DailyNotificationDatabase`)
---
### 1.4 Recovery Points Investigation
| Recovery Point | Expected Behavior | Actual Behavior | Code Reference | Notes |
| -------------- | ----------------- | --------------- | -------------- | ----- |
| Boot event | ✅ Reschedule all alarms | ☐ | `BootReceiver.kt` line 24 | |
| App cold start | ✅ Detect missed alarms | ☐ | Check plugin initialization | |
| App warm start | ✅ Verify active alarms | ☐ | Check plugin initialization | |
| Background fetch return | ⚠️ May reschedule | ☐ | `FetchWorker.kt` | |
| User taps notification | ✅ Launch app | ☐ | Notification intent | |
---
## 2. Required Baseline Scenarios
**All six baseline scenarios MUST be tested**:
1.**Swipe-kill** - Test 2 (Android), Test 2 (iOS)
2.**OS low-RAM kill** - Test 3 (Android)
3.**Reboot** - Test 4 (Android), Test 3 (iOS)
4.**Force stop** - Test 5 (Android only)
5.**Cold start** - See [Test 4 Step 5](./02-plugin-behavior-exploration.md#test-4-device-reboot) (Android), Test 4 (iOS)
6.**Notification-tap resume** - See [Recovery Points §1.4](./02-plugin-behavior-exploration.md#14-recovery-points-investigation) (Both)
---
## 3. iOS Exploration
### 3.1 Code-Level Inspection Checklist
**Source Locations**:
- Plugin: `ios/Plugin/`
- Test App: `test-apps/ios-test-app/`
- Alternative: Check `ios-2` branch
| Task | File/Function | Line | Status | Notes |
| ---- | ------------- | ---- | ------ | ----- |
| Locate main plugin class | `DailyNotificationPlugin.swift` | 506 | ☐ | `scheduleUserNotification()` |
| Identify notification scheduling | `DailyNotificationScheduler.swift` | 133 | ☐ | `scheduleNotification()` |
| Check UNUserNotificationCenter usage | `DailyNotificationScheduler.swift` | 185 | ☐ | `notificationCenter.add()` |
| Check trigger types | `DailyNotificationScheduler.swift` | 172 | ☐ | `UNCalendarNotificationTrigger` |
| Check BGTaskScheduler usage | `DailyNotificationPlugin.swift` | 495 | ☐ | `scheduleBackgroundFetch()` |
| Check persistence | `DailyNotificationPlugin.swift` | 35 | ☐ | `storage: DailyNotificationStorage?` |
| Check app launch recovery | `DailyNotificationPlugin.swift` | 42 | ☐ | `load()` method |
### 3.2 Behavior Testing Matrix
#### Test 1: Base Case
| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule notification 2-5 minutes in future | - | Notification scheduled | ☐ | |
| 2 | Leave app backgrounded | - | - | ☐ | |
| 3 | Wait for trigger time | ✅ Notification fires | ✅ Notification displayed | ☐ | |
| 4 | Check logs | - | No errors | ☐ | |
**Code Reference**: `DailyNotificationScheduler.scheduleNotification()` line 133
**Platform Behavior**: See [Platform Reference §3.1.1](./01-platform-capability-reference.md#311-notifications-survive-app-termination)
---
#### Test 2: Swipe App Away
**Preconditions**:
- App installed and launched at least once
- Notification scheduled and verified
- Test device: [Device model, OS version]
- App build: [Git commit hash or build number]
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
| 1 | Schedule notification 2-5 minutes in future | Plugin | - | Notification scheduled | ☐ | | ☐ |
| 2 | Swipe app away from app switcher | User | - | - | ☐ | | ☐ |
| 3 | Wait for trigger time | OS | ✅ Notification fires (OS handles) - [Doc A §3.1.1](./01-platform-capability-reference.md#311-notifications-survive-app-termination) | ✅ Notification displayed - [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform) | ☐ | | ☐ |
| 4 | Check app state | OS | App terminated | App not running | ☐ | | ☐ |
**Platform Behavior Reference**: [Doc A §3.1.1](./01-platform-capability-reference.md#311-notifications-survive-app-termination) - OS-guaranteed
---
#### Test 3: Device Reboot
**Preconditions**:
- App installed and launched at least once
- Notification scheduled with calendar/time trigger
- Test device: [Device model, OS version]
- App build: [Git commit hash or build number]
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
| 1 | Schedule notification for future time | Plugin | - | Notification scheduled | ☐ | | ☐ |
| 2 | Reboot device | User | - | - | ☐ | | ☐ |
| 3 | Do NOT open app | OS | ✅ Notification fires (OS persists) - [Doc A §3.1.2](./01-platform-capability-reference.md#312-notifications-persist-across-device-reboot) | ✅ Notification displayed - [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform) | ☐ | | ☐ |
| 4 | Check notification timing | OS | ✅ On time (±180s tolerance) - [Doc A §6.1](./01-platform-capability-reference.md#61-notification-timing-accuracy) | ✅ On time | ☐ | | ☐ |
**Platform Behavior Reference**: [Doc A §3.1.2](./01-platform-capability-reference.md#312-notifications-persist-across-device-reboot) - OS-guaranteed
**Note**: Only calendar and time-based triggers persist. Location triggers do not - See [Doc A §3.1.2](./01-platform-capability-reference.md#312-notifications-persist-across-device-reboot)
---
#### Test 4: Hard Termination & Relaunch
| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule repeating notifications | - | Notifications scheduled | ☐ | |
| 2 | Terminate app via Xcode/switcher | - | - | ☐ | |
| 3 | Allow some triggers to occur | ✅ Notifications fire | ✅ Notifications displayed | ☐ | |
| 4 | Reopen app | - | Plugin checks for missed events | ☐ | |
| 5 | Check missed event detection | ⚠️ May detect | ☐ | Plugin-specific |
| 6 | Check state recovery | ⚠️ May recover | ☐ | Plugin-specific |
**Platform Behavior**: OS-guaranteed for notifications; Plugin-guaranteed for missed event detection
---
#### Test 5: Background Execution Limits
| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule BGTaskScheduler task | - | Task scheduled | ☐ | |
| 2 | Wait for system to execute | ⚠️ System-controlled | ⚠️ May not execute | ☐ | |
| 3 | Check execution timing | ⚠️ Not guaranteed | ⚠️ Not guaranteed | ☐ | |
| 4 | Check time budget | ⚠️ ~30 seconds | ⚠️ Limited time | ☐ | |
**Code Reference**: `DailyNotificationPlugin.scheduleBackgroundFetch()` line 495
**Platform Behavior**: Conditional (see [Platform Reference §3.1.3](./01-platform-capability-reference.md#313-background-tasks-for-prefetching))
---
### 3.3 Persistence Investigation
| Item | Expected | Actual | Code Reference | Notes |
| ---- | -------- | ------ | -------------- | ----- |
| Notification ID stored | ✅ Yes (in UNUserNotificationCenter) | ☐ | `UNNotificationRequest` | |
| Plugin-side storage | ⚠️ May not exist | ☐ | `DailyNotificationStorage?` | |
| Trigger time stored | ✅ Yes (in trigger) | ☐ | `UNCalendarNotificationTrigger` | |
| Repeat rule stored | ✅ Yes (in trigger) | ☐ | `repeats: true/false` | |
| Payload stored | ✅ Yes (in userInfo) | ☐ | `notificationContent.userInfo` | |
**Storage Location**:
- Primary: UNUserNotificationCenter (OS-managed)
- Secondary: Plugin storage (if implemented)
---
### 3.4 Recovery Points Investigation
| Recovery Point | Expected Behavior | Actual Behavior | Code Reference | Notes |
| -------------- | ----------------- | --------------- | -------------- | ----- |
| Boot event | ✅ Notifications fire automatically | ☐ | OS handles | |
| App cold start | ⚠️ May detect missed notifications | ☐ | Check `load()` method | |
| App warm start | ⚠️ May verify pending notifications | ☐ | Check plugin initialization | |
| Background fetch | ⚠️ May reschedule | ☐ | `BGTaskScheduler` | |
| User taps notification | ✅ App launched | ☐ | Notification action | |
---
## 4. Cross-Platform Comparison
### 3.1 Observed Behavior Summary
| Scenario | Android (Observed) | iOS (Observed) | Platform Difference |
| -------- | ------------------ | -------------- | ------------------- |
| Swipe/termination | ☐ | ☐ | Both should work |
| Reboot | ☐ | ☐ | iOS auto, Android manual |
| Force stop | ☐ | N/A | Android only |
| App code on trigger | ☐ | ☐ | Android yes, iOS no |
| Background execution | ☐ | ☐ | Android more flexible |
---
## 5. Findings & Gaps
### 4.1 Android Gaps
| Gap | Severity | Description | Recommendation |
| --- | -------- | ----------- | -------------- |
| Boot recovery | ☐ Critical/Major/Minor/Expected | Does plugin reschedule on boot? | Implement if missing |
| Missed alarm detection | ☐ Critical/Major/Minor/Expected | Does plugin detect missed alarms? | Implement if missing |
| Force stop recovery | ☐ Critical/Major/Minor/Expected | Does plugin recover after force stop? | Implement if missing |
| Persistence completeness | ☐ Critical/Major/Minor/Expected | Are all required fields persisted? | Verify and add if missing |
**Severity Classification**:
- **Critical**: Breaks plugin guarantee (see [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform))
- **Major**: Unexpected but recoverable (plugin works but behavior differs from expected)
- **Minor**: Non-blocking deviation (cosmetic or edge case)
- **Expected**: Platform limitation (documented in [Doc A](./01-platform-capability-reference.md))
### 4.2 iOS Gaps
| Gap | Severity | Description | Recommendation |
| --- | -------- | ----------- | -------------- |
| Missed notification detection | ☐ Critical/Major/Minor/Expected | Does plugin detect missed notifications? | Implement if missing |
| Plugin-side persistence | ☐ Critical/Major/Minor/Expected | Does plugin persist state separately? | Consider if needed |
| Background task reliability | ☐ Critical/Major/Minor/Expected | Can plugin rely on BGTaskScheduler? | Document limitations |
**Severity Classification**: Same as Android (see above).
---
## 6. Deliverables from This Exploration
After completing this exploration, generate:
1. **Completed test results** - All checkboxes filled, actual results documented
2. **Gap analysis** - Documented limitations and gaps
3. **Annotated code pointers** - Code locations with findings
4. **Open Questions / TODOs** - Unresolved issues
---
## Related Documentation
- [Platform Capability Reference](./01-platform-capability-reference.md) - OS-level facts
- [Plugin Requirements](./03-plugin-requirements.md) - Requirements based on findings
- [Unified Alarm Directive](./000-UNIFIED-ALARM-DIRECTIVE.md) - Master coordination document
---
## Notes for Explorers
* Fill in checkboxes (☐) as you complete each test
* Document actual results in "Actual Result" columns
* Add notes for any unexpected behavior
* Reference code locations when documenting findings
* Update "Findings & Gaps" section as you discover issues
* Use platform capability reference to understand expected OS behavior
* Link to Platform Reference sections instead of duplicating platform facts

File diff suppressed because it is too large Load Diff