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

5.4 KiB

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-_errornotifyListeners() 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.