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,60 @@
# Verification Report: snooze-reschedule-fix
## Mode
Strict TDD (RED-GREEN-REFACTOR), hybrid artifact store.
## Test & Analysis Evidence
- `flutter analyze`: 0 issues.
- `flutter test`: 238 passed, 0 failed.
- `git diff --stat` on touched files: 295 changed lines (within 400-line review budget; tasks.md forecast of Low risk confirmed).
## Spec Compliance Matrix
| Requirement | Scenario | Status | Evidence |
|---|---|---|---|
| Permission Pre-Check Before Snooze Scheduling | Permission revoked since alarm created | PASS | `posponerAlarma()` L211 / `posponerProximaDesdePreaviso()` L242 call `_solicitarPermisosNecesariosParaAlarma()` before `android.programar()` |
| Permission Pre-Check Before Snooze Scheduling | Permission already granted (no-op) | PASS | Mirrors guardarAlarma()'s pre-check; covered implicitly by all passing-path tests |
| Native Scheduling Failure Must Not Corrupt UI State | Native scheduling succeeds (happy path) | PASS | `estado_alarmas_snooze_test.dart` L30-56, L336-363 |
| Native Scheduling Failure Must Not Corrupt UI State | Native scheduling throws (failure path) | PASS | `estado_alarmas_snooze_test.dart` L252-279 — no throw, notifyListeners fires, _error set, state committed |
| Native Scheduling Failure Must Not Corrupt UI State | Pre-notice snooze failure (variant) | PASS | `estado_alarmas_snooze_test.dart` L305-334 — identical assertions for posponerProximaDesdePreaviso |
| User-Facing Failure Feedback | Snooze fails, screen dismisses, SnackBar shown | PASS | `pantalla_alarma_sonando_dismiss_guard_test.dart` L300-337 |
| User-Facing Failure Feedback | Snooze succeeds, no failure SnackBar | PASS | `pantalla_alarma_sonando_dismiss_guard_test.dart` L339-357 |
All 7 scenarios PASS with runtime-passing covering tests.
## Design Compliance
| Decision | Status | Evidence |
|---|---|---|
| D1: try/catch + trailing unconditional notifyListeners() (NOT finally) | PASS | Confirmed in both methods, lib/estado/estado_alarmas.dart |
| D2: untyped catch(e), not `on StateError` | PASS | L214, L245 |
| D3: stays Future<void>, records into _error, UI reads after await | PASS | No throw/rethrow; both UI call sites read .error post-await |
| D4: ScaffoldMessenger captured BEFORE dismiss | PASS | pantalla_alarma_sonando.dart L179 |
| D5: _error = null at start of each method | PASS | L195, L226 + regression-guard tests |
| D6: no Kotlin edits | PASS | All touched files are Dart-only |
| D7: fallaProgramar switch on FakePuertoAlarmasAndroid | PASS | test/helpers/fakes_alarmas.dart L23, L36-38 |
## Task Completion
Phases 1-4 and 6: fully complete, matches code. Phase 5: GREEN code change (5.2-equivalent) implemented and verified correct; 5.1 (RED widget test) and 5.3 (refactor) not done — see gap analysis.
## Gap Analysis — Task 5.1 Exception (app.dart POSTPONE_NEXT widget test)
Assessed as a justified, scoped exception, not a blocking gap:
- Real, independently confirmed blocker: PluriWaveApp has no DI seams (EstadoAlarmas/EstadoRadio hardcoded in build()); EstadoRadio's default ServicioAudio() asserts on audio_service's _handlerGlobal, requiring AudioService.init() — unavailable in widget tests without platform channel setup. No existing test in the repo mounts PluriWaveApp for this same reason.
- The app.dart change (L303-315) is a 6-line mechanical mirror of the already-tested Phase 4 branch logic (error != null -> error SnackBar, else success SnackBar).
- Spec Requirement 3 explicitly names `_posponer()` in pantalla_alarma_sonando.dart, not app.dart's POSTPONE_NEXT handler — the spec's explicit test obligation is satisfied; app.dart wiring is a design-level completeness addition beyond the literal spec scenario text.
- flutter analyze clean, no existing test broken, code verified correct by inspection.
Conclusion: WARNING, not CRITICAL. Recommend a follow-up task to add DI seams to PluriWaveApp for future testability; does not block archive.
## Issues
**CRITICAL**: None.
**WARNING**:
1. Task 5.1 (RED widget test for app.dart POSTPONE_NEXT SnackBar) not written — architecturally blocked by PluriWaveApp's lack of DI seams. Code verified correct by inspection, mirrors fully-tested Phase 4 pattern. Recommend follow-up task for DI seams, not blocking.
**SUGGESTION**:
1. Consider a dedicated `alarmSnoozeFailed` l10n key instead of reusing androidExactAlarmScheduleError verbatim (deferred per design, not required).
2. No isolated unit test distinguishes "permission pre-check no-op" from "pre-check invoked-and-granted" — implicitly covered by all passing-path tests; an explicit spy-based assertion would strengthen confidence if internals change.
## Verdict
PASS WITH WARNINGS