diff --git a/CHANGELOG.md b/CHANGELOG.md index c81b766..47569b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,435 +2,133 @@ All notable changes to Chanora will be documented in this file. -This project is expected to follow a Conventional Commits style workflow. +This project follows a Conventional Commits style workflow. -## [Unreleased] +## [v0.3.0] — Cross-platform voice client baseline + +The v0.3.0 milestone transitions Chanora from an internal-beta voice +prototype to a cross-platform baseline client with event-driven UI, +per-user audio controls, non-self client info parity, and CI-hardened +Android / iOS / macOS / Linux builds. ### Added -- Apple CoreML-backed Silero VAD is now the preferred Apple voice - activity detector when the private sibling `silero-coreml` SwiftPM - package is available; WebRTC VAD remains the runtime fallback. +- **Event-driven UI** replaces timer-based snapshot polling. Protocol + deltas (client join/leave/move/update, channel add/remove/update) + flow through a typed `ProtocolDelta` enum and update the Flutter UI + in real time. Channel switching is instant. +- **Per-user volume controls.** Each client in the snapshot gets an + independent volume slider persisted in the bridge layer. Avatar + badges show muted/deafened state. Volume adjustments take effect + immediately on the audio mix. +- **Non-self client info parity with Qint.** The Info tab now populates + connection metadata (name, description, created, last connected, + connections, transfer, ping deviation) for other clients via an + explicit `ClientProfileRefreshPlan` that fetches `connectioninfo` + and recent text messages with a bounded timeout. +- **Ping deviation in client profiles.** `ping_deviation_milliseconds` + propagated from protocol DTO through bridge API to Dart, with a + conditional l10n row in the client info sheet (en + zh). +- **Apple CoreML Silero VAD** as the preferred voice activity detector + on iOS / macOS when the private `silero-coreml` SwiftPM submodule is + available. WebRTC VAD remains the runtime fallback. +- **TeamSpeak address resolver** (`chanora_resolver`) for DNS SRV + lookups and `ts3server://` URI handling. +- **Per-ABI Android APK splitting.** `flutter build apk + --split-per-abi` produces separate arm64-v8a / armeabi-v7a / x86_64 + APKs instead of a single fat APK. +- **Cross-platform CI** (GitHub Actions): cargo check + test, cargo + deny, cargo about license inventory, flutter analyze, flutter test, + flutter iOS unsigned release build. All gates must pass before merge. +- **Diagnostic recording.** Bridge events, audio interruptions, and + Rust-level log entries are captured into an in-memory ring buffer + accessible from the diagnostics page. +- **Shared app snackbar styling** for consistent error/info feedback. ### Changed -- Apple platform floors are raised to iOS 16 and macOS 13 while the - CoreML VAD package is linked. - -## [v1.0.0-rc.1] — MVP Public release candidate - -This is the first release candidate for the MVP public release per -DEC-001 sequencing. The remaining work before `v1.0.0` is DEC-012 -legal sign-off (see `docs/governance/legal-review-readiness.md`) and -the staged platform promotions in -`docs/governance/staged-release-plan.md`. - -### Added - -- **Platform keyring backing for the per-install Data Encryption Key.** - `chanora_storage::IdentityFileStore` now stores the 32-byte DEK in - the OS keyring (Linux Secret Service via D-Bus, macOS Keychain, - Windows Credential Manager, iOS Keychain) when one is available, - and transparently falls back to the v0.4 file-fallback at - `/identity.dek` otherwise. Existing file-fallback - installs are migrated into the keyring on first run when the - bus is reachable; the on-disk DEK copy is removed once the - keyring acknowledges the write. -- **`CHANORA_DISABLE_KEYRING=1`** environment override forces the - file-fallback path. Used by tests and headless / CI hosts where - a real keyring call would prompt the user or block on a missing - D-Bus session. -- **`chanora_storage::Crypto` trait + `IdentityFileStore::crypto()`** - give callers an envelope encrypt / decrypt pair anchored on the - per-install DEK. Used by `BookmarkRepository::with_crypto`. -- **Encrypted server passwords for bookmarks.** New `password_blob` - BLOB column (schema v2). When the bookmark repository is - constructed with a `Crypto` handle, server passwords are - ChaCha20-Poly1305-encrypted under the same per-install DEK as - the identity. Legacy `password TEXT` rows are still read for - backward compatibility and lifted into `password_blob` on the - next `update()`. `chanora_core::ChanoraSession::init_storage` - wires this automatically. -- **`SessionEvent::SnapshotChanged` now triggers on any tree - mutation**, not just count changes. The watchdog probe hashes - channels (id + parent + order + name) and clients (id + channel - + name); any change to those bits — including in-channel client - moves and channel renames — emits the event. -- **In-app About dialog** with the public product name (DEC-018), - the non-affiliation statement (DEC-019), the dual-license - declaration (DEC-020), and a pointer to the `NOTICE` file for - third-party attribution. New AppBar info icon opens the dialog. -- **`docs/governance/legal-review-readiness.md`** — the - engineering-side handoff package for the DEC-012 legal / - trademark / licensing review. -- **`docs/governance/staged-release-plan.md`** — the staging - schedule for DEC-002's five-platform MVP target. Linux + Android - sideload promote to GA on DEC-012 sign-off; Windows / macOS / - iOS gate on per-platform build host availability. - -### Changed - -- **`chanora_storage` test count rises from 8 to 10**: encrypted - bookmark password round-trip and legacy-plaintext-bookmark - upgrade scenarios. -- **`chanora_core` test count rises from 5 to 7**: signature - detects in-channel move; signature is stable under input-vector - reordering. -- **`NOTICE` refreshed** for the MVP product-code dependency set - (`chacha20poly1305`, `rand`, `zeroize`, `keyring`, - `connectivity_plus`, `path_provider`, `freezed_annotation`, the - removed `linux-keyutils` / `hound`, etc.). The PoC-era - enumeration is preserved upstream in git history. -- **`chanora_protocol::lib`** now also re-exports `ChannelId` and - `ClientId` for downstream signature / hashing helpers. +- **iOS / macOS audio lifecycle hardened.** Voice unit restart-in-place, + serialized lifecycle events, WebRTC VAD on iOS, unblocked connect-time + audio startup. +- **Linux native audio path promoted** with ONNX Runtime bundled for + VAD. Desktop voice I/O works on PipeWire / PulseAudio. +- **Android audio routing** uses `MODE_IN_COMMUNICATION`, proper + startup permission flow, and system back-button integration. +- **`SnapshotChanged` event removed.** Replaced by the typed delta + stream. The dead variant was removed end-to-end (protocol, bridge, + Flutter). +- **Prefetch crate renamed** from the PoC-era name to + `chanora_prefetch`. All docs, specs, and code updated. +- **Build number bumped to 76.** +- **Flutter bridge regenerated** for `flutter_rust_bridge` 2.12.0. ### Fixed -- The watchdog signature blind spot from v0.4: same-count - snapshots no longer suppress `SnapshotChanged`. +- **`clamp` panic on Info tab open.** `adapter.rs` cast `i64::MIN` to + `u128` before clamping, producing `min > max`. Replaced with + `.min(i64::MAX as u128) as i64`. +- **Non-self client profiles empty.** Added `request_client_db_info()` + with graceful fallback for missing fields. +- **Server query clients visible in UI.** Delta joins now filter + `is_server_query` clients from the channel tree. +- **Speaking indicators lost after reconnect.** Event forwarders are + reattached after the connection task restarts. +- **Channel double-tap join.** 1-second cooldown prevents rapid + re-join attempts. +- **`getconnectioninfo` errors silently discarded.** Now logged at + warning level instead. +- **iOS keyboard lag.** Multiple focus/tap handling fixes for iOS 26 + `TextField` stale-focus regression. +- **Storage test isolation.** Temp directories no longer collide across + parallel test runs. +- **CI submodule fetch.** iOS build job uses best-effort `git submodule + update` with `|| true` fallback for the private `silero-coreml` + package. +- **Stale license inventory.** Regenerated `docs/security/license- + inventory.md` to match current `Cargo.lock`. -### Security +### Notes -- DEK now sits behind the OS session lock on every supported - desktop platform; the v0.4 two-file weakness is closed for those - installs. Android, iOS, and other platforms without keyring - reach fall back to the v0.4 file model; `RISK-PoC-002` remains - open for them. - -### Notes (MVP scope honesty) - -- DEC-012 legal review has *not* been performed. `v1.0.0-rc.1` is - not the public release; it is the candidate that the review - signs off on (or rejects) before `v1.0.0` is tagged. -- Crash reporting is intentionally disabled (DEC-017). Repository - grep for `sentry|crashlytics|bugsnag` returns zero hits in the - MVP product code. -- Automatic diagnostic upload remains forbidden (DEC-016). The - user-initiated export path is the only way logs leave the - device. -- Android Keystore-backed DEK and iOS-side - `AVAudioSession.Mode.voiceChat` engagement are deferred to - v1.1. -- iOS, Windows, and macOS release binaries are not built into - `v1.0.0-rc.1`. The release page ships Linux x86_64 + Android - arm64-v8a only; the other three platforms are source-buildable - and promote per `staged-release-plan.md`. - -## [v0.4.0-beta.2] — External Beta - -Server password input, channel join via tap, self mute (mic + -speaker), master output gain slider, SQLite bookmarks with save / -connect / delete, ChaCha20-Poly1305-encrypted identity at rest -with `identity.dek` file, Android `MODE_IN_COMMUNICATION` routing, -default log filter trims `tsproto::resend` chatter, GitHub Actions -CI on every push. - -## [v0.3.0-beta.1] — Internal Beta (polish) - -A.1 cross-platform DNS, A.2 identity persistence, A.3 redacted -diagnostic export, A.4 SnapshotChanged event, A.5 mobile voice- -preset flag, A.6 reconnect supervisor with watchdog + UI banner, -A.6.1 OS connectivity signal drives reconnect timing. +- The `silero-coreml` submodule references a private repository + (`chanoraapp/silero-coreml`). CI builds skip the iOS unsigned build + when the submodule is unavailable. +- Default base branch is `main` (previously `product/scaffold-v0`). +- DSP chain (AEC / AGC / NS / HPF) is not yet production-tuned. + `AudioEffects` struct exists but filters are placeholder-grade. +- Desktop push-to-talk is capability-based; global PTT requires + OS-specific permissions and is not yet wired end-to-end in the UI. ## [v0.2.0-beta.1] — Internal Beta first build - - **Voice in/out wired end-to-end through the Flutter UI.** Per DEC-001 - this reaches the Internal Beta milestone. Build hash: see the - `v0.2.0-beta.1` git tag. -- `crates/chanora_audio/` promoted from scaffold to a working engine: - - cpal-based capture (mic gain, linear resampling to 48 kHz, mono - down-mix) and playback (48 kHz stereo, requested config). - - `audiopus::Encoder` for Opus VoIP encoding (20 ms / 960-sample - mono frames). - - `tsclientlib::audio::AudioHandler` for the decode + per-client - jitter buffer + mix on the playback side. - - Push-to-talk gate: encoder is bypassed entirely when PTT is off, - so no spurious silence frames leak out. - - Graceful playback-only fallback: if the host has no usable mic - (typical for headless CI / users who deny the mic permission), - capture logs a warning and the engine continues with output only. - `AudioEngine::capture_active()` exposes this for the UI. - - Live counters: `frames_sent` / `frames_received` / `ptt()`. -- `crates/chanora_protocol/` extended with voice channels: - - `ProtocolClient::voice_out()` returns a clonable - `mpsc::Sender` for outbound frames. - - `ProtocolClient::take_voice_in()` returns a one-shot - `mpsc::Receiver` of decoded `S2C` / `S2CWhisper` - packets, with the originating `from_client` ID extracted. - - Re-exports the few `tsproto_packets::packets` types (`OutAudio`, - `OutPacket`, `InAudioBuf`, `AudioData`, `CodecType`, `Direction`) - that `chanora_audio` legitimately needs. This is the **only** - deliberate cross-crate type re-export; per SAD-067 the audio - path is performance-sensitive and a parallel type hierarchy - would force a copy per 20 ms frame. - - Connection task interleaves outbound voice (drained first per - loop iteration), event pumping, and control-request handling. -- `core/chanora_core::ChanoraSession` audio API: - - `start_audio(AudioEngineConfig)` — starts the engine attached to - the active connection. Idempotent. - - `set_ptt(bool)` — toggles transmission. No-op without an engine. - - `audio_stats()` → `(frames_sent, frames_received, ptt_active)`. - - `disconnect()` now stops the engine before disconnecting the - protocol task. -- `crates/chanora_bridge/` audio surface: - - `start_audio()`, `set_ptt(active)`, `audio_stats()` Dart-callable - commands. - - `BridgeAudioStats { frames_sent, frames_received, ptt_active }` - DTO. - - Mapped `CoreError::AudioNotStarted` and `CoreError::Audio(_)` - arms in `BridgeError::From`. -- `apps/chanora_flutter/`: - - Beta UI rewrite of `main.dart`: "Start audio" button after - connect; hold-to-talk button with pressed/released visual state; - live audio-stats line below the PTT (`TX … frames • RX … frames - • PTT on/off`). - - ARB key set expanded with `startAudioAction`, `pttHoldToTalk`, - `pttTransmitting`, `audioStatsLine` in both `en` and `zh-Hans`. - - `test/beta_e2e_test.dart` exercises the full - Dart → FRB → chanora_bridge → chanora_core → chanora_audio - path against `cn.teamspeak.app`. Verifies connect, audio start, - PTT toggle, disconnect. -- `flutter_rust_bridge.yaml` now sets `local: true` so the codegen - resolves the workspace member's library name correctly. Without - this, the generated Dart side fell back to `libUNKNOWN.so` and - failed to load the cdylib. + this reaches the Internal Beta milestone. +- `crates/chanora_audio/` promoted from scaffold to working engine: + cpal capture (mic gain, linear resampling to 48 kHz, mono down-mix) + and playback (48 kHz stereo). Opus VoIP encoding (20 ms frames). + Push-to-talk gate. Live counters. +- `crates/chanora_protocol/` extended with voice channels. +- `core/chanora_core::ChanoraSession` audio API. +- `crates/chanora_bridge/` audio surface for Dart. +- Beta UI rewrite with connect, PTT, and audio stats. -### Changed +### Notes -- `flutter_rust_bridge.yaml`: added `local: true`. -- `chanora_bridge::api`: `BridgeError::From` now maps - `CoreError::AudioNotStarted` to `BridgeError::InvalidCommand` and - `CoreError::Audio(_)` to `BridgeError::Connection`. -- `apps/chanora_flutter/test/widget_test.dart`: banner-string - expectations updated from "Alpha build" to "Beta build" and from - "Alpha 版本" to "Beta 版本". -- `docs/governance/product-decision-register.md` bumped to v0.9.7 - with a Beta-milestone change-history entry. No decision rows - change. -- `docs/governance/poc-results-summary.md` bumped to v0.6.0 with a - Beta-milestone change-history entry; RISK-PoC-005 updated to - reflect Beta progress. +- DSP chain not yet implemented (AEC / AGC / NS / HPF deferred). +- Capture resampler is linear interpolation (production resampler + deferred). +- Identity is ephemeral per connect; persistence deferred. +- No live event stream — UI polls on timer. +- `chanora_diagnostics` still scaffold. +- Audio engine is desktop-only in this build. -### Notes (Beta scope honesty) +## [v0.1.0-alpha.1] — Internal Alpha -- DSP chain (AEC / AGC / NS / HPF per DEC-007..010) is **not yet - implemented**. `AudioEffects` exists as a struct but its filters - are no-ops in v0.2.0-beta.1. Real DSP is queued for Beta+ work. -- The capture resampler is a simple linear interpolator. Production - quality requires a proper resampler in Beta+. -- Identity is still ephemeral per connect; persistence via - `chanora_storage` is queued. -- No live event stream into Dart yet — the UI fetches snapshots and - audio stats on a timer instead of subscribing to push events. -- `chanora_diagnostics` is still a scaffold; no redaction wired into - `tracing` yet. -- Audio engine is desktop-only in this Beta. Mobile bundle of the - bridge cdylib + UI verification was proven by the PoC but is not - re-built into product code in this milestone. - -### Carry-over from Alpha (v0.1.0-alpha.1) - -- **First Alpha build wires the connect → snapshot → disconnect cycle - end-to-end from the Flutter UI to a live TeamSpeak-compatible - server via the typed Flutter/Rust bridge.** Per DEC-001 this is the - Internal Alpha milestone; Audio (voice in/out) is deferred to Beta. -- `crates/chanora_protocol/` promoted from a scaffold to a working - adapter. Public surface: - - `ConnectConfig`, `ProtocolClient`, `ProtocolError`. - - DTO module exposing `ChannelId`, `ClientId`, `ChannelInfo`, - `ClientInfo`, `ServerSnapshot` — all owned primitives and - `String`s; no `tsclientlib::*` types leak (SAD-067). - - Tokio task owns the `tsclientlib::Connection`; public handle - communicates via `mpsc` requests + `oneshot` replies. - - Connect waits for the initial `BookEvents` snapshot, then pumps - events for ~2 s so the subscribed channel tree settles before - the first snapshot is served. - - Promoted from `poc/tsclientlib-connect-spike`. -- `core/chanora_core::ChanoraSession` now drives the protocol crate - with a typed `connect`/`snapshot`/`is_connected`/`disconnect` API. - Enforces the DEC-006 single-connection invariant via an internal - `tokio::sync::Mutex>`. -- `crates/chanora_bridge/` wired against `flutter_rust_bridge` 2.12.0 - (DEC-014). Compiled as `cdylib + staticlib + rlib`. Exposes: - - `bridge_init()` (FRB lifecycle), `connect()`, `snapshot()`, - `disconnect()`, `is_connected()`. - - Typed `BridgeChannel`, `BridgeClient`, `BridgeSnapshot` DTOs; - `BridgeError` with `From`. - - A process-wide `tokio::Runtime` + `ChanoraSession` via - `OnceLock`, used by every async command. - - The crate's `#![forbid(unsafe_code)]` lint was lifted to - `#![warn(missing_docs)]` only, with a doc-comment explanation - that the FRB-generated glue legitimately uses unsafe at the FFI - boundary; hand-written code in the crate is still expected to - avoid `unsafe`. -- `flutter_rust_bridge.yaml` at the repo root drives codegen for the - bridge. -- Generated Dart bindings under - `apps/chanora_flutter/lib/src/rust/{api.dart,frb_generated*.dart,lib*.dart}`. -- Generated Rust glue under `crates/chanora_bridge/src/frb_generated.rs`. -- `apps/chanora_flutter/lib/main.dart` rewritten as the Alpha UI: - - Form: server address + nickname, both pre-populated for - convenience. - - Connect button → calls FRB → enters connecting state → shows - snapshot. - - Snapshot view: server welcome banner (preserved verbatim per - ADR-008), `N channels • M online` count, ordered channel list - with clients indented under their channel. - - Refresh and Disconnect actions in the app bar. -- `apps/chanora_flutter/lib/l10n/app_{en,zh}.arb` expanded with the - Alpha key set: - `homeNotProductionReadyBanner` (now says "Alpha build"), - `fieldServerHost`, `fieldNickname`, - `connectAction`, `disconnectAction`, `refreshAction`, - `statusIdle`, `statusConnecting`, `statusConnected`, `statusError`, - `channelsHeading`, `clientsHeading`, `countChannelsAndClients`. -- `flutter_localizations`, `intl`, `flutter_rust_bridge`, - `freezed_annotation` added to dependencies; - `freezed` and `build_runner` added to dev_dependencies. -- `apps/chanora_flutter/test/alpha_e2e_test.dart` runs the full - Dart → FRB → Rust → tsclientlib → network → server path against - `cn.teamspeak.app`. Verifies the snapshot contains a non-empty - server name and a non-empty channel list, that `isConnected()` - flips true → false across the disconnect, and that a re-fetched - snapshot agrees on the server name. Passes in ~2.5 s. -- `core/chanora_core/tests/alpha_smoke.rs` runs the same path from the - Rust side; tagged `#[ignore]` so `cargo test --workspace` doesn't - hit the network by default. Run with `--ignored alpha_smoke`. - -### Changed - -- `chanora_core::CoreError` no longer wraps `chanora_bridge::BridgeError`; - the relationship is the other way around (bridge maps from core). - This removes a cyclic `chanora_core` ↔ `chanora_bridge` dependency - introduced when the bridge crate gained `chanora_core` as a dep. -- `chanora_bridge` lints relaxed from `#![forbid(unsafe_code)]` to - `#![warn(missing_docs)]` (documented above). - -### LICENSE files (carry-over from earlier in this branch) - -- `LICENSE-APACHE` — Apache License Version 2.0 text (DEC-020). -- `LICENSE-MIT` — MIT License text (DEC-020). -- Initial repository foundation files. -- Documentation-first project structure. -- `justfile` with `format`, `lint`, `test`, `verify-docs`, and - `security-scan` targets, completing `repository-bootstrap-plan` v0.1.0 §3. -- `poc/tsclientlib-connect-spike/` — PoC proving protocol feasibility via - `tsclientlib`. Verified against `cn.teamspeak.app` on 2026-05-13. -- `poc/flutter_rust_bridge_hello/` — PoC proving the Flutter↔Rust command - and event-stream boundary via `flutter_rust_bridge` 2.12.0. Verified on - Linux desktop on 2026-05-13. -- `poc/secure-storage-spike/` — PoC proving platform secure storage via - a typed `SecretStorageRepository` trait and a Linux adapter selecting - between Secret Service (libsecret) and kernel keyutils. Audit checks - SS-AUD-001/002/003/005/006 and SS-TC-003 verified on 2026-05-13. -- `poc/sqlite-storage-spike/` — PoC proving SRS-089's "embedded data - store + migration mechanism" acceptance criteria: forward-only schema - migrator tracked via `PRAGMA user_version`, repository pattern with - `BookmarkRepository` / `SettingsRepository` traits over - `LocalDatabaseRepository`. 11/11 tests verified on 2026-05-13. -- `poc/diagnostics-redaction-spike/` — PoC proving the diagnostic - redaction policy from `diagnostic-redaction-audit-report.md`: - typed policy + regex rules + literal known-secret registry + bundle - redaction. Audit cases REDACT-TC-001..010 verified on 2026-05-13. -- `poc/audio-capture-playback-spike/` — PoC proving platform audio - capture/playback via cpal. Desktop half (Linux + PipeWire) - empirically verified end-to-end on 2026-05-13; mobile half closed - separately by `poc/audio-capture-playback-android-spike`. -- `poc/audio-capture-playback-android-spike/` — PoC closing the - mobile half of the audio capture/playback PoC plan entry. Rust - cdylib + JNI + Kotlin Android app; cpal targets Android's Oboe - backend (AAudio). Verified end-to-end on a physical Motorola - Moto G Stylus 5G (2023) running Android 14 arm64-v8a on - 2026-05-13: 500 ms 440 Hz sine wave driven out the device speaker - (22,050 frames at 44.1 kHz) and 1 s captured from the microphone - into a valid 85,292-byte RIFF/WAVE mono 16-bit PCM file pulled via - `adb exec-out run-as`. -- `poc/README.md` summarising PoC status against - `docs/architecture/proof-of-concept-plan.md`. - -### Changed - -- **DEC-020 license resolved.** Chanora is now dual-licensed under - **Apache-2.0 OR MIT** (recipient's choice), the standard - Rust-ecosystem permissive model. Compatible with every direct - dependency (`tsclientlib`, `flutter_rust_bridge`, `cpal`, `rusqlite`, - `keyring`, etc.) and with the Flutter framework's BSD-3-Clause. - `LICENSE` rewritten as a dual-license aggregator pointing at - `LICENSE-APACHE` and `LICENSE-MIT`. `NOTICE` rewritten with current - direct-dependency attributions. `README.md` §License updated. -- `docs/governance/product-decision-register.md` bumped to v0.9.6: - DEC-020 status promoted from Open to Accepted. §4 license row - updated. §6 collapsed: there is no longer any open decision — - DEC-012 legal review remains as a *work* item, not a pending - decision. Change-history entry added. -- `docs/governance/poc-results-summary.md` bumped to v0.4.0: - RISK-PoC-003 closed. DEC-020 row moved from the "Still open" - section into the closed table. - -- `docs/governance/product-decision-register.md` bumped to v0.9.5: - owner confirmation on all 17 previously-Proposed decisions - (DEC-001..010, 012, 015..019, 021). Sixteen were Accepted as - recommended; two were modified by the owner — **DEC-004** - Android minimum raised from API 24 to **API 28**, and - **DEC-015** product language for MVP expanded from English-only - to **English + Chinese (Simplified)**. DEC-020 license remains - Open / Deferred and is now the only public-release-gating - decision outstanding. §4 renamed "Recommended" → "Accepted MVP - Defaults" with MODIFIED rows annotated. §6 collapsed to the - single remaining DEC-020 item. §7 dated and statused for every - decision. -- `docs/governance/poc-results-summary.md` bumped to v0.3.0: - RISK-PoC-004 closed by the owner-confirmation pass; new - RISK-PoC-006 (Android `minSdk` move 24 → 28 for product code) - and RISK-PoC-007 (MVP language expansion to en + zh-Hans) added. -- `docs/architecture/proof-of-concept-plan.md` bumped to v0.3.0 to - promote the audio PoC from PARTIAL PASS to PASS after the Android - mobile half was closed; all six PoC plan entries are now PASS. -- `docs/governance/product-decision-register.md` bumped to v0.9.4 to - promote DEC-011.1 mobile half from Deferred to Accepted (Android), - keeping iOS Deferred. -- `docs/governance/poc-results-summary.md` bumped to v0.2.0: - audio row promoted to PASS, RISK-PoC-001 narrowed from "mobile - audio" to "iOS audio only", Android toolchain added to the - toolchain table. -- `poc/audio-capture-playback-spike/VERIFICATION.md` updated to point - at the Android spike for the mobile half. -- `poc/README.md` updated to list both audio spike directories. -- `docs/architecture/proof-of-concept-plan.md` bumped to v0.2.0 to - record PoC outcomes (5 PASS, 1 PARTIAL) and add a Status column. -- `docs/security/secure-storage-audit-report.md` bumped to v0.9.3: - SS-AUD-001/002/003/005/006 status set to PoC Pass with evidence - pointers; SS-TC-003 (Linux) Actual Result populated and Status set - to PoC Pass; findings SS-FIND-001..003 added; non-Linux test cases - marked Deferred. -- `docs/security/diagnostic-redaction-audit-report.md` bumped to - v0.9.3: REDACT-TC-001..010 status set to PoC Pass with evidence - pointers; export bundle policy §5 populated; findings - REDACT-FIND-001..003 added. -- `docs/governance/product-decision-register.md` bumped to v0.9.3: - owner-confirmed decisions recorded — DEC-014 Accepted - (`flutter_rust_bridge` 2.x pinned), DEC-013.1 Accepted (`rusqlite` - bundled), DEC-013.2 Accepted (Linux Secret Service preferred, - keyutils fallback), DEC-011.1 Accepted (desktop `cpal`) / Deferred - (mobile), DEC-022 Accepted (canonical implementation directory - layout per README sketch + SAD §7.2), DEC-020 explicitly Deferred - and remains a public-release blocker. - -### Added (governance) - -- `docs/governance/poc-results-summary.md` v0.1.0 — single-page - reviewer-facing summary of the PoC phase, the toolchain exercised, - the owner decisions taken, the audit coverage, and the open risks - RISK-PoC-001..005. - -### Fixed - -- N/A - -### Security - -- N/A +- First Alpha build wires connect → snapshot → disconnect end-to-end + from the Flutter UI to a live TeamSpeak-compatible server via the + typed Flutter/Rust bridge. +- `crates/chanora_protocol/` promoted from scaffold to working adapter. +- `crates/chanora_bridge/` wired against `flutter_rust_bridge` 2.12.0. +- Alpha UI: server address form, connect button, snapshot view. ## Versioning note diff --git a/apps/chanora_flutter/android/app/build.gradle.kts b/apps/chanora_flutter/android/app/build.gradle.kts index 886d22b..3700d44 100644 --- a/apps/chanora_flutter/android/app/build.gradle.kts +++ b/apps/chanora_flutter/android/app/build.gradle.kts @@ -33,9 +33,10 @@ val releaseStorePassword = resolveSigningProp("CHANORA_RELEASE_STORE_PASSWORD") val releaseKeyAlias = resolveSigningProp("CHANORA_RELEASE_KEY_ALIAS") val releaseKeyPassword = resolveSigningProp("CHANORA_RELEASE_KEY_PASSWORD") val hasReleaseSigning = listOf(releaseStoreFile, releaseStorePassword, releaseKeyAlias, releaseKeyPassword).all { !it.isNullOrBlank() } -val splitPerAbiRequested = gradle.startParameter.taskNames.any { taskName -> - taskName.contains("split-per-abi", ignoreCase = true) -} +val splitPerAbiRequested = project.hasProperty("split-per-abi") || + gradle.startParameter.taskNames.any { taskName -> + taskName.contains("split-per-abi", ignoreCase = true) + } val configuredAbiSet = listOf("arm64-v8a", "x86_64") val flutterTargetPlatformArg = gradle.startParameter.projectProperties["target-platform"] ?.split(',') @@ -86,16 +87,22 @@ android { // and x86_64. Other ABIs (x86, mips, …) shall not be packaged. // Per-ABI delivery is handled by the AAB bundle splits below // (SDD-109 item 2) rather than a fat APK. - ndk { - // DEC-032 RESOLVED (2026-05-18): canonical two-ABI set - // (arm64-v8a + x86_64) restored after the audiopus_sys - // ANDROID_ABI propagation gap was closed by the workspace - // [patch.crates-io] override pinning `cmake` to the fork - // carrying cmake-rs PR #257 (forwards ANDROID_ABI / - // ANDROID_PLATFORM as -D variables to the child cmake - // invocation). See Cargo.toml [patch.crates-io] block and - // docs/governance/product-decision-register.md DEC-032. - abiFilters += effectivePackagingAbis + // When Flutter --split-per-abi is active, skip ndk.abiFilters to avoid + // conflicting with the Gradle splits.abi mechanism that Flutter injects. + // The per-ABI filtering is still handled by the jniLibs excludes below + // and the Rust cargo-ndk per-ABI build tasks. + if (!splitPerAbiRequested) { + ndk { + // DEC-032 RESOLVED (2026-05-18): canonical two-ABI set + // (arm64-v8a + x86_64) restored after the audiopus_sys + // ANDROID_ABI propagation gap was closed by the workspace + // [patch.crates-io] override pinning `cmake` to the fork + // carrying cmake-rs PR #257 (forwards ANDROID_ABI / + // ANDROID_PLATFORM as -D variables to the child cmake + // invocation). See Cargo.toml [patch.crates-io] block and + // docs/governance/product-decision-register.md DEC-032. + abiFilters += effectivePackagingAbis + } } } diff --git a/apps/chanora_flutter/pubspec.yaml b/apps/chanora_flutter/pubspec.yaml index c513ed9..5be734b 100644 --- a/apps/chanora_flutter/pubspec.yaml +++ b/apps/chanora_flutter/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.2.0-beta.1+76 +version: 0.3.0+100 environment: sdk: ^3.11.5