# Chanora SWE.4 Software Unit Verification Plan **Document type:** Software Unit Verification Plan **Process alignment:** ASPICE SWE.4 Software Unit Verification **Version:** 0.9.14 **Status:** Baseline Candidate **Language:** English **Product:** Chanora **Verification object:** Software units defined by SDD **Direct source layer:** SDD only **Repo path:** `docs/verification/swe4-unit-verification-plan.md` --- ## 1. Purpose This document defines the software unit verification strategy for Chanora. It verifies that software units implement the Software Detailed Design. This document is downstream of SDD and shall not bypass the document hierarchy. ```text SysRS -> SysDes -> SRS -> SAD -> SDD -> SWE.4 Unit Verification ``` Direct source rule: ```text SWE.4 unit verification items shall link directly to SDD only. ``` ## 2. Verification Scope In scope: - Flutter unit tests - Flutter widget-level unit verification where a widget is treated as a software unit - Dart static analysis - Dart code review - Rust unit tests - Rust static analysis - Rust code review - Unit-level regression verification - Unit-level interface boundary tests - Unit-level localization, Unicode, design-token, and diagnostics verification Out of scope: - Software integration verification across components; handled by SWE.5. - Fully integrated software verification against SRS; handled by SWE.6. - System integration verification against SysDes; handled by SYS.4. ## 3. Unit Verification Strategy | Verification type | Applies to | Purpose | |---|---|---| | Static analysis | Dart, Rust | Detect structural, lint, safety, style, and maintainability issues | | Code review | Dart, Rust, build scripts | Confirm design compliance and maintainability | | Unit tests | Dart, Rust | Verify individual units against SDD behavior | | Widget tests | Flutter widgets | Verify component rendering, semantics, and state behavior | | Golden tests | Design-system components | Verify stable UI rendering where appropriate | | Localization tests | Localization service and accessibility labels | Verify fallback, keys, and localized display strings | | Unicode tests | Protocol/bridge/text-boundary units | Verify UTF-8 and multilingual content handling | | Regression tests | Changed units | Confirm unchanged behavior remains valid after modifications | ## 4. Entry Criteria | Criterion | Description | |---|---| | SDD baseline available | Unit design items and source SAD links are available. | | Unit implementation available | The unit exists in source code or executable test double form. | | Unit test environment available | Flutter and/or Rust test infrastructure is configured. | | Verification measure defined | Test, review, or static analysis objective is defined. | | Pass/fail criteria defined | Expected result is objective and reviewable. | ## 5. Exit Criteria | Criterion | Description | |---|---| | Selected unit verification measures executed | Tests, reviews, and analyses required for the release scope are complete. | | Results recorded | Verification results are stored in test reports or review records. | | Nonconformances recorded | Failures are recorded for problem resolution. | | Traceability complete | Each unit verification item traces to SDD and result evidence. | | Regression scope complete | Changed units have selected regression measures executed. | ## 6. Unit Verification Measures **SWE4-UV-001**: Verify `ChanoraApp` initialization order. - Source SDD: SDD-001, SDD-045 - Verification method: Flutter unit/integration test - Pass criteria: Theme, localization, platform services, routing, and adaptive shell initialize before feature rendering. - Evidence: Test result **SWE4-UV-002**: Verify `ChanoraThemeFactory` Material 3 theme creation. - Source SDD: SDD-002, SDD-003 - Verification method: Dart unit test - Pass criteria: Light and dark Material 3 ThemeData objects are created with valid ColorScheme and TextTheme values. - Evidence: Test result **SWE4-UV-003**: Verify `ChanoraSemanticColors` connection token behavior. - Source SDD: SDD-004, SDD-006 - Verification method: Dart unit test - Pass criteria: All connection semantic roles are present and do not require feature-screen hardcoding. - Evidence: Test result **SWE4-UV-004**: Verify voice semantic token behavior. - Source SDD: SDD-005, SDD-006 - Verification method: Dart unit test - Pass criteria: Speaking, muted, deafened, and push-to-talk active states are available through semantic tokens. - Evidence: Test result **SWE4-UV-005**: Verify feature widgets use theme accessors rather than hardcoded semantic values. - Source SDD: SDD-010 - Verification method: Static inspection - Pass criteria: Feature widgets do not construct product semantic token values directly. - Evidence: Review record **SWE4-UV-006**: Verify adaptive shell window classification. - Source SDD: SDD-011, SDD-012 - Verification method: Dart unit test - Pass criteria: Compact, medium, and expanded classes are selected deterministically. - Evidence: Test result **SWE4-UV-007**: Verify `CompactShell` layout behavior. - Source SDD: SDD-013 - Verification method: Flutter widget test - Pass criteria: Compact shell renders a single-column layout and mobile navigation entry points. - Evidence: Test result **SWE4-UV-008**: Verify `MediumShell` layout behavior. - Source SDD: SDD-014 - Verification method: Flutter widget test - Pass criteria: Medium shell renders side navigation or navigation rail behavior. - Evidence: Test result **SWE4-UV-009**: Verify `ExpandedShell` persistent pane behavior. - Source SDD: SDD-015 - Verification method: Flutter widget test - Pass criteria: Expanded shell renders persistent side pane and VoiceBar slot. - Evidence: Test result **SWE4-UV-010**: Verify connection status presentation uses non-color-only cues. - Source SDD: SDD-016, SDD-022 - Verification method: Dart unit test, widget test - Pass criteria: The presenter exposes label, icon, semantic label, and severity token. - Evidence: Test result **SWE4-UV-011**: Verify `ChanoraVoiceBar` exposed properties. - Source SDD: SDD-017, SDD-018 - Verification method: Flutter widget test - Pass criteria: Mute, deaf, push-to-talk, input meter, current channel, and latency properties render correctly. - Evidence: Test result **SWE4-UV-012**: Verify `ChanoraChannelTree` data and interaction behavior. - Source SDD: SDD-019, SDD-020 - Verification method: Flutter widget test - Pass criteria: Channel hierarchy, selected state, expansion state, join intent, and context-menu intent operate as designed. - Evidence: Test result **SWE4-UV-013**: Verify `ChanoraClientTile` state semantics. - Source SDD: SDD-021 - Verification method: Widget test, accessibility test - Pass criteria: Client status is available through text/icon/semantic cues and not color alone. - Evidence: Test result **SWE4-UV-014**: Verify localized semantic labels for icon-only buttons. - Source SDD: SDD-024, SDD-031, SDD-032 - Verification method: Accessibility test, localization unit test - Pass criteria: Icon-only controls expose localized semantic labels with fallback. - Evidence: Test result **SWE4-UV-015**: Verify keyboard focus traversal. - Source SDD: SDD-025 - Verification method: Widget test - Pass criteria: Primary interactive controls can be traversed in a logical order. - Evidence: Test result **SWE4-UV-016**: Verify text-scale resilience of critical controls. - Source SDD: SDD-026 - Verification method: Accessibility widget test - Pass criteria: Critical controls remain reachable under increased text scale. - Evidence: Test result **SWE4-UV-017**: Verify platform inset service unit behavior. - Source SDD: SDD-027, SDD-030 - Verification method: Unit test with platform test doubles - Pass criteria: Insets are normalized and exposed to the shell. - Evidence: Test result **SWE4-UV-018**: Verify back intent service behavior. - Source SDD: SDD-028 - Verification method: Unit test with platform test doubles - Pass criteria: Platform back events map to expected route-level intents. - Evidence: Test result **SWE4-UV-019**: Verify localization fallback. - Source SDD: SDD-031, SDD-032, SDD-033 - Verification method: Unit test - Pass criteria: Missing localized strings fall back deterministically. - Evidence: Test result **SWE4-UV-020**: Verify server-content pass-through. - Source SDD: SDD-034 - Verification method: Unit test - Pass criteria: Server-provided content is not translated by product localization. - Evidence: Test result **SWE4-UV-021**: Verify Unicode text boundary behavior. - Source SDD: SDD-035, SDD-036, SDD-037 - Verification method: Unit test - Pass criteria: Valid multilingual Unicode content is preserved; invalid external encodings are handled at boundaries. - Evidence: Test result **SWE4-UV-022**: Verify diagnostic Unicode preservation and redaction behavior. - Source SDD: SDD-038, SDD-041, SDD-050, SDD-054 - Verification method: Unit test, security review - Pass criteria: Secrets are redacted while multilingual content is preserved. - Evidence: Test result, review record **SWE4-UV-023**: Verify locale-aware formatting. - Source SDD: SDD-040 - Verification method: Unit test - Pass criteria: Dates, times, numbers, and timestamps format through localization utilities. - Evidence: Test result **SWE4-UV-024**: Verify traceability checker behavior. - Source SDD: SDD-043, SDD-044, SDD-055, SDD-056, SDD-066, SDD-067 - Verification method: Unit test / script test - Pass criteria: Invalid direct-layer references are detected. - Evidence: Test result **SWE4-UV-025**: Verify bridge DTO safety. - Source SDD: SDD-046 - Verification method: Unit test, static inspection - Pass criteria: Bridge DTOs do not expose internal Rust implementation types. - Evidence: Test result, review record **SWE4-UV-026**: Verify Rust core event mapping. - Source SDD: SDD-047 - Verification method: Rust unit test - Pass criteria: Core events map deterministically to view model deltas. - Evidence: Test result **SWE4-UV-027**: Verify voice view model separation from DSP. - Source SDD: SDD-048 - Verification method: Code review, unit test - Pass criteria: Voice UI receives status values and does not perform audio DSP. - Evidence: Review record, test result **SWE4-UV-028**: Verify storage facade isolation. - Source SDD: SDD-049 - Verification method: Static inspection, unit test - Pass criteria: Feature widgets do not directly call database APIs. - Evidence: Review record, test result **SWE4-UV-029**: Verify interface detail catalog completeness. - Source SDD: SDD-059, SDD-060 - Verification method: Review - Pass criteria: Unit-level interface entries include required details where applicable. - Evidence: Review record **SWE4-UV-030**: Verify unit construction and review records. - Source SDD: SDD-064, SDD-065, SDD-068, SDD-069, SDD-070 - Verification method: Review - Pass criteria: Unit construction, review, verification handoff, and registry records exist for release scope units. - Evidence: Review record ## 7. Traceability Matrix | SDD Range | SWE.4 Coverage | |---|---| | SDD-001 through SDD-010 | SWE4-UV-001 through SWE4-UV-005 | | SDD-011 through SDD-018 | SWE4-UV-006 through SWE4-UV-011 | | SDD-019 through SDD-026 | SWE4-UV-012 through SWE4-UV-016 | | SDD-027 through SDD-037 | SWE4-UV-017 through SWE4-UV-021 | | SDD-038 through SDD-050 | SWE4-UV-022 through SWE4-UV-028 | | SDD-051 through SDD-070 | SWE4-UV-029 through SWE4-UV-030 | ## 8. Result Reporting Unit verification results shall be summarized in a unit verification summary report including: - verification scope - selected verification measures - skipped measures and rationale - pass/fail result - nonconformances - regression scope - residual risks - release recommendation ## 9. Change History | Version | Date | Description | |---|---|---| | 0.1.0 | 2026-05-14 | Initial SWE.4 unit verification plan derived from SDD v0.3. | --- ## 10. Platform Decision Unit Verification Addendum **SWE4-UV-031**: Verify iOS and Android build configuration units. - Source SDD: SDD-071, SDD-072, SDD-073 - Verification method: Static inspection, platform test - Pass criteria: iOS minimum runtime, Apple SDK gate, Android minimum runtime, and Android target SDK configuration are inspectable and match release policy. - Evidence: Test result, release inspection **SWE4-UV-032**: Verify single active connection enforcement. - Source SDD: SDD-074 - Verification method: Unit test - Pass criteria: Attempting to create a second active MVP connection is rejected or routed through a controlled disconnect/switch policy. - Evidence: Test result **SWE4-UV-033**: Verify audio processing defaults and backend selection. - Source SDD: SDD-075, SDD-076 - Verification method: Unit test, audio test - Pass criteria: AEC, AGC, Noise Suppression, and High-Pass Filter default to enabled where supported and stable; backend selector prefers platform-native processing. - Evidence: Test result **SWE4-UV-034**: Verify local database, secret storage, bridge, and diagnostics privacy gate units. - Source SDD: SDD-077, SDD-078, SDD-079, SDD-080 - Verification method: Unit test, security inspection - Pass criteria: Non-secret storage, secret storage, typed bridge DTOs, and disabled automatic upload/crash behavior match detailed design. - Evidence: Test result, security review **SWE4-UV-035**: Verify `DesktopPttBackend` trait + `PttCapabilityLevel` enum + `FocusedPttBackend` units. - Source SDD: SDD-081, SDD-082, SDD-087 - Verification method: Unit test - Pass criteria: Trait surface compiles for every implementation; enum `as_str()` mapping is unambiguous; `FocusedPttBackend` reports `L0Focused` and forwards `set_ptt` events into `AudioTransmitGate` unchanged. - Evidence: Test result **SWE4-UV-036**: Verify Windows / macOS / Linux platform backend units in isolation. - Source SDD: SDD-083, SDD-084, SDD-085, SDD-086 - Verification method: Unit test (with mocked OS surfaces), Platform Test (Windows / macOS / GNOME-Wayland reference hosts) - Pass criteria: Each backend reports the expected `PttCapabilityLevel` for the current host configuration; the ladder falls through to `FocusedPttBackend` when its preferred OS API is unavailable. - Evidence: Test result, platform-test trace **SWE4-UV-037**: Verify `PttController` + `AudioTransmitGate` units. - Source SDD: SDD-088, SDD-089 - Verification method: Unit test - Pass criteria: `PttController::set_binding` rebinds the active backend without dropping `AudioTransmitGate`; `AudioTransmitGate::subscribe()` returns a `watch::Receiver` that delivers every transition the gate observes. - Evidence: Test result **SWE4-UV-038**: Verify `PttSanitizer` and `PttCapabilityBadge` units. - Source SDD: SDD-090, SDD-091 - Verification method: Unit test, UI review - Pass criteria: `PttSanitizer` drops records whose field names match the banned list (`key_code`, `scan_code`, `virtual_key`, `vk`, `keysym`, `keysym_string`, `key_sequence`); `PttCapabilityBadge` renders the correct label and explanation sheet for each `PttCapabilityLevel`. - Evidence: Test result, UI screenshot **SWE4-UV-039**: Verify `MissedKeyUpWatchdog` unit. - Source SDD: SDD-092 - Verification method: Unit test (tokio time-paused) - Pass criteria: After a simulated `false -> true -> (timeout elapsed)` sequence the watchdog calls `AudioTransmitGate::set(false)` exactly once and emits a sanitised diagnostic record naming only `capability_level` and `backend_id`. - Evidence: Test result | SDD Range | SWE.4 Coverage | |---|---| | SDD-071 through SDD-080 | SWE4-UV-031 through SWE4-UV-034 | | SDD-081 through SDD-092 | SWE4-UV-035 through SWE4-UV-039 | ## Baseline Candidate 0.9.1 Update | Version | Date | Description | |---|---|---| | 0.9.1 | 2026-05-14 | Updated baseline after product decision closure: Apple App Store SDK gate uses Xcode 26+ and iOS 26 / iPadOS 26 SDK+ since 2026-04-28, platform baselines and decision traceability propagated across the document set. | ## Baseline Candidate 0.9.2 Update | Version | Date | Description | |---|---|---| | 0.9.2 | 2026-05-14 | Corrected Apple App Store Connect upload gate to 2026-04-28 and checked full-package naming, references, and coverage. | ## Baseline Candidate 0.9.3 Update | Version | Date | Description | |---|---|---| | 0.9.3 | 2026-05-15 | Added desktop PTT unit-verification items SWE4-UV-035 through SWE4-UV-039: `DesktopPttBackend` trait + `PttCapabilityLevel`, platform backends, `PttController` + `AudioTransmitGate`, `PttSanitizer` + `PttCapabilityBadge`, `MissedKeyUpWatchdog`. | ## 11. Android P0 Unit Verification Addendum **SWE4-UV-040**: Verify Android build configuration unit (`SDD-073` expanded). - Source SDD: SDD-073 - Verification method: Gradle task assertion + static inspection of `android/app/build.gradle.kts` - Pass criteria: `minSdk` literal equals `28` (DEC-004); `ndk.abiFilters` set equals `{arm64-v8a, armeabi-v7a, x86_64}` (per SDD-073 item 4 and SDD-118 item 3, `x86` 32-bit is explicitly out of scope and shall not be in the set); release `signingConfig` references the CI signing key reference (not debug); R8/ProGuard `minifyEnabled = true` on release; `bundle { abi.enableSplit = true }`; assemble target produces an AAB artifact at `app/build/outputs/bundle/release/app-release.aab`. - Evidence: Gradle log + manifest dump **SWE4-UV-041**: Verify `AndroidPermissionRequester` state machine (`SDD-106`). - Source SDD: SDD-106 - Source SRS: SRS-209 - Verification method: Dart/Kotlin unit test with a permission-platform test double - Pass criteria: State transitions are exhaustive for `{granted, denied, permanently_denied, revoked_mid_session}`; transitioning out of `granted` clamps `AudioTransmitGate::set(false)`; re-entering `granted` does NOT auto-transmit (requires explicit user gesture); permanently-denied surfaces a settings-deep-link intent rather than re-prompting. - Evidence: Test result **SWE4-UV-042**: Verify `BackIntentService` Android branches (`SDD-028` expanded). - Source SDD: SDD-028 - Source SRS: SRS-163 - Verification method: Dart unit test with platform-channel test double for both `OnBackInvokedCallback` (API 33+) and `OnBackPressedDispatcher` (API ≤ 32) paths. - Pass criteria: Modal-first rule — if a modal is open, back closes the modal and does not pop the route. PTT-active-ignore — while `transmit_active == true` the back event is consumed without effect. Route-pop ordering — otherwise the topmost non-modal route pops. The API 33+ branch registers a `OnBackInvokedCallback` at `PRIORITY_DEFAULT`; the pre-33 branch registers an `OnBackPressedCallback`. Switching API level in the test double switches the active branch deterministically. - Evidence: Test result **SWE4-UV-043**: Verify `AndroidJniBootstrap` library load and init ordering (`SDD-105`). - Source SDD: SDD-105 - Verification method: Instrumented unit test on Android (or Robolectric where applicable) - Pass criteria: `System.loadLibrary("chanora_bridge")` is invoked from the `Application` subclass `onCreate` (not from an Activity); `JNI_OnLoad` runs exactly once per process and captures the `JavaVM*`; bridge init occurs before any FFI call from Dart; double-init is a no-op. - Evidence: Test result + logcat trace **SWE4-UV-044**: Verify `AndroidVoiceForegroundService` lifecycle unit (`SDD-107`). - Source SDD: SDD-107 - Source SRS: SRS-111 - Verification method: Kotlin unit test + Robolectric `ServiceController` - Pass criteria: `startForeground` is called within 5 s of `onStartCommand` (API 26+ requirement); notification channel exists with `IMPORTANCE_LOW`; `foregroundServiceType` includes `microphone` on API 30+; service stops cleanly on disconnect intent and does not leak its wakelock; restart policy is `START_NOT_STICKY` (no auto-respawn after force-stop). - Evidence: Test result **SWE4-UV-045**: Verify `AndroidAudioModeController` snapshot/restore + refcount (`SDD-108`). - Source SDD: SDD-108 - Source SRS: SRS-208 - Source SysRS: SysRS-305 - Verification method: Kotlin unit test with `AudioManager` test double - Pass criteria: First acquire snapshots prior `AudioManager.getMode()` and sets `MODE_IN_COMMUNICATION`; nested acquires increment refcount without re-snapshotting; matched release decrements; final release restores the snapshotted prior mode exactly once; when `AudioManager` is unavailable (e.g. injected null), controller logs a sanitized warning and degrades to no-op without throwing. - Evidence: Test result **SWE4-UV-046**: Verify `AndroidPttCapability` reports `L0Focused` and pins `FocusedPttBackend` (`SDD-110`). - Source SDD: SDD-110 - Verification method: Rust + Dart unit test - Pass criteria: On `target_os = "android"` the `DesktopPttBackend` factory returns `FocusedPttBackend` unconditionally (no ladder evaluation); `PttCapabilityBadge` renders the localized `L0Focused` label with the Android-specific explanation string; no Android branch attempts to bind global hotkeys. - Evidence: Test result + UI screenshot | SDD Range | SWE.4 Coverage | |---|---| | SDD-028 (expanded) | SWE4-UV-042 | | SDD-073 (refreshed) | SWE4-UV-040 | | SDD-105 | SWE4-UV-043 | | SDD-106 | SWE4-UV-041 | | SDD-107 | SWE4-UV-044 | | SDD-108 | SWE4-UV-045 | | SDD-110 | SWE4-UV-046 | ### Android voice audio backend unit-verification items (SDD-111..SDD-116 wave) **SWE4-UV-047**: Verify `AndroidVoiceStreamConfig` builder records requested vs. achieved fields. - Source SDD: SDD-112 (config struct), SDD-111 (trait surface) - Source SRS: SRS-210, SRS-211, SRS-213, SRS-214 - Source SAD: SAD-077, SAD-081 - Verification method: Rust unit test with a fake Oboe builder return path (no device) - Pass criteria: Given a `MobileVoiceStreamConfig` requesting `PERFORMANCE_MODE_LOW_LATENCY`, input preset `VoiceCommunication`, output usage `VoiceCommunication`, content type `Speech`, and sharing mode `Exclusive`, the resulting `AndroidVoiceStreamConfig` records the requested values verbatim AND exposes `achieved_*` accessors populated from the fake builder's grant values. Mismatch between requested and achieved is observable via the accessors with no panics. Both input and output stream configs are independently recorded. - Evidence: Rust unit test result - SDD-116 matrix row satisfied: none directly (unit-level; matrix consumes the accessors per-device) **SWE4-UV-048**: Verify input preset fallback ladder is observable at each step. - Source SDD: SDD-111 (trait surface, open() error pathway), SDD-112 (preset field) - Source SRS: SRS-211 - Source SAD: SAD-077 - Verification method: Rust unit test with a scripted Oboe builder mock that returns `ErrorIllegalArgument` for successive presets - Pass criteria: With the mock denying `VoiceCommunication`, `open()` retries with `VoicePerformance`; with the mock denying both, `open()` retries with `Generic` (`Unprocessed`/default). Each retry is recorded in a structured field (e.g. `attempted_presets: Vec`) and the final `achieved_input_preset()` returns the preset that was granted. If all presets fail, `open()` returns `BackendError::InputPresetUnavailable` (or the SDD-111 equivalent). No silent fallback. - Evidence: Rust unit test result - SDD-116 matrix row satisfied: none directly (matrix records `achieved_input_preset` per device) **SWE4-UV-049**: Verify sharing-mode fallback Exclusive→Shared is observable. - Source SDD: SDD-111, SDD-112 (sharing mode field) - Source SRS: SRS-214 - Source SAD: SAD-077 - Verification method: Rust unit test with a fake Oboe builder return path - Pass criteria: When the fake builder accepts `SharingMode::Exclusive`, `achieved_sharing_mode()` returns `Exclusive` and no retry occurs. When the fake builder rejects `Exclusive` (returns the documented Oboe error path for exclusive denial), the unit retries with `Shared`, and `achieved_sharing_mode()` returns `Shared`. The original request (`Exclusive`) is still recorded for diagnostics. - Evidence: Rust unit test result - SDD-116 matrix row satisfied: none directly (matrix records `achieved_sharing_mode` per device) **SWE4-UV-050**: Verify hardware effects per-effect success/failure logic with software-AEC fallback. - Source SDD: SDD-113 (per-effect construction + software fallback signal) - Source SRS: SRS-212 - Source SAD: SAD-077, SAD-081 - Verification method: Rust unit test with a mocked JNI surface (`new_object`-style indirection) representing `AcousticEchoCanceler.create`, `NoiseSuppressor.create`, `AutomaticGainControl.create` - Pass criteria: For each of AEC, NS, AGC: (a) success path — mock returns a non-null `GlobalRef`, effect is recorded as engaged, `setEnabled(true)` is invoked once; (b) failure path — mock returns null OR throws, the unit records the per-effect failure, does NOT abort the other two, and signals the engine to engage the software equivalent (per SDD-113 item 5 — for AEC failure the engine's software AEC must be flagged on). Order of effect construction does not affect outcome (no cross-effect coupling). `release()` is called on every engaged `GlobalRef` exactly once when the unit is torn down. - Evidence: Rust unit test result - SDD-116 matrix row satisfied: per-device AEC/NS/AGC availability column **SWE4-UV-051**: Verify performance-mode achieved recording feeds SRS-210 latency tier classification. - Source SDD: SDD-111 (`achieved_performance_mode`), SDD-112 (mode field) - Source SRS: SRS-210 - Source SAD: SAD-077 - Verification method: Rust unit test - Pass criteria: When the fake builder grants `PERFORMANCE_MODE_LOW_LATENCY`, `achieved_performance_mode()` returns `LowLatency` and the SRS-210 tier classifier (the unit-level pure function that maps achieved mode → latency target) returns the 150 ms tier. When the fake builder grants `PERFORMANCE_MODE_NONE` or `POWER_SAVING`, the classifier returns the 250 ms tier. The classifier is a pure function reachable from the engine without a device. - Evidence: Rust unit test result - SDD-116 matrix row satisfied: per-device `achieved_performance_mode` column **SWE4-UV-052**: Verify output stream usage and content type are set correctly. - Source SDD: SDD-112 (output config fields) - Source SRS: SRS-213 - Source SAD: SAD-077 - Verification method: Rust unit test inspecting the builder calls captured by a mock Oboe builder - Pass criteria: The output stream-construction path invokes `setUsage(VoiceCommunication)` and `setContentType(Speech)` exactly once on the builder before `openStream`. No other usage / content-type combination is reachable from the production path (the test asserts there is no code path that constructs the output stream with `Media` / `Music` defaults). `achieved_output_usage()` returns `VoiceCommunication` and `achieved_output_content_type()` returns `Speech` on a successful open. - Evidence: Rust unit test result - SDD-116 matrix row satisfied: per-device `achieved_output_usage` / `achieved_output_content_type` column | SDD Range | SWE.4 Coverage | |---|---| | SDD-111 | SWE4-UV-047, SWE4-UV-048, SWE4-UV-049, SWE4-UV-051 | | SDD-112 | SWE4-UV-047, SWE4-UV-048, SWE4-UV-049, SWE4-UV-051, SWE4-UV-052 | | SDD-113 | SWE4-UV-050 | | SDD-115 | (lifecycle sequencing — see SWE.5 integration items) | | SDD-116 | (device matrix — see SWE.6 + android-p0-acceptance TC-14..TC-18) | ## Baseline Candidate 0.9.4 Update | Version | Date | Description | |---|---|---| | 0.9.4 | 2026-05-18 | Added Android P0 unit-verification items SWE4-UV-040 through SWE4-UV-046 covering SDD-028 (expanded back-intent branches), SDD-073 (refreshed build config + AAB), SDD-105 (JNI bootstrap), SDD-106 (permission state machine + transmit clamp), SDD-107 (foreground service lifecycle), SDD-108 (audio mode controller refcount + restore), SDD-110 (PTT capability pin). | | 0.9.5 | 2026-05-18 | Added Android voice audio backend unit-verification items SWE4-UV-047 through SWE4-UV-052 covering SDD-111 (trait surface), SDD-112 (config requested vs achieved), SDD-113 (per-effect hardware engagement + software fallback) and feeding SRS-210/211/213/214 unit-level classification. | | 0.9.14 | 2026-05-18 | Wave 3 reviewer follow-up: allocated real SWE.4 IDs for two test sets that had been cited under provisional `SWE4-UV-NNN` placeholders. SWE4-UV-053..055 anchor the three `TransmitModeSelector` permission-state clamp tests in `crates/chanora_audio/src/transmit_selector.rs` (commit 635d160 was cited under the "SWE4-UV-026 family" without real anchors). SWE4-UV-056..057 anchor the two missing `DiagnosticExport::with_android_audio` rendering tests in `crates/chanora_diagnostics/src/lib.rs` (commit aea50a1 introduced the field/builder/`to_text` branch but the unit-test pair was queued for the commit-8 amend). Closes the Wave 3 traceability gap; downstream test cites in commits 4 and 8 are amended to reference these IDs. | ## 12. Android Permission Clamp + Diagnostics Android-Audio Unit Verification Addendum (Wave 3 — v0.9.14) **Background.** Wave 3 reviewer audit flagged two newly-landed test groups whose source comments cited verification IDs as `SWE4-UV-NNN` placeholders rather than real allocated anchors: 1. Three `TransmitModeSelector` permission-state tests at `crates/chanora_audio/src/transmit_selector.rs:343-435` (introduced by commit 635d160). The reviewer noted at `transmit_selector.rs:343` that these tests cite "SWE4-UV-026 family" without real IDs. 2. Two missing unit tests for the new `chanora_diagnostics` Android-audio surface (`android_audio: Option` field, `with_android_audio` builder, `[audio.android]` `to_text` branch) introduced by commit aea50a1; queued for the commit-8 amend. This addendum allocates the five required anchors. SWE4-UV-052 was the prior high-water mark; SWE4-UV-053..057 are the next free contiguous range. **SWE4-UV-053**: Verify `TransmitModeSelector` clamps transmit to `false` when `permission_state == Denied` (or `PermanentlyDenied`/`Unknown`) regardless of PTT, channel, or transmit-mode state. - Source SDD: SDD-106 §6 - Source SRS: SRS-209 (fail-safe listen-only default) - Verification method: Rust unit test - Test code path: `crates/chanora_audio/src/transmit_selector.rs::tests::permission_state_denied_clamps_transmit_to_false` (lines 348-384) - Pass criteria: With `TransmitMode::Ptt`, `in_channel = true`, `ptt_held = true` and the default `Granted` permission state the gate evaluates `true`. Publishing `PermissionGate::Denied` flips the gate to `false`. `PermanentlyDenied` and `Unknown` likewise clamp `false`. The clamp wins over `TransmitMode::Continuous`. - Evidence: `cargo test -p chanora_audio` result - Notes: Establishes the fail-safe semantics: cold-launch `Unknown` is listen-only per SRS-209. **SWE4-UV-054**: Verify `TransmitModeSelector` releases the permission clamp on transition back to `Granted` and resumes normal PTT-driven evaluation. - Source SDD: SDD-106 §6 - Source SRS: SRS-209 - Verification method: Rust unit test - Test code path: `crates/chanora_audio/src/transmit_selector.rs::tests::permission_state_granted_releases_clamp` (lines 389-409) - Pass criteria: After `Denied` clamps the gate to `false`, transitioning to `PermissionGate::Granted` (with PTT held + in channel) restores the gate to `true` on the next state tick. Releasing the PTT key then drops the gate per normal PTT semantics — the clamp is no longer in effect. - Evidence: `cargo test -p chanora_audio` result - Notes: Pairs with SWE4-UV-053; together they cover the clamp on/off edges. **SWE4-UV-055**: Verify `TransmitModeSelector` ignores `PermissionState` events for non-`RECORD_AUDIO` permissions (contract: bridge filters before reaching the selector). - Source SDD: SDD-106 §5 - Verification method: Rust unit test (contract pin) - Test code path: `crates/chanora_audio/src/transmit_selector.rs::tests::permission_state_for_other_permission_does_not_clamp` (lines 418-435) - Pass criteria: The selector exposes no setter for non-`RECORD_AUDIO` permissions. With `TransmitMode::Continuous` + `in_channel = true` and no call to `set_permission_state`, the selector remains in its `Granted` default and the gate evaluates `true`. Demonstrates the contract that unrelated permission events (e.g. `POST_NOTIFICATIONS`) cannot reach this code path. - Evidence: `cargo test -p chanora_audio` result - Notes: This is a negative/contract test; the JNI bridge is responsible for filtering by permission name before invoking `set_permission_state`. **SWE4-UV-056**: Verify `DiagnosticExport::with_android_audio(Some(yaml))` renders the `[audio.android]` section between `[metadata]` and `[recent logs]` in `to_text()`. - Source SDD: SDD-116 item 3 (diagnostics matrix surface), SDD-112 item 10 / SDD-113 item 7 (producing crate) - Verification method: Rust unit test - Test code path: `crates/chanora_diagnostics/src/lib.rs::tests::android_audio_renders_between_metadata_and_logs` (to be added by commit-8 amend) - Pass criteria: Building a `DiagnosticExport::from_sink(...)` and chaining `.with_android_audio(Some("perf: low_latency\n".into()))` produces a `to_text()` output where the substring `[audio.android]` appears (a) after the `[metadata]` header, (b) before the `[recent logs]` header, and (c) is immediately followed by the supplied YAML fragment verbatim. The YAML fragment is not re-redacted by the diagnostics bundle (SDD-090 places sanitisation in the producing crate). - Evidence: `cargo test -p chanora_diagnostics` result - Notes: Section ordering is part of the SDD-116 matrix contract; downstream tooling parses by header. **SWE4-UV-057**: Verify `DiagnosticExport` with default `android_audio = None` omits the `[audio.android]` header entirely (negative test). - Source SDD: SDD-116 item 3 (negative case — non-Android or pre-session) - Verification method: Rust unit test - Test code path: `crates/chanora_diagnostics/src/lib.rs::tests::android_audio_absent_omits_section` (to be added by commit-8 amend) - Pass criteria: A `DiagnosticExport::from_sink(...)` constructed without `.with_android_audio(...)` (i.e. `android_audio == None`) produces a `to_text()` output that does **not** contain the substring `[audio.android]`. The `[metadata]` and `[recent logs]` sections remain present in order. Calling `.with_android_audio(None)` explicitly is equivalent (idempotent omission). - Evidence: `cargo test -p chanora_diagnostics` result - Notes: Pairs with SWE4-UV-056; together they cover the conditional-render branch in `DiagnosticExport::to_text`. | SDD Range | SWE.4 Coverage | |---|---| | SDD-106 §5 | SWE4-UV-055 | | SDD-106 §6 | SWE4-UV-053, SWE4-UV-054 | | SDD-116 item 3 | SWE4-UV-056, SWE4-UV-057 |