# Issue History Analysis **Date:** 2026-06-11 **Scope:** All git history, PRs, and issue patterns --- ## 1. Issue Categories ### iOS Audio (15+ issues) — Most Problematic Area | Commit | Issue | Root Cause | Fix | |--------|-------|------------|-----| | #42 (OPEN) | AVAudioSession not activated before connect | Auto-join spawns VPIO before session in playAndRecord mode | Activate session BEFORE rust.connect | | #41 | iOS Debug builds blocked | Debug.xcconfig missing `-u` flags; verify script checked wrong Mach-O | Mirror Release xcconfig; check correct dylib | | #38 | Audio session dead after "already in channel" | Server response 0x0302 treated as failure | Keep session active on already-in-channel | | #33 | App kills other apps' audio while idle | Held `.playAndRecord` from launch | Idle baseline now `.ambient`; escalate during calls | | #28 | False underrun counters when muted | `peak_i16 == 0` check didn't gate on muted state | Gate underrun on `!muted` | | #26 | Silero exports stripped in Xcode Archive | `ld -dead_strip` removed unreferenced symbols | `-exported_symbol` whitelist in xcconfigs | | #10 | Voice join stuck at "Connecting" | Audio startup blocking connect critical path | Move audio startup off connect path | **Pattern:** iOS AVAudioSession has 7+ interacting configuration dimensions. Each fix reveals the next layer. ### Realtime Thread Safety (5+ issues) | Commit | Issue | Root Cause | Fix | |--------|-------|------------|-----| | #20 | Android audio output stutter | Mutex contention in audio callback | Oboe config tuning + lock-free callback | | #27 | macOS audio event queue | Lock contention in render path | Lock-free ArrayQueue pattern | | engine.rs:39 | ~39 `unwrap()` calls on Mutex | Poisoned mutex will panic engine | Need `try_lock()` or `parking_lot::Mutex` | **Pattern:** Realtime audio callbacks must NEVER use `Mutex::lock()` — always `try_lock()` with silence fallback. ### Build Toolchain (4+ issues) | Commit | Issue | Root Cause | Fix | |--------|-------|------------|-----| | #41 | iOS Debug builds fail | Debug.xcconfig diverged from Release | Mirror Release settings in Debug | | #26 | Silero exports stripped | `ld -dead_strip` + install-time `strip` | `-exported_symbol` whitelist + `STRIP_STYLE = non-global` | | #37 | MSVC CRT mismatch | cmake linking wrong CRT | `cmake-msvc-release-crt.cmd` | **Pattern:** Always verify with `xcodebuild archive`, not just `flutter build`. ### Protocol Issues (3+ issues) | Commit | Issue | Root Cause | Fix | |--------|-------|------------|-----| | #16 | Speaking state incorrect for non-self clients | Client profiles not refreshed before mapping | Refresh non-self profiles | | #16 | Server-query clients missing | Missing protocol DTO fields | Add ping deviation through full stack | | #5 | UI crashes on unexpected state transitions | Missing null/mounted guards | Guard deferred side effects | **Pattern:** Every protocol command should surface errors to UI — fire-and-forget hides failures. --- ## 2. PR Development Patterns ### PR Summary (42 total, 34 merged, 8 closed) | Type | Count | Merged | |------|-------|--------| | Features | 14 | 10 | | Bug fixes | 12 | 12 | | Refactoring | 4 | 3 | | Documentation | 1 | 1 | | Build/Chore | 4 | 4 | | Performance | 1 | 1 | | Dependency | 1 | 0 | | Closed (superseded) | 5 | 0 | ### Most Active Areas | Area | PR Count | Notes | |------|----------|-------| | iOS Audio | 10+ | Most recurring issues | | macOS Audio | 5 | Lock-free architecture | | Voice/VAD | 6 | CoreML, ONNX, WebRTC | | Flutter UI | 8 | Event-driven, responsive | | Protocol/State | 5 | State reducers, events | ### Quality Patterns 1. **Self-review via "Oracle" agent** — catches real issues pre-merge 2. **Local CI mirroring** — GitHub Actions billing broken 3. **PR stacking** — need better branch management workflow 4. **Follow-up fix pattern** — PRs stay focused --- ## 3. Test Cases for Known Issues ### iOS Audio Session Lifecycle ```dart // Test: Session activates before connect test('voice_join activates AVAudioSession before starting voice', () async { // Verify session state transitions: ambient → playAndRecord → ambient }); // Test: Already-in-channel response keeps session active test('voice_join keeps session active on already-in-channel response', () async { // Mock server response code 0x0302 // Verify session remains in playAndRecord state }); // Test: Idle app doesn't kill other audio test('app uses ambient mode when not in voice channel', () async { // Verify session mode is .ambient + .mixWithOthers when idle }); ``` ### Realtime Thread Safety ```rust // Test: Audio callback doesn't panic on poisoned mutex #[test] fn audio_callback_survives_poisoned_mutex() { // Verify try_lock fallback produces silence, not panic } ``` ### Protocol Error Surfacing ```dart // Test: Server errors surface to UI test('server error messages are forwarded as UI events', () async { // Mock protocol error // Verify UI receives error event }); ``` ### Build Verification ```bash # Test: iOS Debug build succeeds xcodebuild -workspace ios/Runner.xcworkspace -scheme Runner -configuration Debug build # Test: iOS Archive build preserves Silero exports xcodebuild archive -workspace ios/Runner.xcworkspace -scheme Runner # Verify: nm -g archive.xcarchive/Products/Applications/Chanora.app/Chanora | grep silero ``` --- ## 4. Root Cause Patterns | Pattern | Frequency | Prevention | |---------|-----------|------------| | iOS AVAudioSession lifecycle | 8+ PRs | Document state machine, add integration tests | | Mutex on realtime threads | 5+ issues | Use `try_lock()` or `parking_lot::Mutex` | | Xcode Archive vs build divergence | 4+ issues | Always test with `xcodebuild archive` | | Silent protocol failures | 3+ issues | Surface all errors to UI | | Platform-specific build quirks | 5+ issues | CI on all target platforms | --- *Generated by git history analysis agents on 2026-06-11*