Files
pluriwave/openspec/changes/snooze-reschedule-fix/proposal.md
T
FreeTLab bccc5c48b8
Build & Deploy PluriWave / Análisis de código (push) Successful in 38s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m30s
docs(openspec): add SDD artifact trail for recent alarm and EQ changes
Persist the exploration, proposal, spec, design, tasks, and
verify/archive reports produced during the multi-device EQ,
alarm-countdown, and notification-visual-polish SDD cycles.
2026-07-04 12:42:11 +02:00

67 lines
5.4 KiB
Markdown

# Proposal: Snooze Reschedule Reliability Fix
## Intent
Snoozing an alarm silently fails: the alarm never re-fires, no countdown notification appears, and the "Next alarm" panel keeps showing the already-fired alarm. Confirmed structural defect (exploration `sdd/snooze-reschedule-fix/explore`): `posponerAlarma()` and `posponerProximaDesdePreaviso()` await `android.programar()` with NO try/catch, so a native scheduling failure (most likely exact-alarm permission revoked — these methods never re-request it) throws past `notifyListeners()`, leaving in-memory state mutated but UI stale and no real alarm armed. `guardarAlarma()` already handles this correctly; the snooze paths regressed. Snooze is core alarm functionality — silent failure is critical.
## Scope
### In Scope
- Wrap `android.programar()` in try/catch in `posponerAlarma()` and `posponerProximaDesdePreaviso()`, always reaching `notifyListeners()` (mirror `guardarAlarma()`).
- Add `_solicitarPermisosNecesariosParaAlarma()` pre-check before scheduling in both snooze methods.
- Surface failure to the user in `_posponer()` (SnackBar/feedback) instead of silent `debugPrint`.
- Regression tests (Strict TDD) for both snooze paths: success reschedules + notifies; failure still notifies + reports error.
### Out of Scope
- **Notification visual improvements** (custom small icon, color theming, action-button icons, BigTextStyle, fallback artwork, channel groups) — split into a separate change `notification-visual-polish` (see Approach for rationale).
- Changing the Kotlin `scheduleMainAlarm()` inexact-fallback policy (intentional behavior; out of this fix).
- iOS snooze path (this defect is Android-specific).
## Capabilities
### New Capabilities
- `alarm-snooze-reschedule`: snoozing an alarm MUST reliably re-arm the native alarm, refresh the UI, and report any scheduling failure to the user — covering both ringing-screen snooze and pre-notice snooze.
### Modified Capabilities
- None. (`alarm-pre-notice-countdown` behavior is unchanged; only its scheduling reliability is hardened, which the new capability covers.)
## Approach
Mirror the proven `guardarAlarma()` pattern in both snooze methods: permission pre-check → try/schedule/catch-into-`_error``notifyListeners()` in a `finally` so the widget tree always rebuilds. Propagate a failure signal to `_posponer()` for user-visible feedback (the ringing screen dismisses by design, so feedback must survive dismissal). Dart-only change — fully testable under Strict TDD with a mocked `ServicioAlarmasAndroid`.
**Split decision (one of the two questions this proposal answers):** Bug fix and notification visuals are SEPARATE changes. Justification: (1) **Risk isolation** — a critical, fast, Dart-only, fully-testable fix must not be blocked or complicated by cosmetic Kotlin work that has no test infra. (2) **File overlap is shallow** — the bug fix barely touches Kotlin (only optionally a signal in `scheduleSpec`); visuals are Kotlin-heavy. Coupling them would force the critical fix through a larger, riskier review. (3) **Delivery** — this fix is small (well under the 400-line budget), ships as a single PR with no `size:exception`; visuals ship later as their own change.
## Affected Areas
| Area | Impact | Description |
|------|--------|-------------|
| `lib/estado/estado_alarmas.dart` | Modified | try/catch + permission pre-check + guaranteed `notifyListeners()` in both snooze methods |
| `lib/pantallas/pantalla_alarma_sonando.dart` | Modified | `_posponer()` surfaces snooze failure to user |
| `test/` (Dart) | New | Regression tests for both snooze paths (success + failure) |
| `android/.../AlarmScheduler.kt` | Modified (optional) | Optionally distinguish "main fire failed" so caller can react — only if needed by tests |
## Risks
| Risk | Likelihood | Mitigation |
|------|------------|------------|
| Root cause is permission-dependent; unconfirmed without device logcat | Med | Fix targets the confirmed structural defect (missing try/catch + notify), valid regardless of which native call failed |
| Different unfound bug if permission was actually granted | Low | Request `adb logcat` (tag `PluriWave`) for a snooze attempt before/alongside implementation |
| Re-requesting permission at snooze time disrupts the ringing UX | Low | Pre-check mirrors `guardarAlarma()`; if already granted it's a no-op |
## Rollback Plan
Single-PR, Dart-focused change. Revert by reverting the PR commit(s) — `estado_alarmas.dart` and `pantalla_alarma_sonando.dart` return to current behavior; new tests removed with the revert. No data migration, no schema change, no persisted-state format change, so rollback is clean with zero residual state.
## Dependencies
- Optional but recommended: device `adb logcat` (tag `PluriWave`) confirming `scheduleMainAlarm`/`setAlarmClock` failure, to upgrade the hypothesis to a confirmed reproduction.
## Success Criteria
- [ ] Snoozing from the ringing screen re-arms the native alarm; it rings again at the snooze time.
- [ ] The per-minute countdown notification appears after snoozing.
- [ ] The "Next alarm" panel updates immediately to the snoozed time (UI rebuilds via `notifyListeners()`).
- [ ] On scheduling failure, the user sees explicit feedback (no silent failure) and the UI still rebuilds.
- [ ] Pre-notice snooze (`posponerProximaDesdePreaviso`) has identical reliability.
- [ ] Dart regression tests cover success and failure for both paths and pass under `flutter test`.