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,34 @@
# Exploration: snooze-reschedule-fix
## Root Cause (single defect explains all 3 symptoms)
`lib/estado/estado_alarmas.dart``posponerAlarma()` (L194-212) and `posponerProximaDesdePreaviso()` (L214-236) call `await android.programar(actualizada)` with **no try/catch**, unlike `guardarAlarma()` (L98-115) which wraps the identical call in try/catch and still reaches `notifyListeners()` on failure.
### Failure chain
1. Native `scheduleMainAlarm()` likely fails (most probable: exact-alarm permission revoked on Android 14+/OEM battery manager — `posponerAlarma` never re-requests permission before scheduling, unlike `guardarAlarma` which calls `_solicitarPermisosNecesariosParaAlarma()` first)
2. `AlarmScheduler.scheduleSpec()` (Kotlin, L108-118): if `scheduleMainAlarm()` returns `false`, returns `false` immediately — **before reaching `scheduleSnoozeCountdown()` at L126**. This is why the countdown notification never appears too — same root cause as the no-refire bug.
3. `scheduleAlarm()` returns `false``ServicioAlarmasAndroid.programar()` throws `StateError`
4. Exception propagates out of `posponerAlarma()` **uncaught**`notifyListeners()` (L211) never reached, even though `_aplicar(config)` (L206) already mutated `_alarmas` in memory
5. `_posponer()` in `pantalla_alarma_sonando.dart` (L181-187) catches it only to `debugPrint` and dismiss the screen — no user feedback, no retry
6. Result: (A) no real fire alarm scheduled; (B) `scheduleSnoozeCountdown` never runs; (C) `proximaAlarma`/`proximaProgramable` getters hold correct data in memory but UI never rebuilds because `notifyListeners()` was skipped
## Ruled out (verified)
- PendingIntent requestCode collision — different formulas (31x vs 47x), correctly scoped
- Notification channel mismatch — channel created identically by both classes
- "Missing initial countdown post" — `scheduleSnoozeCountdown()` posts notification AND arms first tick in one call
- Dart→Kotlin Long encoding, `alarma.activa` flag, periodic resync, fire-vs-snooze race — all verified correct
## Affected Areas
- `lib/estado/estado_alarmas.dart``posponerAlarma()`, `posponerProximaDesdePreaviso()`: missing try/catch, missing notifyListeners()-on-failure, missing permission pre-check
- `android/.../AlarmScheduler.kt``scheduleSpec()` (81-137): early return false skips scheduleSnoozeCountdown entirely (by design, but compounds the silent Dart-side failure)
- `lib/pantallas/pantalla_alarma_sonando.dart``_posponer()`: swallows exception with only debugPrint, no user-facing signal
## Recommendation
1. Wrap `android.programar()` in both snooze methods in try/catch mirroring `guardarAlarma()` — always reach `notifyListeners()`
2. Add the same permission pre-check (`_solicitarPermisosNecesariosParaAlarma()`) before scheduling in both snooze methods
3. Surface failure to user in `_posponer()` (SnackBar) since the screen always dismisses regardless by design
4. Device-test with exact-alarm permission both granted and revoked
## Risks
- Root cause is permission-dependent; cannot be 100% confirmed without `adb logcat` from the device at failure time. Fix should land regardless since missing try/catch + missing notifyListeners is a confirmed defect independent of which native call failed underneath
- `posponerProximaDesdePreaviso` shares the identical defect, must be fixed together