# Phase 1 — TEST 1 Golden Run (Force-Stop Recovery - Database Restoration)

**Related Docs:**
- [PHASE1_TEST0_GOLDEN.md](./PHASE1_TEST0_GOLDEN.md)
- [PHASE1_TEST1_GOLDEN.md](./PHASE1_TEST1_GOLDEN.md)

---

## 1. Test Overview

**Test Name:** TEST 1 — Force-Stop Recovery: Database Restoration  
**Purpose:** Verify that after an Android **force-stop** (which clears all scheduled alarms), the plugin:

1. **Persists** the alarm schedule in its database.
2. **Detects** that alarms are missing on app launch.
3. **Rebuilds** the missing alarm(s) from the database.
4. Restores the **one-notification-per-day** contract:
   - Before force-stop: 1 alarm
   - After force-stop: 0 alarms
   - After recovery: 1 alarm (same trigger time as before force-stop)

This golden run documents a **known-good execution** on 2025-12-04.

---

## 2. Environment & Build Info

- **Date/Time of Run:** 2025-12-04 (around 09:51–09:55 UTC)
- **Command Used:**

  ```bash
  ./test-phase1.sh
  ```

* **Project:** `daily-notification-plugin` — `test-apps/android-test-app`

* **Gradle:**

  * Build invoked via `./gradlew assembleDebug` (through the script)
  * Gradle output included:

    ```text
    Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
    ```

* **APK Built:**

  ```text
  ./app/build/outputs/apk/debug/app-debug.apk
  ```

* **App ID:** `org.timesafari.dailynotification`

> **Note:** Device/emulator model & API level can be added here later if desired.

---

## 3. Step-by-Step Execution (Golden Run)

This section captures the **actual** sequence for the golden run.

1. Ran `./test-phase1.sh`.
2. Pre-flight checks:
   * ✅ ADB device connected
   * ✅ Emulator ready
3. Build phase:
   * ✅ Debug APK built successfully.
   * ✅ APK path: `./app/build/outputs/apk/debug/app-debug.apk`
4. Install phase:
   * ✅ Previous app uninstall succeeded
   * ✅ APK installed successfully
   * ✅ App verified in package list
   * ✅ Logcat cleared (twice)
5. **TEST 0** executed:
   * Configured plugin in UI (if needed).
   * Scheduled daily notification.
   * Verified:
     * Before scheduling: 0 plugin alarms.
     * After scheduling: 1 plugin alarm for **today**.
     * After fire/rollover: 1 plugin alarm for **tomorrow**.
   * **TEST 0 PASSED.**
6. **TEST 1** started:
   * Step 1: Detected 1 lingering plugin alarm (tomorrow's alarm from TEST 0).
   * Auto-reset:
     * Uninstalled app
     * Reinstalled APK
     * Cleared logcat
     * Verified plugin alarms = 0
   * Confirmed **clean starting state** for TEST 1.
7. Step 2: Launched app and confirmed plugin configured.
8. In UI: tapped **"Test Notification"** button (schedules a notification ~4 minutes in the future).
9. Step 3 (pre-FS verify):
   * Verified **1** plugin alarm exists in AlarmManager.
   * Confirmed alarm details (time, tag, type).
   * Confirmed scheduling logs with `source=TEST_NOTIFICATION`.
10. Step 4: Performed **force-stop** via `adb shell am force-stop org.timesafari.dailynotification`.
11. Step 5 (post-FS verify):
    * Verified plugin alarms = **0** (force-stop cleared alarms).
12. Step 6: Relaunched app (cold start).
13. Step 7 (recovery verify):
    * Verified plugin alarms = **1** after recovery.
    * Confirmed recovery logs under `DNP-REACTIVATION`:
      * App launch recovery
      * Boot recovery
      * `rescheduled=1`
    * Confirmed rescheduled alarm uses the **same scheduleId and triggerTime** as pre-force-stop.
14. Fire verification was **skipped** (`VERIFY_FIRE=false`).
15. TEST 1 summary:
    * ✅ Before FS: 1 alarm
    * ✅ After FS: 0 alarms
    * ✅ After recovery: 1 alarm
    * ✅ `rescheduled=1`, `errors=0`
    * ✅ TEST 1 PASSED.

---

## 4. Expected Script Output (Key Excerpts)

These are the **critical excerpts** from the test harness output for a passing TEST 1.

### 4.1 Clean Start & Auto-Reset

```text
→ Step 1: Clean start - checking for lingering alarms...
ℹ️  Current plugin notification alarms: 1
ℹ️  System/other alarms: 17 (for context)
⚠️  Found 1 lingering plugin alarm(s) - these will interfere with TEST 1.
ℹ️  TEST 1 needs a clean state (no existing plugin alarms).
ℹ️  Resetting app state via uninstall + reinstall...
ℹ️  Uninstalling existing app...
✅ App uninstall succeeded (clean slate).
ℹ️  Reinstalling APK...
✅ App reinstall succeeded.
ℹ️  Clearing logcat buffer after reinstall...
ℹ️  Rechecking plugin alarms after reset...
ℹ️  Plugin alarms after reset: 0 (expected: 0)
✅ App state reset complete. TEST 1 starting from clean state.
```

### 4.2 Alarm Scheduled Before Force-Stop

```text
→ Step 3: Verifying alarm exists in AlarmManager (BEFORE force-stop)...
ℹ️  Plugin alarms: 1 (expected: 1)
ℹ️  System/other alarms: 19 (for context)
✅ ✅ Single plugin alarm confirmed in AlarmManager (one per day)
ℹ️  Alarm details:
    RTC_WAKEUP #4: Alarm{161cd2b type 0 origWhen 1764842100000 whenElapsed 13009441 org.timesafari.dailynotification}
      tag=*walarm*:org.timesafari.daily.NOTIFICATION
      type=RTC_WAKEUP origWhen=2025-12-04 09:55:00.000 window=0 exactAllowReason=policy_permission repeatInterval=0 count=0 flags=0x3
      policyWhenElapsed: requester=+3m4s281ms app_standby=-6s566ms device_idle=-- battery_saver=--
--
ℹ️  Alarm scheduled for: Thu Dec  4 09:55:00 AM UTC 2025 (1764842100000 ms)
ℹ️  Checking logs for scheduling confirmation...
12-04 09:51:49.150  6803  6867 W DNP-SCHEDULE: Cancelling existing alarm before rescheduling: requestCode=3454, scheduleId=daily_1764841909137, source=TEST_NOTIFICATION
12-04 09:51:49.151  6803  6867 I DNP-NOTIFY: Scheduling alarm: triggerTime=2025-12-04 09:55:00, delayMs=190849, requestCode=3454, scheduleId=daily_1764841909137
12-04 09:51:49.152  6803  6867 I DNP-SCHEDULE: Scheduling OS alarm: variant=ALARM_CLOCK, action=org.timesafari.daily.NOTIFICATION, triggerTime=1764842100000, requestCode=3454, scheduleId=daily_1764841909137, source=TEST_NOTIFICATION, pendingIntentHash=267839060, showIntentHash=256236029
12-04 09:51:49.153  6803  6867 I DNP-NOTIFY: Alarm clock scheduled (setAlarmClock): triggerAt=1764842100000, requestCode=3454
```

### 4.3 Force-Stop & Alarm Clearance

```text
→ Step 4: Force-stopping app (clears all alarms)...
⚠️  Force-stop will clear ALL alarms from AlarmManager
ℹ️  Executing: adb shell am force-stop org.timesafari.dailynotification
ℹ️  Forcing stop of app process...
✅ Force stop issued
→ Step 5: Verifying alarms are MISSING from AlarmManager (AFTER force-stop)...
ℹ️  Plugin alarms after force-stop: 0 (expected: 0)
ℹ️  System/other alarms: 17 (for context)
✅ ✅ Plugin alarms cleared by force-stop (count: 0)
ℹ️  This confirms: Force-stop cleared alarms from AlarmManager
```

### 4.4 Recovery & Rescheduling

```text
→ Step 6: Relaunching app (triggers recovery from database)...
ℹ️  Clearing logcat buffer...
✅ Logs cleared
ℹ️  Launching app...
Starting: Intent { cmp=org.timesafari.dailynotification/.MainActivity }
✅ App launched
→ Step 7: Verifying recovery rebuilt alarms from database...
ℹ️  Plugin alarms after recovery: 1 (expected: 1)
ℹ️  System/other alarms: 21 (for context)
ℹ️  Checking recovery logs...

12-04 09:52:21.919  6954  7015 I DNP-REACTIVATION: Starting app launch recovery (Phase 1: cold start only)
12-04 09:52:21.926  6954  7015 I DNP-REACTIVATION: Cold start recovery: checking for missed notifications
12-04 09:52:21.937  6954  7015 I DNP-REACTIVATION: Rescheduled alarm: daily_1764841909137 for 1764842100000
12-04 09:52:21.937  6954  7015 I DNP-REACTIVATION: Rescheduled missing alarm: daily_1764841909137 at 1764842100000
12-04 09:52:21.952  6954  7015 I DNP-REACTIVATION: Cold start recovery complete: missed=0, rescheduled=1, verified=0, errors=0
12-04 09:52:21.952  6954  7015 I DNP-REACTIVATION: App launch recovery completed: missed=0, rescheduled=1, verified=0, errors=0
12-04 09:52:22.077  6954  7015 I DNP-REACTIVATION: Starting boot recovery
12-04 09:52:22.135  6954  7017 I DNP-REACTIVATION: Loaded 1 schedules from DB
12-04 09:52:22.138  6954  7017 I DNP-REACTIVATION: Rescheduled alarm: daily_1764841909137 for 1764842100000
12-04 09:52:22.143  6954  7017 I DNP-REACTIVATION: Boot recovery complete: missed=0, rescheduled=1, verified=0, errors=0
```

Final summary:

```text
✅ ✅ Alarms restored in AlarmManager (count: 1)
✅ ✅ Recovery logs confirm rescheduling (rescheduled=1)
✅ TEST 1 PASSED: Recovery successfully rebuilt alarms from database!
ℹ️  Summary:
  - Before force-stop: 1 alarm(s)
  - After force-stop: 0 alarm(s) (cleared)
  - After recovery: 1 alarm(s) (rebuilt)
  - Rescheduled: 1 alarm(s)
  - Verified: 0 alarm(s)
ℹ️  Skipping fire verification (VERIFY_FIRE=false, set VERIFY_FIRE=true to enable)
```

---

## 5. Expected `dumpsys alarm` Shapes

### 5.1 Before Force-Stop (Scheduled)

* **Plugin alarm count:** 1
* Example block (shape, not necessarily exact handle):

```text
RTC_WAKEUP #4: Alarm{161cd2b type 0 origWhen 1764842100000 whenElapsed 13009441 org.timesafari.dailynotification}
  tag=*walarm*:org.timesafari.daily.NOTIFICATION
  type=RTC_WAKEUP origWhen=2025-12-04 09:55:00.000 window=0 exactAllowReason=policy_permission repeatInterval=0 count=0 flags=0x3
  policyWhenElapsed: requester=+3m4s281ms app_standby=-6s566ms device_idle=-- battery_saver=--
```

### 5.2 After Force-Stop

* **Plugin alarm count:** 0
* No `*walarm*:org.timesafari.daily.NOTIFICATION` entries should appear.

### 5.3 After Recovery

* **Plugin alarm count:** 1
* Alarm should be restored with:
  * Same `scheduleId`: `daily_1764841909137`
  * Same `triggerTime`: `1764842100000` → `2025-12-04 09:55:00`

---

## 6. Expected `logcat` Patterns

For a passing run, look for:

* **Scheduling (before FS):**

  ```text
  DNP-NOTIFY: Scheduling alarm: triggerTime=2025-12-04 09:55:00, delayMs=..., requestCode=3454, scheduleId=daily_1764841909137
  DNP-SCHEDULE: Scheduling OS alarm: variant=ALARM_CLOCK, action=org.timesafari.daily.NOTIFICATION, triggerTime=1764842100000, requestCode=3454, scheduleId=daily_1764841909137, source=TEST_NOTIFICATION, ...
  ```

* **Recovery (after FS + relaunch):**

  ```text
  DNP-REACTIVATION: Starting app launch recovery (Phase 1: cold start only)
  DNP-REACTIVATION: Rescheduled alarm: daily_1764841909137 for 1764842100000
  DNP-REACTIVATION: Cold start recovery complete: missed=0, rescheduled=1, verified=0, errors=0
  DNP-REACTIVATION: App launch recovery completed: missed=0, rescheduled=1, verified=0, errors=0

  DNP-REACTIVATION: Starting boot recovery
  DNP-REACTIVATION: Loaded 1 schedules from DB
  DNP-REACTIVATION: Rescheduled alarm: daily_1764841909137 for 1764842100000
  DNP-REACTIVATION: Boot recovery complete: missed=0, rescheduled=1, verified=0, errors=0
  ```

Key invariants:

* `rescheduled=1`
* `errors=0`
* `scheduleId` and `triggerTime` match pre-FS values.

---

## 7. Quick Pass/Fail Checklist

A TEST 1 run is a **PASS** if all of the following are true:

* **Starting state:**
  * Script auto-resets if lingering alarms exist from TEST 0.
  * After reset: plugin alarm count = **0**.

* **Pre-force-stop:**
  * Plugin alarm count = **1**.
  * Alarm is tagged `*walarm*:org.timesafari.daily.NOTIFICATION`.
  * `triggerTime` and `origWhen` are consistent (e.g. `2025-12-04 09:55:00`, `1764842100000`).
  * `scheduleId` looks like `daily_<timestamp>` (here: `daily_1764841909137`).
  * Logs show `source=TEST_NOTIFICATION`.

* **After force-stop:**
  * Plugin alarm count = **0**.
  * No NOTIFICATION alarms remain in `dumpsys`.

* **After recovery (relaunch):**
  * Plugin alarm count = **1**.
  * Logs show `DNP-REACTIVATION` with:
    * `rescheduled=1`
    * `errors=0`
    * Same `scheduleId` and `triggerTime` as pre-FS.

* **Script summary:**
  * States:
    * Before force-stop: 1 alarm
    * After force-stop: 0 alarms
    * After recovery: 1 alarm
  * Ends with: `✅ TEST 1 PASSED: Recovery successfully rebuilt alarms from database!`

If any of these conditions fail, the run is **NOT GOLDEN** and should not overwrite this reference.

---

## 8. Notes / Deviations

* This golden run **skips fire verification** (`VERIFY_FIRE=false`).
  Future runs may enable fire verification; if that becomes standard, update this doc.
* It is acceptable for both:
  * **Cold start recovery** and
  * **Boot recovery**
  to run on app launch, as long as:
  * `rescheduled=1`
  * No duplicate alarms are scheduled.
* If OS behavior changes (e.g., force-stop no longer clears alarms on a future Android version), this test's expectations may need to be revised; document any such deviations explicitly here before changing the checklist.
