docs(openspec): add SDD artifact trail for recent alarm and EQ changes
Build & Deploy PluriWave / Análisis de código (push) Successful in 38s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m30s

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.
This commit is contained in:
2026-07-04 12:42:11 +02:00
parent e5b6d8acb3
commit bccc5c48b8
64 changed files with 6020 additions and 0 deletions
@@ -0,0 +1,71 @@
# Alarm Snooze Reschedule Specification
## Purpose
Snoozing an alarm (from the ringing screen or from a pre-notice) MUST reliably re-arm the native Android alarm, refresh the in-app UI, and inform the user when scheduling fails. This spec covers `EstadoAlarmas.posponerAlarma()`, `EstadoAlarmas.posponerProximaDesdePreaviso()`, and the user-facing failure feedback in `_posponer()`.
## Requirements
### Requirement: Permission Pre-Check Before Snooze Scheduling
The system MUST call `_solicitarPermisosNecesariosParaAlarma()` before invoking `android.programar()` in both `posponerAlarma()` and `posponerProximaDesdePreaviso()`, mirroring `guardarAlarma()`.
#### Scenario: Exact-alarm permission was revoked since the alarm was created
- GIVEN the exact-alarm permission was previously granted but has since been revoked (OEM battery manager or Android 14 auto-revoke)
- WHEN the user snoozes the ringing alarm
- THEN the system re-requests the exact-alarm permission before calling `android.programar()`
#### Scenario: Permission already granted
- GIVEN the exact-alarm permission is currently granted
- WHEN the user snoozes the alarm
- THEN the permission pre-check is a no-op and scheduling proceeds immediately
### Requirement: Native Scheduling Failure Must Not Corrupt UI State
`posponerAlarma()` and `posponerProximaDesdePreaviso()` MUST wrap the call to `android.programar()` in try/catch and MUST call `notifyListeners()` regardless of whether scheduling succeeds or fails.
#### Scenario: Native scheduling succeeds (happy path)
- GIVEN the user snoozes an alarm from the ringing screen
- WHEN `android.programar()` completes successfully
- THEN the in-memory alarm state reflects the new `snoozeHasta`
- AND `notifyListeners()` is called
- AND the "next alarm" panel updates to show the snoozed time
- AND a per-minute countdown notification appears
- AND the native alarm re-fires at the snoozed time
#### Scenario: Native scheduling throws (failure path)
- GIVEN the user snoozes an alarm from the ringing screen
- WHEN `android.programar()` throws (e.g. `StateError` from a failed `scheduleAlarm` platform call)
- THEN the exception is caught inside `posponerAlarma()` (or `posponerProximaDesdePreaviso()`)
- AND `notifyListeners()` is still called
- AND no real alarm is left silently un-scheduled without the UI knowing
- AND the failure is recorded (e.g. into an error field) instead of propagating uncaught
#### Scenario: Pre-notice snooze failure (variant path)
- GIVEN the user snoozes from a pre-notice (not the ringing screen)
- WHEN `android.programar()` throws inside `posponerProximaDesdePreaviso()`
- THEN the same catch + `notifyListeners()` guarantee applies as in `posponerAlarma()`
### Requirement: User-Facing Failure Feedback
`_posponer()` in `pantalla_alarma_sonando.dart` MUST surface a scheduling failure to the user (e.g. via SnackBar) instead of only `debugPrint`.
#### Scenario: Snooze fails and ringing screen dismisses
- GIVEN `posponerAlarma()` reports a failure (via thrown/caught error or returned failure state)
- WHEN `_posponer()` handles the result
- THEN the ringing screen still dismisses (existing dismiss-by-design behavior is preserved)
- AND the user sees an explicit failure message (e.g. SnackBar) before or immediately after dismissal
- AND no failure is silently swallowed with only a debug log
#### Scenario: Snooze succeeds
- GIVEN `posponerAlarma()` completes successfully
- WHEN `_posponer()` handles the result
- THEN the ringing screen dismisses
- AND no failure message is shown