|
|
|
@@ -142,11 +142,46 @@ Chain strategy: pending
|
|
|
|
|
|
|
|
|
|
## Phase 4: Fade-In Dedup at Handoff (Slice 3, strict TDD)
|
|
|
|
|
|
|
|
|
|
- [ ] 4.1 (RED) In `test/pantallas/pantalla_alarma_sonando_test.dart` (or a new focused fade-in test file), add a widget test asserting the Dart fade-in ramp (observable via `FakeServicioAudio`/fallback player volume changes) does NOT start before `confirmarAudioFlutter` has been invoked on the android port (i.e., before `_confirmarAudioFlutterListo()` runs) — assert `env.android.detenidas` (which `confirmarAudioFlutter` appends to, per `FakePuertoAlarmasAndroid.confirmarAudioFlutter`) is non-empty before any volume-ramp step is observed. Run `flutter test` — confirm it fails (current code starts the ramp at L66 immediately after `radio.reproducir`, before confirmation).
|
|
|
|
|
- [ ] 4.2 (RED) Add a test asserting the fade-in DOES start once `_confirmarAudioFlutterListo()` has run (radio path via `estadoStream` emitting `reproduciendo`, or fallback path via `_iniciarFallback`) — the ramp must still function end-to-end after the gate. Run `flutter test` — confirm it fails or is trivially satisfied depending on 4.1's fixture; treat 4.1+4.2 as one RED pair validating gate correctness both ways.
|
|
|
|
|
- [ ] 4.3 (GREEN) In `lib/pantallas/pantalla_alarma_sonando.dart`, remove the `_iniciarFadeIn()` call at L66 (radio path, currently fires immediately after `radio.reproducir(emisora)`) and the one at L96 (fallback path, currently fires before `_confirmarAudioFlutterListo()` at L97); move the single `_iniciarFadeIn()` invocation INTO `_confirmarAudioFlutterListo()` (L133-139) so it fires exactly once, after the `_audioFlutterConfirmado` guard, for both the radio and fallback paths. Run `flutter test` — confirm 4.1-4.2 pass.
|
|
|
|
|
- [ ] 4.4 (REFACTOR) Re-run the full `pantalla_alarma_sonando_test.dart` and `pantalla_alarma_sonando_dismiss_guard_test.dart` suites — confirm no existing fade/dismiss/snooze assertions regressed from moving the ramp start point.
|
|
|
|
|
- [ ] 4.5 `flutter analyze` and `dart format .` — confirm clean formatting/lint state for all Slice 3 edits.
|
|
|
|
|
- [x] 4.1 (RED) In `test/pantallas/pantalla_alarma_sonando_test.dart` (or a new focused fade-in test file), add a widget test asserting the Dart fade-in ramp (observable via `FakeServicioAudio`/fallback player volume changes) does NOT start before `confirmarAudioFlutter` has been invoked on the android port (i.e., before `_confirmarAudioFlutterListo()` runs) — assert `env.android.detenidas` (which `confirmarAudioFlutter` appends to, per `FakePuertoAlarmasAndroid.confirmarAudioFlutter`) is non-empty before any volume-ramp step is observed. Run `flutter test` — confirm it fails (current code starts the ramp at L66 immediately after `radio.reproducir`, before confirmation).
|
|
|
|
|
- [x] 4.2 (RED) Add a test asserting the fade-in DOES start once `_confirmarAudioFlutterListo()` has run (radio path via `estadoStream` emitting `reproduciendo`, or fallback path via `_iniciarFallback`) — the ramp must still function end-to-end after the gate. Run `flutter test` — confirm it fails or is trivially satisfied depending on 4.1's fixture; treat 4.1+4.2 as one RED pair validating gate correctness both ways.
|
|
|
|
|
|
|
|
|
|
> Implementation note: 4.1+4.2 were implemented as a single RED pair (one `testWidgets`, two
|
|
|
|
|
> assertion stages) in `test/pantallas/pantalla_alarma_sonando_test.dart`, radio path. Rather than
|
|
|
|
|
> relying on real `estadoStream` subscription timing (existing `_montarPantalla` pre-emits
|
|
|
|
|
> `reproduciendo` BEFORE mount in all prior tests, which — traced via code inspection — means
|
|
|
|
|
> `_confirmarAudioFlutterListo()` never actually fires in those fixtures: the broadcast stream drops
|
|
|
|
|
> the pre-mount event, and the fallback timer's immediate-cancel branch also short-circuits before
|
|
|
|
|
> any listener would see it), added a new opt-out param `audioYaReproduciendo` (default `true`,
|
|
|
|
|
> preserves all existing tests byte-for-byte) plus a test-only `Completer`-based gate
|
|
|
|
|
> (`FakePuertoAlarmasAndroid.puertaConfirmarAudioFlutter`) on `confirmarAudioFlutter`, so the test
|
|
|
|
|
> can deterministically observe the pre-confirm state, release the gate, then observe the
|
|
|
|
|
> post-confirm state — independent of stream/timer race conditions. Confirmed RED against the
|
|
|
|
|
> pre-4.3 code: the gate-pending assertion failed with `Actual: [0.05, 0.85]` (ramp already fired
|
|
|
|
|
> before the gate was ever released), proving the ramp was ungated.
|
|
|
|
|
>
|
|
|
|
|
> Also added a THIRD test beyond the literal 4.1/4.2 wording, covering the explicit edge case in
|
|
|
|
|
> this batch's own dispatch instructions: if `confirmarAudioFlutter` FAILS (dead/never-there native
|
|
|
|
|
> channel), the Dart ramp must still start — the ring must never stay stuck at
|
|
|
|
|
> `_volumenInicialFadeIn` forever, since Dart is the only audible source once native is gone. Added
|
|
|
|
|
> `FakePuertoAlarmasAndroid.fallaConfirmarAudioFlutter` to simulate this. Confirmed RED against
|
|
|
|
|
> pre-4.3 code too: the fake's `StateError` propagated UNCAUGHT out of `_confirmarAudioFlutterListo()`
|
|
|
|
|
> (no try/catch existed), crashing the test — proving the failure path was unhandled before this
|
|
|
|
|
> slice.
|
|
|
|
|
|
|
|
|
|
- [x] 4.3 (GREEN) In `lib/pantallas/pantalla_alarma_sonando.dart`, remove the `_iniciarFadeIn()` call at L66 (radio path, currently fires immediately after `radio.reproducir(emisora)`) and the one at L96 (fallback path, currently fires before `_confirmarAudioFlutterListo()` at L97); move the single `_iniciarFadeIn()` invocation INTO `_confirmarAudioFlutterListo()` (L133-139) so it fires exactly once, after the `_audioFlutterConfirmado` guard, for both the radio and fallback paths. Run `flutter test` — confirm 4.1-4.2 pass.
|
|
|
|
|
|
|
|
|
|
> Implementation note: moved as specified. `_confirmarAudioFlutterListo()` now wraps the native
|
|
|
|
|
> channel call in `try { await ... } catch (e) { debugPrint(...); } finally { _iniciarFadeIn(); }` —
|
|
|
|
|
> matching the existing `try/catch/finally` idiom already used in `_detener()`/`_posponer()` in the
|
|
|
|
|
> same file. The `finally` block is what satisfies the failure-edge case above: whether the native
|
|
|
|
|
> confirmation succeeds or throws, the fade-in always starts exactly once (still gated by the
|
|
|
|
|
> pre-existing `_audioFlutterConfirmado` guard at the top of the method, unchanged). All 3 new tests
|
|
|
|
|
> (4.1+4.2 combined, plus the failure-edge test) pass after this change; `rg '_iniciarFadeIn'
|
|
|
|
|
> lib/` confirms exactly one call site remains (inside `_confirmarAudioFlutterListo`) plus the
|
|
|
|
|
> function definition itself.
|
|
|
|
|
|
|
|
|
|
- [x] 4.4 (REFACTOR) Re-run the full `pantalla_alarma_sonando_test.dart` and `pantalla_alarma_sonando_dismiss_guard_test.dart` suites — confirm no existing fade/dismiss/snooze assertions regressed from moving the ramp start point. (Also included `pantalla_alarma_sonando_scaffold_test.dart` and `servicio_alarmas_android_test.dart` for extra confidence since a shared fake was extended. 22/22 tests green, no regressions — none of the pre-existing tests assert on fade/volume timing, since none of them previously exercised `_confirmarAudioFlutterListo()` at all under the old pre-mount-emit fixture pattern, as traced in the 4.1/4.2 note above.)
|
|
|
|
|
- [x] 4.5 `flutter analyze` and `dart format .` — confirm clean formatting/lint state for all Slice 3 edits. (`flutter analyze`: 0 issues. `dart format .` reformatted the 3 Slice 3 files cleanly; it also touched 8 files unrelated to this change — pre-existing formatter-version drift on `main`, confirmed reproducible and out of scope per this batch's file-scope constraint — reverted via `git checkout --` both times it recurred, see Phase 6 6.3 note.)
|
|
|
|
|
|
|
|
|
|
## Phase 5: Manual/On-Device QA (mandatory human gate — Android 14+ physical or emulator device)
|
|
|
|
|
|
|
|
|
@@ -161,6 +196,48 @@ Chain strategy: pending
|
|
|
|
|
|
|
|
|
|
## Phase 6: Final Static Sweep
|
|
|
|
|
|
|
|
|
|
- [ ] 6.1 Full-repo `rg 'systemExempted|SYSTEM_EXEMPTED'` across `android/app/src/main` — confirm zero remaining references (fully dropped, not kept alongside `alarm`).
|
|
|
|
|
- [ ] 6.2 `flutter test` (full suite) and `flutter analyze` — final clean run before requesting review.
|
|
|
|
|
- [ ] 6.3 `dart format .` — confirm no formatting diffs remain uncommitted.
|
|
|
|
|
- [x] 6.1 Full-repo `rg 'systemExempted|SYSTEM_EXEMPTED'` across `android/app/src/main` — confirm zero remaining references (fully dropped, not kept alongside `alarm`).
|
|
|
|
|
|
|
|
|
|
> **INTERPRETATION FLIP (sdd-apply, 2026-07-11):** this check's original "zero remaining
|
|
|
|
|
> references" wording was written under the Phase 1 premise that later proved false. Ran it anyway:
|
|
|
|
|
> 3 references found (`AndroidManifest.xml:6` permission, `AndroidManifest.xml:58`
|
|
|
|
|
> `foregroundServiceType`, `PluriWaveAlarmService.kt:124` runtime constant) — all `systemExempted`/
|
|
|
|
|
> `SYSTEM_EXEMPTED`, none `alarm`. This is the CORRECT and EXPECTED state, not a failure: per the
|
|
|
|
|
> Phase 1 cancellation banner (design.md correction, confirmed via `javap -constants` SDK
|
|
|
|
|
> inspection), `FOREGROUND_SERVICE_TYPE_ALARM`/`FOREGROUND_SERVICE_ALARM` are fictional and
|
|
|
|
|
> `mediaPlayback|systemExempted` is confirmed the correct, intentional declaration — so
|
|
|
|
|
> "fully dropped" is no longer the right target; "present and internally consistent between
|
|
|
|
|
> manifest and runtime" is. Manifest (`systemExempted` at L6+L58) and Kotlin runtime
|
|
|
|
|
> (`FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED` at L124) match each other exactly, same as before this
|
|
|
|
|
> entire change — Slice 1 shipped no code (cancelled), so this file pair was never touched by any
|
|
|
|
|
> batch of this change. Marking complete because the check RAN and its result was interpreted
|
|
|
|
|
> correctly against the corrected design, not because the literal original wording's outcome was
|
|
|
|
|
> achieved.
|
|
|
|
|
|
|
|
|
|
- [x] 6.2 `flutter test` (full suite) and `flutter analyze` — final clean run before requesting review.
|
|
|
|
|
|
|
|
|
|
> Implementation note: the full-suite invocation reproduced the documented intermittent hang (this
|
|
|
|
|
> task's own dispatch instructions named `estado_alarmas_ejecuciones_test.dart` and
|
|
|
|
|
> `servicio_grabacion_radio_test.dart` as known culprits) — it stalled past `+276` tests for several
|
|
|
|
|
> minutes of real time with zero further progress and had to be killed. Fell back exactly as
|
|
|
|
|
> instructed: ran all 44 other test files (everything under `test/` except those two) together —
|
|
|
|
|
> `01:02 +272: All tests passed!`, zero failures. Then ran the two known-flaky files standalone —
|
|
|
|
|
> `+7: All tests passed!`, zero failures, confirming (again) they only misbehave under full-suite
|
|
|
|
|
> load, not on their own — same conclusion already recorded in Batch 2's apply-progress for
|
|
|
|
|
> `servicio_grabacion_radio_test.dart` (`_fallar must clear activa flag immediately`, timing-
|
|
|
|
|
> sensitive). 272 + 7 = 279 tests total across all 46 files in the suite, all green. `flutter
|
|
|
|
|
> analyze`: 0 issues.
|
|
|
|
|
|
|
|
|
|
- [x] 6.3 `dart format .` — confirm no formatting diffs remain uncommitted.
|
|
|
|
|
|
|
|
|
|
> Implementation note: `dart format .` left the 3 files this batch touched
|
|
|
|
|
> (`lib/pantallas/pantalla_alarma_sonando.dart`, `test/helpers/fakes_alarmas.dart`,
|
|
|
|
|
> `test/pantallas/pantalla_alarma_sonando_test.dart`) untouched on its second run (already clean
|
|
|
|
|
> from the 4.5 pass) — confirmed via `git status --short` showing only those 3 files modified. Both
|
|
|
|
|
> times `dart format .` ran in this batch (4.5 and 6.3) it ALSO reformatted 8 files this batch never
|
|
|
|
|
> edited (`lib/pantallas/pantalla_ajustes.dart`, `lib/servicios/servicio_ecualizador.dart`, and 6
|
|
|
|
|
> test files under `test/estado`, `test/pantallas`, `test/servicios`) — reverted both times via `git
|
|
|
|
|
> checkout --` to stay within this batch's file-scope constraint (only
|
|
|
|
|
> `pantalla_alarma_sonando.dart` + test files). This is pre-existing formatter-version drift already
|
|
|
|
|
> present on `main` before this change started, unrelated to Slice 2 or Slice 3 — worth a
|
|
|
|
|
> follow-up `dart format .` cleanup commit on its own, out of scope here.
|
|
|
|
|