change: native-alarm-ring archived_date: 2026-07-12 status: archived archived_from: openspec/changes/native-alarm-ring verification_verdict: "FAIL at sdd-verify time, PASS WITH SUGGESTIONS after post-verify closures (contingent on Phase 3 on-device QA gate)" verify_report_observations: - id: 2393 type: verify-report critical_issues: 1 (CLOSED post-verify via commit 3f0267f/6f07e27) warnings: 1 (CLOSED post-verify via tasks 3.10/3.11 addition) suggestions: 3 (accepted-documented, non-blocking) artifacts_migrated: - explore.md (consolidates reliable-delivery + audio-architecture + code-map research; supersedes retired media-stream/handoff design after 5 on-device failures) - proposal.md (obs #2388) - specs/native-alarms/spec.md (obs #2389, delta merged into existing openspec/specs/native-alarms/spec.md) - design.md (obs #2390, 11 ADRs D1-D11) - tasks.md (obs #2391, on-disk copy has 37 checkboxes vs 35 in the engram observation -- see notes) - verify-report.md (obs #2393, FAIL verdict, preserved verbatim as historical pre-fix record) - apply-progress: engram-only (obs #2392), no separate on-disk file existed for this change phase_status: Phase 1 (Dart pure-UI ring screen + port reduction, WU1): COMPLETE - 14/14 tasks [x] - commit bd7f883 (rebase of 83e003a) on main, 8 files, +76/-638 Phase 2 (Kotlin native audio rebuild, WU2): COMPLETE - 12/12 tasks [x] - commit a69f397 (pushed as 884567b, identical tree) on main, base bd7f883, 2 files, +159/-247 Phase 3 (Final sweep + on-device QA): PENDING - 11 tasks [ ] (3.1-3.11; 3.10/3.11 added post-verify to close WARNING-1), mandatory human gate, not executable by any agent test_results: total_changed_lines: "WU1 714 (76+/638-), WU2 406 (159+/247-); total 1120 changed, net deletion ~403 lines" flutter_analyze: "0 issues (verify session, independently re-run; unaffected by post-verify fix per orchestrator note)" targeted_suites: - pantalla_alarma_sonando_test.dart - pantalla_alarma_sonando_dismiss_guard_test.dart - pantalla_alarma_sonando_scaffold_test.dart - servicio_alarmas_android_test.dart total_tests_passing: "16/16 targeted (verify session, re-run independently; 26 baseline - 10 deleted audio-mechanism tests)" repo_wide_rg_sweeps: "0 matches for every removed Dart/Kotlin symbol; setStreamVolume 0 matches anywhere; pluriwave_alarm_fire_v2 exactly 1 match (new LEGACY_CHANNEL_FIRE_V2 constant)" post_verify_fix: commit: "3f0267f (pushed as 6f07e27)" what: "CRITICAL-1 closed: added .setSound(null, null) inside ensureChannel()'s NotificationChannel(...).apply {} block, next to enableVibration(true) -- matches design ADR D4 exactly and the pre-notice channel's own precedent for real channel silence" evidence: "Re-verified via rg + flutter analyze 0 per orchestrator note; independently re-confirmed present at PluriWaveAlarmService.kt line 691 during this archive pass via direct file read" reflected_in_tasks_md: false post_verify_warning_closure: what: "WARNING-1 closed: tasks 3.10 (real v2->v3 channel migration test on an upgrade device) and 3.11 (dumpsys audio focus-abandon check) added to the Phase 3 QA checklist" reflected_in_tasks_md: true reflected_in_engram_obs_2391: false notes: | This change is an architecture REPLACEMENT, not an incremental feature: after 5 consecutive on-device failures under a split Dart/native media-stream handoff design (Dart ramp -> hand off to native -> override STREAM_MUSIC -> restore on dismiss), the ring was rebuilt native-only to AOSP DeskClock's AsyncRingtonePlayer pattern. PluriWaveAlarmService is now the SOLE ring-audio owner for the entire ring on STREAM_ALARM; the Flutter ringing screen is pure UI. Two REMOVED requirements (ring-scoped device-volume override, single fade-in driver across handoff) and five ADDED requirements (sole native ownership, exponential dB fade-in ceiling, manual transient focus with no system volume writes, notification channel migration v2->v3, ring screen is pure UI) were merged into openspec/specs/native-alarms/spec.md, which already existed as a domain (created by the prior alarm-volume-ramp-restore change). The Purpose paragraph was rewritten to describe the post-change architecture; this is the only authored (non-verbatim) text in the merged main spec. CRITICAL-1 (fire notification channel not actually silent) was found by sdd-verify: WU2 deleted the old setSound(DEFAULT_ALARM_ALERT_URI, ...) call but never added the setSound(null, null) replacement that design ADR D4 explicitly specifies. Root cause traced through the whole pipeline to tasks.md task 2.7's own flawed phrasing ("no setSound call = silent"), which both apply-progress and the code inherited unquestioned -- the design itself (design.md) was correct throughout. Fixed post-verify by the orchestrator via commit 3f0267f (pushed as 6f07e27): one-line addition, no other code affected. Independently re-confirmed present in the codebase during this archive pass (line 691, PluriWaveAlarmService.kt, inside ensureChannel()). WARNING-1 (Phase 3 QA checklist gaps: no real v2->v3 device-upgrade migration test, no dumpsys audio focus-abandon check, even though the spec names both as valid testability methods) was CLOSED post-verify by adding tasks 3.10 and 3.11 to tasks.md's Phase 3 checklist. This addition is present in the on-disk tasks.md (copied into this archive, authoritative) but NOT reflected in engram observation #2391, which predates the addition -- documented here and in archive-report.md for the audit trail. This is the mirror-image of the alarm-volume-ramp-restore precedent (there, a post-verify fix was code-only and NOT folded back into tasks.md at all; here, the post-verify closure WAS folded into tasks.md but the engram observation was not re-saved to match). SUGGESTIONS (3, all accepted-documented, non-blocking): (1) three l10n getters (alarmRingingFallbackActive/TryingStation/PreparingFallback) are now dead code across all 13 arb-generated files, expected/harmless per design D8. (2) no JVM/Kotlin unit-test harness exists in this project, so computeFadeVolume -- the one pure, exactly-specified function this change introduces -- has zero automated coverage; repo-wide gap, pre-dates this change. (3) stopAlarm()'s actual teardown order (release wake lock before abandon audio focus) differs from design.md Sec.2's ASCII diagram (which lists focus-abandon first); no ADR pins the order, no functional dependency found, documentation-accuracy nitpick only. Phase 3 (final sweep + mandatory on-device QA, 11 tasks 3.1-3.11) is the ONLY remaining work before this change is considered fully verified end-to-end. It cannot be completed by any agent and requires a real device (e.g. POCO X7 Pro). Task 3.6 (no second audible source, fire notification posts silently) and 3.10 (real v2->v3 migration) are the on-device confirmation of the now-fixed CRITICAL-1. Follow-up change planned: oem-reliability-guidance (in-app permission-status surface, MIUI/OEM autostart guidance + deep link, receiver-level PARTIAL_WAKE_LOCK) -- explicitly out of scope for this change per the proposal, not a prerequisite, independently plannable. ARCHIVE TOOLING NOTE: the sdd-archive executor for this change had no Bash/shell tool available (Read/Edit/Write/Glob/mem_* only) and could not run a filesystem copy command or delete the source folder. All six on-disk artifacts (explore.md, proposal.md, design.md, tasks.md, verify-report.md, specs/native-alarms/spec.md) were reconstructed into this archive folder via Read-verified Write calls, then independently re-verified line-by-line (final line number and final-line content compared between freshly re-read source and freshly re-read archive copy for all 6 files -- all matched exactly). Per this archive run's explicit instructions, the orchestrator (which has shell access) will delete openspec/changes/native-alarm-ring/ and diff-verify the two folders afterward -- this was the intended division of labor for this run, not an unplanned limitation.