eb10db5b59f178645890beaeba9fb0a1e12b402c
55
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
eb10db5b59 |
docs(audio): document macOS 13 floor, render peak limiter, and VPIO ducking config
- docs/sysrs.md: raised macOS minimum runtime in SysRS-310 from 10.15 to 13.0 to match the actual floor in apps/chanora_flutter/macos/chanora_bridge.podspec (MACOSX_DEPLOYMENT_TARGET = 13.0) and macos_deployment_target.rb; added a change-log entry for the raise. SysRS-051 gained a note documenting the iOS/macOS audio-lifecycle asymmetry (iOS has full AVAudioSession lifecycle; macOS is limited to launch-time mic permission + VPIO engine restart on default-device change + VPIO startup readback in the current baseline). - docs/architecture/sdd.md: added two rows to the Audio Detailed Design table. 'Render peak limiter' documents voice_render::limit_peak_inplace (single-pass, allocation-free, threshold 0.99, applied in both Apple render callbacks before i16 downmix). 'VPIO ducking config (macOS 14+)' documents the 8-byte AuVoiceIoOtherAudioDuckingConfiguration struct write to selector 2108 on the VoiceProcessingIO AudioUnit at startup, with the macOS 13 silent-fallback behaviour. - docs/governance/product-decision-register.md: added DEC-033 recording the VPIO ducking configuration decision (advanced ducking off, level = Min, macOS 14+ only). |
||
|
|
5e8b7915db |
feat(ui): adaptive 3-panel layout, chat panel switching, audio metering fix
- Add responsive breakpoints (compact <600, medium 600-1023, expanded >=1024) - Add ViewportInfo InheritedWidget for layout-aware descendants - Add inline ChatPanel (380dp right column) for expanded desktop layout - Add channel right-click context menu with Chat option for in-place switching - Add per-target draft persistence via restoredDraft/onDraftChanged callbacks - Fix header chat button to switch to current voice channel when panel open - Fix close = dismiss (preserves last target and draft for reopen) - Add unread dot indicator on channel tiles when chat is closed - Fix audio regression: decimate dBFS computation to every 3rd callback (~31 Hz) to avoid buffer underruns on macOS CoreAudio real-time thread - Add tools/build-macos.sh release build script (7-step process) - Add chat panel switching implementation plan and 3-panel design spec Tests: 183 passed, 2 skipped. Flutter analyze clean. |
||
|
|
2902a8bcd5 |
fix(audio): eliminate Android output stutter via Oboe config + lock-free callback (#20)
* fix(audio): eliminate Android output stutter via Oboe config + lock-free callback Phase 1 — Oboe configuration: - Change output stream from Usage::VoiceCommunication to Usage::Game with ContentType::Sonification to avoid forcing the Legacy (OpenSL ES) data path on most devices (Oboe issue #2075) - Switch output format from i16 Mono to f32 Stereo, matching Qint's proven configuration and eliminating per-callback downmix conversion - Set buffer size to 2x burst after stream open, reducing default buffer from 8-20x burst to 2x burst for lower latency - Remove scratch Mutex<Vec<f32>>; callback writes directly to Oboe buffer Phase 2 — Lock-free output callback: - Add audio_event_queue.rs: lock-free SPSC bridge using crossbeam ArrayQueue with separate packet (lossy) and control (reliable) channels - OutputCallback now owns AudioHandler directly (no Arc<Mutex<>> on Android) - Inbound forwarder pushes packets via AudioEventProducer (no mutex) - set_client_volume pushes control commands via event queue on Android - iOS/desktop Arc<Mutex<AudioHandler>> path unchanged * fix(audio): address PR #20 review findings - Store AudioEventConsumer directly in OutputCallback to eliminate per-callback Arc clone on the real-time audio thread - Add SAFETY comment for the unsafe from_raw_parts_mut transmute - Bound set_client_volume spin-loop to 64 retries with warn log - Remove redundant crossbeam-utils direct dependency - Regenerate license inventory for new crossbeam deps (CI fix) * fix(audio): use ASCII TODO punctuation |
||
|
|
808324f374 |
feat: event-driven UI updates for instant channel switching (#15)
* chore: regenerate Cargo.lock after rebase * fix(ui): add 1s cool-down to prevent double-tap channel join voiceJoin returns instantly (fire-and-forget protocol), so the pending-join guard clears before a second tap lands. The cool-down prevents the rapid channel oscillation and ClientIsFlooding (524) that results from double-tapping. * fix(ui): handle ChannelAlreadyIn as success, ClientIsFlooding with backoff - ChannelAlreadyIn (0x0302): treat as silent success, update UI state - ClientIsFlooding (0x020c): show localized snackbar, extend cooldown 5s - Add l10n strings for flooding error (en + zh) * fix(proto): use Windows TS3 client version for broadest compatibility Matches Qint's default (Windows_3_X_X__1). Avoids server-side behavioral differences with TS5 version strings. * fix(proto): patch tsproto-types to handle short P-256 coordinates BigInt::to_bytes_be() strips leading zeros, causing WrongPublicKeyLength when a server's ephemeral key coordinate starts with 0x00. Patch from EdisonJwa/tsclientlib fix/p256-short-coordinate-pad branch left-pads coordinates to the P-256 field size instead of rejecting them. * refactor(core): stop watchdog from emitting SnapshotChanged The watchdog now serves only as a liveness probe (miss counting for reconnection). UI updates are handled entirely by the event-driven delta path (ProtocolDelta → SessionEvent → BridgeEvent → Flutter). Removes signature tracking and SnapshotChanged emission from the supervisor loop. The initial snapshot is still fetched via the Connected event handler in Flutter. * refactor(ui): remove channel-join cooldown guard With event-driven deltas the UI updates instantly on channel moves, so the 1-second cooldown is no longer needed. Double-taps are handled by the server (ChannelAlreadyIn → success) and the pending-channel-id guard prevents overlapping requests. Also removes the _lastJoinCompletedAt field entirely. * fix(core): reattach event forwarders after reconnect The reconnect path swapped in a new ProtocolClient but never took chat_rx, activity_rx, or delta_rx from it. After the first reconnect, the event-driven UI pipeline was dead. Fix by extracting spawn_event_forwarders() helper called on both initial connect and reconnect. Also replaces lossy try_recv+sleep polling with proper recv().await for push-based delivery. * feat(protocol): enrich delta schema with all snapshot-visible fields ClientJoined now carries input_muted, output_muted, is_server_query, talk_power, talk_power_granted. ChannelAdded/ChannelUpdated now carry has_password and needed_talk_power. ClientUpdated also carries is_server_query, talk_power, talk_power_granted. This prevents local snapshot drift where fabricated defaults could hide password requirements, talk-power restrictions, or client type. * refactor: remove dead SnapshotChanged variant end-to-end SnapshotChanged is no longer emitted since the watchdog was refactored to liveness-only. Removes the variant from SessionEvent, BridgeEvent, and the Flutter switch statement. FRB bindings regenerated. * fix(ci): regenerate license inventory and fix iOS submodule fetch - Regenerate docs/security/license-inventory.md to match current lockfile - Remove submodules: true from checkout (causes hard fail on private submodule) - Add explicit git submodule update --init --depth=1 with || true fallback - Check silero-coreml/Package.swift instead of directory existence |
||
|
|
dab90852a3 |
Merge pull request #13 from EdisonJwa/feat/apple-coreml-vad
Add Apple CoreML Silero VAD |
||
|
|
80c2ed46bc | fix(ci): align Flutter inventory with stable SDK | ||
|
|
7510bdca73 | fix(ci): refresh Flutter license inventory | ||
|
|
ddf858cc6c | fix(audio): address CoreML VAD review feedback | ||
|
|
966afd2b53 | ci: fix Apple CoreML VAD checks | ||
|
|
0e6c4941ad | docs(security): refresh license inventory ordering | ||
|
|
1fc0aaeabb | docs(prefetch): update rename design spec | ||
|
|
d19501ec66 | docs(prefetch): update rename implementation plan | ||
|
|
92c09aece3 | docs(verification): rename prefetch crate references | ||
|
|
8506e56da1 | docs(security): rename prefetch crate references | ||
|
|
31373d3ec4 | docs(architecture): rename prefetch crate references | ||
|
|
fe6e07353e | chore: restore product scaffold to rollback baseline | ||
|
|
cd14aa7b98 | build: bundle onnxruntime in linux releases | ||
|
|
a2d686d9d0 | feat: promote linux native audio path | ||
|
|
3200312b0d | docs: add baseline references and workspace tasks | ||
|
|
6af4ecab0f | feat(voice): add iOS VAD runtime support | ||
|
|
7d6d56e330 | docs(p0): compact MVP spec for Android Oboe focus | ||
|
|
8c253f1d4d | feat(voice): harden Android audio and channel joins | ||
|
|
29a553d4e1 |
docs(traceability): add Deferred Work Watchlist (DW-001..DW-012); matrix v0.9.11
Convert prose-only deferrals scattered across SDD-120 §10, SDD-119 §3, DEC-032 resolution prose, and researcher Wave 4 Tier B notes into a single durable governance register. Watchlist is governance-layer only; no engineering-chain coverage rule relaxed. Entries: - DW-001 Dimension 3 production telemetry export (SDD-120 §10 / SysRS-308; P1; systems-requirements) - DW-002 Build-failing hard CI gate vs. current advisory-only (SDD-120 §10; P1; systems-requirements) - DW-003 Multi-host benchmarking (macOS Apple Silicon + Windows x86_64; SDD-120 §10 / SysDes-157; P2; system-architect) - DW-004 IDE integration for cargo bench (SDD-120 §10; P3; builder) - DW-005 Dart-side flutter_rust_bridge round-trip bench (SDD-120 §10 / Tier B4; P2; detailed-designer) - DW-006 iOS deployment-target SoT consolidation (SDD-119 §3 v0.9.17; macOS half already closed by b23b46c; P2; detailed-designer) - DW-007 Opus encode/decode latency under varied conditions (Tier B; P2; verification-engineer) - DW-008 Resampler throughput at non-canonical rate pairs (Tier B; P3; verification-engineer) - DW-009 Protocol forwarder loop tracing benchmark (Tier B; P3; verification-engineer) - DW-010 Remove [patch.crates-io] cmake-rs pin once PR #257 merges and a release lands (DEC-032 resolution prose; P2; builder) - DW-011 Linux SIGABRT root cause + graceful shutdown SRS/SDD chain (no source SDD yet; P0; debugger then systems-requirements) - DW-012 Manual bench-baseline-update.yml workflow_dispatch to seed first real baseline (SDD-120 §6 / SAD-091; P1; operator action) DW-010 and DW-006 had partial prose precedents in DEC-032 and SDD-119 respectively; neither was tracked in a watchlist. No duplicates introduced. ID convention (monotonic DW-NNN, retired-not-reused) established in the section intro. Doc-only change; no code touched. |
||
|
|
477394d83e |
fix(android,build): restore multi-ABI build via cmake-rs patch (DEC-032 exit)
Closes DEC-032. Restores the canonical Android ABI set
{arm64-v8a, armeabi-v7a, x86_64} per SDD-073 item 4 / SDD-118 item 3.
Root cause was the audiopus_sys + cmake-rs + NDK toolchain-file gap:
cargo-ndk 4.x sets ANDROID_ABI / ANDROID_PLATFORM as env vars per
invocation, but upstream cmake-rs 0.x does not forward them to the
child cmake invocation as -D variables, so armeabi-v7a and x86_64
configure steps fell through to the toolchain-file default and
failed to build.
Fix:
- Cargo.toml: add a workspace [patch.crates-io] stanza pinning the
cmake crate to fork pr2502/cmake-rs @ commit
bdad5edc569d82151922c5c6c4685b1563f12aa1 (branch android-build),
which carries cmake-rs PR #257
(https://github.com/rust-lang/cmake-rs/pull/257). The patch is a
9-line addition that forwards ANDROID_ABI and ANDROID_PLATFORM
from the env to the child cmake as -D variables.
- Cargo.lock: regenerated by 'cargo update -p cmake'; the lone
cmake entry now points at the fork rev.
- apps/chanora_flutter/android/app/build.gradle.kts: restore
abiFilters to {arm64-v8a, armeabi-v7a, x86_64}; remove the
TODO(x86_64/armv7 follow-up) comment.
- docs/governance/product-decision-register.md: mark DEC-032 as
Resolved (2026-05-18) with the resolution mechanism, update the
§3 / §7 rows, and append a 0.9.8.1 change-history entry.
Verification (host: Linux):
cargo update -p cmake -> pulled fork rev
cargo check --workspace --all-targets -> PASS
cargo test --workspace -> PASS (no regressions)
cargo ndk --platform 28 -t arm64-v8a build -p chanora_bridge -> PASS
cargo ndk --platform 28 -t armeabi-v7a build -p chanora_bridge -> PASS
cargo ndk --platform 28 -t x86_64 build -p chanora_bridge -> PASS
Upstream tracking: re-evaluate the [patch.crates-io] override once
cmake-rs PR #257 merges and a fresh cmake release lands on
crates.io; at that point switch to a plain dep bump and remove the
override.
|
||
|
|
167aef5760 |
docs(sysrs): SysRS-310 — macOS minimum runtime baseline (v0.9.11)
Author SysRS-310 ratifying the macOS minimum runtime baseline at 10.15 (Catalina) at the SysRS layer, parallel to SysRS-286 (iOS 13.0) and SysRS-288 (Android API 28). Closes the Wave 1.5 traceability-audit deferred-but-optional follow-up. ID allocation: SysRS-310 (not SysRS-290, which is already allocated to MVP single-active-server-connection scope); monotonic numbering preserved. Cross-references SAD-087, SDD-119, SysRS-286, SysRS-288. Verification: Review + Platform Test on a macOS 10.15 system. Raising the baseline (e.g., to 11.0 / Big Sur) requires a DEC entry. Trace: SysRS v0.9.11, SAD-087, SDD-119. |
||
|
|
a77a9b2ef2 |
docs(sdd-119)+feat(macos): consolidate deployment-target SoT (SDD-119 amendment v0.9.17)
Resolve the macOS half of the SDD-119 item 3 single-source-of-truth follow-up. The chanora_bridge cdylib macOS deployment-target floor ('10.15') was previously hard-coded at 7 sites across Podfile and chanora_bridge.podspec; this commit collapses them to a single Ruby constant declaration in a new SoT file.
Selected Option B (Ruby constant) over Option A (.xcconfig — rejected because the podspec prepare_command runs before any xcconfig is applied) and Option C (versioned text file — rejected as overkill given both consumers are already Ruby). Realizes SAD-087(a)'s 'single macOS build-configuration location' mandate.
Out of scope: the pbxproj 'MACOSX_DEPLOYMENT_TARGET = 10.15' lines (565/666/717) belong to the PBXProject default config and are independently overridden to '11.0' at the Runner PBXNativeTarget level; they are the Runner app's floor, not the bridge cdylib's floor. The iOS half (IPHONEOS_DEPLOYMENT_TARGET=13.0) remains an open follow-up.
Files: new apps/chanora_flutter/macos/macos_deployment_target.rb (MACOS_BRIDGE_DEPLOYMENT_TARGET = '10.15'.freeze); Podfile + chanora_bridge.podspec require_relative the constant and consume it at 7 sites; docs/architecture/sdd.md SDD-119 item 3 rewritten + Notes bullet updated + v0.9.17 changelog entry.
|
||
|
|
92087d066a |
docs(verification,traceability): SWE4-UV-058..062 for SDD-120 benches + matrix absorption
Closes the SDD-120 §11 verification-engineer follow-up and refreshes the
traceability matrix to incorporate the full benchmark-infrastructure
chain landed in commits 3a7750a / 8e95972 / 75b04f0.
swe4-unit-verification-plan.md v0.9.14 → v0.9.15:
- SWE4-UV-058: bench_capture_alloc_count (SDD-120 §3; SRS-216 metric 1;
SRS-219 clause a zero-tolerance).
- SWE4-UV-059: bench_capture_callback_wall_clock (metric 2; SRS-219 b
+20% p95).
- SWE4-UV-060: bench_opus_encode_latency (metric 3; SRS-219 c +15% mean).
- SWE4-UV-061: bench_opus_decode_latency (metric 4; SRS-219 c +15% mean).
- SWE4-UV-062: bench_resampler_throughput (metric 5; SRS-219 d -10%
samples/sec).
All five status PENDING_BASELINE until the first manual
bench-baseline-update.yml dispatch establishes baselines.
traceability-matrix.md v0.9.9 → v0.9.10:
- 9 new chain rows binding SysRS-307..309 → SysDes-156..158 →
SRS-216..219 → SAD-088..091 → SDD-120 sections → code anchors →
SWE4-UV-058..062.
- 10 new code-anchor rows for the benchmark files (benches/{common,
realtime_capture,opus_codec,resampler}.rs + examples/{emit,compare}
_baseline.rs + Cargo.toml + bench-advisory.yml +
bench-baseline-update.yml + .gitignore).
- 5 §A markers reconciled to PENDING_BASELINE (the SWE.4 IDs are now
authored; what remains pending is the baseline measurement).
- DEC-032 (abiFilters reduction) status unchanged; exit criteria
pending.
- All 5 prior open issues from earlier wave audits confirmed closed.
Verdict: TRACEABILITY_OK (engineering chain closed end-to-end). Only
remaining gap: PENDING_BASELINE, gated on CI minutes return + manual
workflow_dispatch on bench-baseline-update.yml.
|
||
|
|
b4cfb8174d |
docs(sdd-120): correct post-processor binary placement to examples/ (v0.9.16)
SDD-120 amendment v0.9.15 → v0.9.16 reflecting commit 3a7750a discovery. The two post-processor tools (emit_baseline, compare_baseline) were originally specified in SDD-120 §2 as residing in crates/chanora_audio/benches/, with [[bin]] declarations in Cargo.toml. The implementation discovered that Cargo's dependency resolver only routes [dev-dependencies] to [[test]], [[bench]], and [[example]] targets — NOT to [[bin]] targets under src/bin/ or to ad-hoc paths. Routing serde_json (required by both binaries) as a regular [dependencies] entry to support [[bin]] placement would force it into the production cdylib build, contradicting SDD-120 §10 release-artifact isolation: "no production telemetry export" and "no benchmark surface in shipping artifacts." Confirmed by the user's question about whether benchmark crates ship in the release artifact (they must not). The correct Cargo-idiomatic placement is examples/. Cargo auto-discovers files under examples/ as example targets; they receive [dev-dependencies] routing; and they are excluded from cargo build --release and from flutter build --release artifacts by Cargo design. Amendment scope (SDD-120 only): - §1 item 4: [[bin]] → [[example]]; cargo run --bin → cargo run --example. - §2: added item 5 with the rationale clause + Cargo dependency resolver explanation. - §5 item 1: path benches/ → examples/; invocation flag --bin → --example. - §5 item 4: dev-dependencies routing clause updated. - §6 step 6/8: --bin → --example. - §7 step 5: --bin → --example. - §10 item 1: release-artifact-isolation bullet extended to cite the [dev-dependencies] Cargo design mechanism that enforces it. - §11 verification matrix unchanged. - "Allocated to" line + "Software units" list updated to reference examples/ paths. No semantic change to SDD-120: same harness, same metrics, same workflows, same out-of-scope deferrals. The implementation at 3a7750a already lives at the corrected paths; this amendment brings the SDD text into agreement with the code. |
||
|
|
575a6cbc5c |
docs(perf,benchmark-infra): authorize realtime audio benchmark + advisory CI (SysRS-307..309 / SysDes-156..158 / SRS-216..219 / SAD-088..091 / SDD-120)
Author the full SysRS -> SysDes -> SRS -> SAD -> SDD chain for the benchmark infrastructure authorized by the Option B product decision (Dimensions 1 + 2-advisory; Dimension 3 telemetry export deferred to P1; build-failing hard CI gate deferred until baseline maturity). SysRS v0.9.10 adds: - SysRS-307: maintained numeric performance baselines for the realtime audio path (allocations per callback after warmup, callback wall-clock, Opus encode/decode latency, resampler throughput). - SysRS-308: advisory CI regression reporting on PR + merge to default; non-blocking semantics. - SysRS-309: explicit declared tolerance window. SysDes v0.9.8 adds: - SysDes-156: benchmark coverage allocated to SE-13 (Audio Subsystem). - SysDes-157: CI advisory-reporting integration allocated to SE-18 (Deployment). - SysDes-158: per-metric tolerance table (zero / +20% p95 / +15% mean / -10% throughput). SRS v0.9.9 adds: - SRS-216: realtime audio benchmark instrumentation in chanora_audio/benches/. - SRS-217: baseline storage format (JSON with metric/value/unit/host_arch/toolchain/git_sha/timestamp). - SRS-218: CI advisory workflow with non-blocking semantics. - SRS-219: tolerance window binding + merge-base comparison methodology. SAD v0.9.9 adds: - SAD-088: chanora_audio criterion bench harness (extends SAD-034). - SAD-089: baseline JSON path pinned to crates/chanora_audio/benches/baselines/x86_64-unknown-linux-gnu.json. - SAD-090: advisory CI workflow file (.github/workflows/bench-advisory.yml). - SAD-091: manual-trigger baseline-update workflow (sole writer of SAD-089). - Yellow-marker semantics pinned at SAD: 50%-of-tolerance trending detection. SDD v0.9.15 adds: - SDD-120: criterion 0.5 + dhat 0.3 dev-deps; three bench files (realtime_capture, opus_codec, resampler) + common.rs; two post-processor binaries (emit_baseline, compare_baseline); two GitHub Actions workflow YAMLs; simpler-form yellow-marker realization (baseline-only comparator). Out of scope (deferred): - Dimension 3 production telemetry export (P1). - Build-failing hard CI gate (post-baseline-maturity). - Multi-host benchmarking (Linux x86_64 only). - Dart-side flutter_rust_bridge round-trip benchmark. Implementation follows in a separate commit per the no-huge-commit guideline. |
||
|
|
5aa51c310f |
docs(p0): SysRS/SysDes/SRS/SAD/SDD/Verification + traceability for Android P0 reconciliation
Full P0 Android documentation chain: - SysRS: API 24 → API 28 reconciliation per DEC-004 (SysRS-288); add SysRS-305 (Android in-call audio mode), SysRS-306 (RECORD_AUDIO runtime timing). - SysDes: SysDes-152 (in-call audio mode subsystem), SysDes-153 (RECORD_AUDIO permission flow), SysDes-154 (Android voice audio backend), SysDes-155 (macOS runtime baseline). - SRS: SRS-187 → API 28; add SRS-208 (in-call audio mode), SRS-209 (RECORD_AUDIO + listen-only fallback), SRS-210..215 (Android voice audio backend latency/preset/AEC/usage/sharing/foreground service); retarget SysDes anchors from generic SysDes-135 to SysDes-152/153/154. - SAD: SAD-063 refreshed (API 28); add SAD-084 (audio mode controller), SAD-085 (permission adapter with listen-only), SAD-086 (foreground service), SAD-087 (macOS runtime baseline); formalize cross-cutting + platform-specific allocation pattern in §24.1. - SDD: expand SDD-028 (BackIntentService); refresh SDD-073 (build config); add SDD-105 (JNI bootstrap), SDD-106 (permission requester), SDD-107 (foreground service), SDD-108 (audio mode controller), SDD-109 (AAB pipeline), SDD-110 (PTT capability), SDD-111..116 (Android voice audio backend), SDD-118 (Android bridge build automation), SDD-119 (iOS/macOS bridge build automation back-fill). - Verification: create android-p0-acceptance.md TC-1..TC-18; add SWE4-UV-040..052, SWE5-IV-016..026, SWE6-SV-018..030, SYS4-SIV-015 strengthened + SYS4-SIV-017/018. - Governance: traceability matrix v0.9.9 with end-to-end chain closure; DEC-032 documents the temporary abiFilters reduction to arm64-v8a only and its restore-by gate. Trace: full chain SysRS → SysDes → SRS → SAD → SDD → Code → Verification. |
||
|
|
7a59f5b9a1 | feat(ios,p0): iOS P0 platform, audio fixes, channel UX | ||
|
|
6d094f3dbe |
docs(verification,index): iPad p0 acceptance checklist + 0.9.9 index row
New controlled document docs/verification/ipad-p0-acceptance.md
extends iOS P0 coverage to iPad. The build artefact is identical
to iPhone — `TARGETED_DEVICE_FAMILY = "1,2"` in
ios/Runner.xcodeproj/project.pbxproj is the Universal family, so
the same Runner.app installs on iPad with the same personal-team
provisioning profile.
15-row checklist mirrors ios-p0-acceptance.md TC-1..TC-12 and adds
three iPad-specific rows:
TC-13 wide-mode landscape layout — iPad in landscape is well
above the 840 dp LayoutBuilder breakpoint shipped in
apps/chanora_flutter/lib/main.dart, so the connected view
splits into a 320 dp left column (banner + Voice Bar) plus
an expanding channel tree. Portrait rotation collapses
back to the stacked iPhone layout. Long channel-name pills
still ellipsize per the earlier voice_bar.dart fix.
TC-14 Split View / Slide Over no-crash — Apple iPad multitasking
is intentionally unsupported in P0. UIApplicationSupports\
MultipleScenes stays false. This row asserts the app does
not crash when iPadOS tries to host it in Split View; the
actual multi-scene wiring is P1.
TC-15 AirPlay 2 audio route — verifies AVAudioSession routing
honours an AirPlay 2 destination picked via Control
Center, and routes back cleanly when iPad is reselected.
docs/governance/document-index.md
Bumped to 0.9.9 with the change-history row noting the iPad
acceptance doc. No spec items added; DEC-025 was originally
iPhone-only for the mobile target and this row formally
extends P0 coverage to iPad within the same iOS toolchain.
python3 tools/validate_docs.py: clean (pre-existing 35-filename
[FAIL] retained, unchanged).
|
||
|
|
41d5a4b91b |
docs(verification,index): macOS + iOS p0 acceptance checklists + 0.9.8 index row
New controlled documents:
* docs/verification/macos-p0-acceptance.md
15-row human-must checklist for Apple Silicon macOS P0 sign-off.
Targets the SDD-085 CGEventTap backend (now fully live) +
SDD-094..097 audio lifecycle. Auto-test rows pre-filled from the
M1 Mac verification pass: chanora_audio 34 / 0 / 0 (Linux: 32;
macOS delta is the keymap + Send-bound + descriptor-builder
tests). Pre-flight covers the manual framework-wrap +
install_name_tool + ad-hoc codesign step via the new
tools/macos-postbuild.sh. TC-3 walks the Input Monitoring grant
+ descriptor watch transition timing (~1.5 s).
* docs/verification/ios-p0-acceptance.md
12-row human-must checklist for iOS P0 sign-off on a physical
iPhone via the developer's free Apple Personal Team. TC-3
documents the Focused-only PTT capability iOS gives us (no
global event tap analogue exists). TC-8 covers UIBackgroundModes
= audio. TC-9 covers AVAudioSession routing — phone-call
interruption, AirPods route, etc.
docs/governance/document-index.md
Bumped to 0.9.8 with a change-history row covering both new
acceptance documents. No spec items added; the existing SDD-085
(macOS) and SDD-094..097 (audio lifecycle) are what these
documents sign off.
python3 tools/validate_docs.py: clean (pre-existing 35-filename
[FAIL] retained, unchanged).
|
||
|
|
cd402f164a |
docs(verification,index): linux p0 acceptance checklist + 0.9.7 index row
New controlled document docs/verification/linux-p0-acceptance.md mirrors
docs/verification/windows-p0-acceptance.md with 15 TC rows tuned for the
GNOME-on-Wayland target environment (DEC-025). Pre-flight calibrated to
the Arch verification host (100.74.219.114): pacman queries, path
prefixes, xdg-desktop-portal-gnome version notes. Auto-test sign-off
filled with the headless verification pass run over SSH:
cargo check --workspace --release clean (30.99 s)
cargo test --workspace --lib 78 / 0 / 1
cargo test ... linux_portal_smoke -- --ignored
-> 1 / 0 (GlobalShortcuts portal reachable, version = 1)
cargo test ... ptt_privacy 1 / 0 (DEC-027 holds)
The 15 GUI rows are marked pending physical-console pass. SDD-086 portal
flow is what this doc signs off; SDD-081/094..097 are referenced.
Document index bumped to 0.9.7 with the change-history row covering the
new acceptance doc. No spec items added; pre-existing 35-filename FAIL
in validate_docs.py retained.
|
||
|
|
61798e5bdf |
docs(verification,index): update test counts + add 0.9.6 row for rc.8 acceptance
- windows-p0-acceptance.md: bump auto-test row to reflect current Windows test count (126/0/1 — was 124/0/2 before the two new start_flips_armed_to_l2 tests landed). - document-index.md: new 0.9.6 row marking DEC-031 (missed-key-up watchdog disabled on P0) and the controlled status of docs/verification/windows-p0-acceptance.md. |
||
|
|
0b6ea11077 |
docs(verification): windows-p0-acceptance.md — human-side rc.8 sign-off
Captures the 15 TC rows the lead walks through on the Korean Win 11 host before tagging v1.0.0-rc.8, plus the auto-test sign-off matrix (Linux + Windows cargo + flutter analyze + validator + windows-smoke). Each TC row maps to a spec requirement (DEC / SRS / SDD) or to a regression the rc.7 review found. Failures block the tag. Known gaps recorded at the bottom: macOS / iOS / Android P0 are separate documents; VAD (DEC-030) and missed-key-up watchdog redesign (DEC-031) are P1; real RMS level meter is P1. |
||
|
|
45fec2310e |
fix(ptt): disable missed-key-up watchdog on P0 (DEC-031, supersedes DEC-028)
The watchdog spawned by ChanoraSession::start_audio cleared ptt_held after 30 s of continuous PTT key-down. That was correct for the 'OS lost the key-up event' failure mode the original SAD-079 / DEC-028 was designed to catch, but it was the wrong shape for real human speech: anyone holding the bound key for a long answer got cut off mid-sentence. For P0: - Comment out the spawn site in ChanoraSession::start_audio with the rationale + the P1 redesign options under consideration (raised ceiling / OS key-state polling / RMS-silence fallback). - Leave the MissedKeyUpWatchdog Rust type, its spawn / spawn_on_signal entry points, and all unit tests in chanora_audio::ptt unchanged so P1 can re-enable with the chosen detection strategy without re-implementing anything. Spec: new DEC-031 in product-decision-register.md supersedes DEC-028 for the v1 ship. DEC-028 stays in the register as historical context. The §7 open-decisions log + §8 change history get matching 0.9.12 rows. Note: Mumble and TeamSpeak ship without a comparable watchdog — the 30 s ceiling was stricter than industry baseline. The underlying protection (OS-level key-up loss) is still worth solving, just not with a fixed timeout. cargo test --workspace --lib: 80 passed / 0 failed / 1 ignored (unchanged; the watchdog unit tests still run because the type itself is unchanged). docs validator: clean (pre-existing 35-filename warning only). |
||
|
|
dfa84ee7bb |
docs(spec): baseline 0.9.5 — v1 audio + PTT lifecycle redesign
Add SysRS-303/304, SysDes-149/150/151, SRS-204/205/206/207, SAD-081/082/083, SDD-094/095/096/097, DEC-029/030. Captures the v1 lifecycle redesign: - Drop manual Start-audio button; audio engine is bound to voice-channel join/leave (ensure_running on first join, shutdown_if_idle on last leave). Output stream opens regardless of mic-permission state so listen-only is a first-class flow. - TransmitMode enum (Ptt / Continuous / VoiceActivity-reserved). Default Ptt on fresh install. Persisted per identity. - PTT release tail: 200 ms default (0-500 ms configurable) before transmit gate closes, avoiding clipped trailing syllables. - Hard-mute toggle overrides transmit gate regardless of mode/PTT. - Bridge surface: drop start_audio/stop_audio; add voice_join(channel_id) / voice_leave() and BridgeEvent::VoiceState. DEC-029 rejects Flutter global-hotkey packages (hotkey_manager, super_hot_key) for PTT: they wrap RegisterHotKey/RegisterEventHotKey which consume the key and don't fire key-up, wrong primitive for PTT. Native Rust DesktopPttBackend (SDD-083/084/085) stays authoritative. DEC-030 defers Voice Activity Detection to P1. RMS / WebRTC VAD / Silero VAD trade-off review (binary-size, dependency-surface, CPU profile) postponed; TransmitMode::VoiceActivity reserved on the enum surface so a P1 increment is non-breaking. Validator clean: 304/151/207/83/97 IDs, strict layered sourcing preserved, no new warnings beyond the pre-existing 35 old-package-name filenames. |
||
|
|
63f2901a6a |
docs(traceability): close SRS-200 SAD/SDD coverage gap (P0 audit follow-up)
A P0 traceability audit per the project's compliance workflow
found exactly one gap across the 162 P0 SRS items:
* SRS-200 (mouse side buttons as bindable inputs for desktop
Global PTT) had no dedicated SAD item. The earlier baseline
matrix folded SRS-200 under the narrative
`SRS-195..203 -> SAD-071..079` umbrella, which technically
covered the requirement at the table level but did not give
SRS-200 a one-to-one SAD source the validator's strict
discipline expects.
Per the project's gate-check workflow (Case C —
BLOCKED_MISSING_SAD) this commit closes the documentation chain
*before* claiming compliance for the already-merged mouse-side-
button code path:
* `docs/architecture/sad.md` v0.9.4 — new `SAD-080` sources
SRS-200, allocates `Audio (Windows / macOS / Linux), Bridge,
Flutter UI`, and records the cross-platform mouse-side-button
surface as a software-architecture item. The §27 coverage
matrix gains a dedicated SRS-200 -> SAD-080 row.
* `docs/architecture/sdd.md` v0.9.4 — new `SDD-093` sources
SAD-080. Specifies the `PttInputClass` enum surface
(`None` / `Keyboard` / `MouseSideButton`), the rebind
contract on the Windows + macOS backends, the Linux portal's
pass-through behaviour, and the Flutter
`PointerEvent.buttons` bitmask capture (back = `0x08`,
forward = `0x10`). The §11 coverage matrix gains the
SAD-080 -> SDD-093 row.
* `docs/governance/traceability-matrix.md` v0.9.4 — the
`(DEC-026 mouse buttons)` row moves from
`SAD-072..074 / SDD-082..086` to the dedicated
`SAD-080 / SDD-093`.
* `docs/governance/baseline-candidate-validation-report.md`
v0.9.4 — ID totals advance to 302 / 148 / 203 / 80 / 93;
direct-layer-rule and undefined-reference counts remain
zero.
* `docs/governance/repo-format-validation-report.md` v0.9.4 —
same ID totals update.
Audit summary
-------------
* 162 P0 SRS items audited.
* 1 SAD-coverage gap (SRS-200) — closed by this commit.
* 0 SDD-coverage gaps (every PTT SAD has explicit SDD coverage;
the inherited baseline `SAD-032/033` are covered through the
documented range row, not individually).
* All Priority: P0 software requirements now have a strict
SRS -> SAD -> SDD chain on file.
Validator output:
```
[OK] SysRS: 302 defined, 0 undefined references
[OK] SysDes: 148 defined, 0 undefined references
[OK] SRS: 203 defined, 0 undefined references
[OK] SAD: 80 defined, 0 undefined references
[OK] SDD: 93 defined, 0 undefined references
[OK] SRS direct SysRS references: 0
[OK] SAD direct SysRS references: 0
[OK] SAD direct SysDes references: 0
[OK] SDD direct SysRS references: 0
[OK] SDD direct SysDes references: 0
[OK] SDD direct SRS references: 0
```
Implementation status
---------------------
The mouse-side-button code was implemented in v1.0.0-rc.4 and
v1.0.0-rc.5 under the (then-implicit) PTT umbrella; the code
already matches the new SDD-093's contract verbatim. This
commit ships **documentation only** — it adds the SAD/SDD/matrix
rows that retroactively justify the existing implementation
under the strict traceability discipline. No code edits, no test
edits.
* `cargo test --workspace`: 67/67 green (unchanged).
* `cargo deny check`: advisories ok, bans ok, licenses ok,
sources ok.
* `cargo about generate`: zero new warnings (no Cargo.lock
delta).
* `flutter analyze`: clean.
* `tools/validate_docs.py`: all SRS/SAD/SDD coverage and
direct-layer-rule checks pass.
Outstanding open items remain live verification per
`docs/release/release-readiness-go-nogo-record.md`
(RR-PTT-001..006/008) and the DEC-012 legal review; both are
non-engineering work.
|
||
|
|
03f5d6bca3 |
fix(p0): close three P0 coverage gaps after rc.5 audit
Audited every `Priority: P0` row in `docs/requirements/{sysrs,srs}.md`
against the live code. Three items needed work; this commit closes
all three.
Gap A — SysRS-262 + SysRS-282 (screen-reader semantics + accessible
labels for the PTT control)
-------------------------------------------------------------------
The Flutter PTT control is a custom `Listener` over a `Container`
— not a built-in `Button`, so the platform accessibility tree had
no idea it was an interactive control. Screen readers
(VoiceOver, TalkBack, NVDA, Orca) would have read the visible text
without announcing the control role or its toggled state.
Wrap the Listener in a `Semantics(button: true, toggled: _pressed,
label: …, hint: …, excludeSemantics: true)` so the platform
accessibility tree carries the right role, the current state
("Hold to talk" / "Transmitting"), and a usage hint. The
`excludeSemantics: true` argument suppresses the duplicate child
nodes the Container + Row + Icon + Text would otherwise generate
on top of our explicit label.
SysRS-263 (no colour-only state) is preserved: the visible label
and the mic icon already differentiate the two states without
relying on the colour transition.
New ARB key `pttHoldToTalkSemanticsHint` in `app_en.arb` and
`app_zh.arb`.
Gap B — SRS-198 (macOS async permission re-check)
-------------------------------------------------
The macOS backend queried `query_permission()` once at
construction and never re-checked. That violates SRS-198's
"upgrade to the appropriate Global level only after the user
grants the required permission" — once Chanora is running, a
runtime grant must lift the descriptor from `L0Focused` to a
Global level without an app restart.
Substantive rewrite of `crates/chanora_audio/src/ptt_backends/macos.rs`:
* `permission: PermissionState` becomes `permission: Arc<AtomicU8>`,
enabling cross-thread updates without a Mutex.
`PermissionState::{to_u8, from_u8}` carry the encoding.
* The backend owns a `tokio::sync::watch::Sender<PttBackendDescriptor>`
and overrides `DesktopPttBackend::descriptor_watch()` to hand
out subscribers; `chanora_core::ChanoraSession::start_audio`
already forwards transitions to `SessionEvent::PttCapability`.
* `start()` spawns a `chanora-perm-watch` OS thread that polls
`query_permission()` every 1.5 s and republishes the
descriptor on every transition. Polling rather than KVO /
notifications because Input-Monitoring has no public
change-notification API on macOS; 1.5 s is sufficient for a
user grant + return-to-Chanora cycle.
* `rebind()` also republishes the descriptor so a
`keyboard → mouse-side-button` change updates the badge.
* Six new unit tests on the platform-independent
`build_descriptor` and the atomic encoding contract. They
only compile under `target_os = "macos"` (consistent with
the rest of the module), so the Linux dev-host workspace
test count is unchanged.
`query_permission()` itself still returns `Undetermined` until
the IOKit live link lands in the macOS platform-verification
commit; the re-query loop will engage the upgrade path
automatically the moment that function returns real values.
Gap C — SRS-200 (Linux mouse-side-button portal-dependence)
-----------------------------------------------------------
`desktop-ptt-architecture.md` §5.3 already described the
heuristic classifier. Added one explicit sentence stating that
Linux mouse-side-button support is *portal-dependent*: Chanora
never claims a fixed Mouse4/Mouse5 binding on Linux; the portal
decides what inputs it accepts in the current session, and the
classifier degrades to `keyboard` whenever the portal's
description does not contain "mouse". This matches the SRS-200
text verbatim and removes the ambiguity over what "Linux
support follows the portal" means in practice.
Verification
------------
* `cargo test --workspace` (with `CHANORA_DISABLE_KEYRING=1`):
all 67 Linux-side tests green (unchanged). The new macOS
unit tests count under `target_os = "macos"` only — they
will report once the macOS reference host runs `cargo test`.
* `cargo deny check`: advisories ok, bans ok, licenses ok,
sources ok.
* `flutter analyze`: clean (no new accessibility warnings).
* Linux release bundle builds clean.
P0 audit summary
----------------
After this commit every Priority: P0 row in `sysrs.md` and
`srs.md` has a concrete implementation. The remaining open items
are all live verification, not code:
* Per-platform live PTT traces on Windows / macOS reference
hosts (RR-PTT-001..003, RR-PTT-008) — hosts unavailable
locally; queued for platform owners.
* Linux GNOME-Wayland live trace (RR-PTT-004) — implemented
in rc.5; awaiting live host trace.
* Linux non-tested compositor fallback trace (RR-PTT-005) —
Open.
* Diagnostic-export key-leak inspection (RR-PTT-006) — Open
but trivially testable on any host with PTT bound.
* DEC-012 legal review — engineering hand-off complete since
rc.2.
|
||
|
|
82d012a46b |
feat(ptt): live Linux GNOME-Wayland portal session flow (DEC-025)
Promotes the Linux backend from probe-only to a live
`org.freedesktop.portal.GlobalShortcuts` session, closing the
gen2 v0.9.3 baseline's last Linux-side code item. Both gaps I
flagged on the review pass are addressed:
* Stop now closes the portal session through the dedicated
`org.freedesktop.portal.Session` interface (not the
request-cancel `Request` interface — that would only abort a
pending Request, not release the bound shortcuts).
* Ten new unit tests cover `classify_shortcuts_value`,
`publish_bound`, `publish_l0`, and the `SHORTCUT_ID` stability
contract using synthesised `OwnedValue` payloads. Live D-Bus
coverage stays in the `linux_portal_smoke` ignored
integration test (RR-PTT-004).
Live session lifecycle (gen2 Q5b — lazy, single backend instance):
1. `start(gate, binding)` spawns one `tokio::spawn` worker that
owns an async `zbus::Connection` (sharing the bridge's
tokio runtime per Q4a).
2. `CreateSession` with fresh random `handle_token` /
`session_handle_token` tokens. The worker awaits the portal
`Response` signal via a `RequestProxy` subscription and
extracts `session_handle` from the results dict.
3. `BindShortcuts(session_handle, [("chanora-ptt", { description
= "Chanora push-to-talk" })], "", {})`. The portal opens its
own system-managed dialog asking the user to choose a key
— Chanora itself never reads raw key events. The audio
engine continues at `L0Focused` while the dialog is open;
the descriptor watch publishes the transition once the
portal returns.
4. On `response_code == 0`: classify the `trigger_description`
substring (heuristic: contains "mouse" -> MouseSideButton,
else Keyboard), publish `L2GlobalHoldToTalk` (or `L3` for
mouse) through the watch sender. The raw trigger_description
string is never logged (DEC-027 / SRS-202).
5. On `response_code == 1` (cancelled) or `>= 2` (failure):
publish `L0Focused` through the watch sender. The user can
retry via the UI "Configure" button (gen2 Q6a).
6. The worker enters a `tokio::select!` loop multiplexing the
`cmd_rx` channel (Rebind / Stop) and the `Activated` /
`Deactivated` signals. Matching signals scoped to this
session handle and `chanora-ptt` shortcut id drive
`gate.set(true/false)`.
7. `Rebind` re-runs `BindShortcuts` on the same session.
8. `Stop` calls `org.freedesktop.portal.Session.Close()` on
the session-handle object path, clears the gate, exits.
UX (gen2 Q3a): when `_pttBackendId == 'gnome-wayland-portal'`,
the Flutter "Configure" button skips the in-app
`_PttBindingCaptureDialog` and shows a SnackBar telling the user
their desktop environment will open its own shortcut dialog.
The button delegates to `setPttBinding(keyboard, "portal")`
which nudges the backend; the portal handles the rest. New ARB
key `pttConfigurePortalRedirect` in en + zh-Hans.
Trait surface (cross-cutting):
* `DesktopPttBackend::descriptor_watch()` is a new trait method
with a default impl returning a never-firing receiver.
Backends with async capability transitions (only the Linux
portal backend today) override it to return the live watch
sender's receiver.
* `chanora_core::ChanoraSession::start_audio` subscribes to the
active backend's `descriptor_watch()` and spawns a forwarder
task that re-emits `SessionEvent::PttCapability` on every
transition. The initial value is emitted synchronously.
`Cargo.toml` (Linux-only):
* `futures-util` (std features, no executor) for stream
consumption on the portal signal subscriptions.
* `rand 0.8` for fresh per-process portal tokens.
* `zbus` continues at v5 with the `tokio` + `blocking-api`
features.
Tests
-----
* `chanora_audio` rises from 8 to 18 unit tests. New
coverage on the Linux module:
- `classify_returns_none_when_shortcut_id_missing`
- `classify_returns_keyboard_for_typical_trigger_description`
- `classify_returns_keyboard_when_trigger_description_missing`
- `classify_detects_mouse_substring`
- `classify_is_case_insensitive_on_mouse_substring`
- `publish_bound_keyboard_publishes_L2_with_keyboard_class`
- `publish_bound_mouse_publishes_L3`
- `publish_bound_none_publishes_L2_keyboard_default`
- `publish_l0_clears_descriptor`
- `shortcut_id_is_stable`
* Workspace total: 67 unit + integration tests, all green with
`CHANORA_DISABLE_KEYRING=1` (was 57 at v1.0.0-rc.4).
* New `crates/chanora_audio/tests/linux_portal_smoke.rs`
ignored integration test (RR-PTT-004 evidence path). Run on
a GNOME-on-Wayland host with
`cargo test -p chanora_audio --test linux_portal_smoke -- --ignored --nocapture`.
Documentation
-------------
* `docs/architecture/desktop-ptt-architecture.md` §5.3 rewritten
to describe the realised lifecycle; v0.9.4 change-history
entry added.
* `docs/governance/product-decision-register.md` v0.9.10
change-history entry recording the code-side promotion. No
decision rows mutate.
* `docs/release/release-readiness-go-nogo-record.md` RR-PTT-004
flipped from `Open` to `Implemented (live trace pending)`;
v0.9.5 change-history entry.
Verification
------------
* `cargo test --workspace`: 67/67 green.
* `cargo deny check`: advisories ok, bans ok, licenses ok,
sources ok.
* `cargo about generate --offline`: zero new warnings.
* `tools/dump_flutter_licenses.sh`: 94 packages, 0 without
LICENSE.
* `flutter analyze`: clean.
* `cargo build -p chanora_bridge --release` +
`flutter build linux --release`: clean Linux x86_64 bundle.
* Live portal trace (RR-PTT-004) — **not run**. The dev shell
is a TTY without a Wayland session. The user will run the
ignored smoke test from inside a GNOME-on-Wayland session
when available.
No Windows / macOS / iOS live verification in this commit (hosts
unavailable). The Windows + macOS backend scaffolds remain in
place reporting their target capability honestly; live OS-call
wiring is queued for their respective platform owners'
reference hosts per `docs/governance/staged-release-plan.md`.
|
||
|
|
5199e3d005 |
feat(ptt): full desktop backend ladder + missed-key-up watchdog (gen2 v0.9.3 follow-up)
Lands SDD-081..088 + SDD-092 implementations on top of v1.0.0-rc.3.
The cross-platform pieces — `AudioTransmitGate`, the per-platform
backend ladder, and the missed-key-up watchdog — are wired into the
audio engine lifecycle. Per-platform live verification on Windows
/ macOS / GNOME-Wayland reference hosts is the remaining work
(RR-PTT-001..006/008 in `release-readiness-go-nogo-record.md`).
`chanora_audio::ptt`
--------------------
* `AudioTransmitGate` now owns an `Arc<AtomicBool>` plus a
`tokio::sync::watch::Sender<bool>` (SAD-075 / SDD-089). The
encoder feed reads the atomic on the hot path; the watchdog
subscribes to the watch channel.
* `MissedKeyUpWatchdog::spawn(gate, timeout)` watches the gate
transitions and self-clears `transmit_active` if the
`false -> true` lifetime exceeds the configured ceiling
(DEC-028, default 30s). Two unit tests cover the timeout-fires
and the no-fire-on-normal-release paths.
`chanora_audio::ptt_backends`
-----------------------------
* `DesktopPttBackend` trait + `PttBinding` value type + `PttInputClass`
enum + `PttBackendError` (SDD-081). `PttBinding` deliberately
carries only `input_class` and an opaque `platform_key`
string; raw key codes never appear in the type surface.
* `select()` factory (SAD-071): runtime ladder evaluation per
OS. Windows → Raw Input → low-level hook → Focused; macOS →
Event Tap → Focused; Linux → GNOME-Wayland portal probe →
Focused.
* `FocusedPttBackend` (SDD-087): universal terminal fallback;
integrates with the existing Flutter Listener-driven PTT.
* `WindowsRawInputBackend` + `WindowsHookBackend` (SDD-083 /
SDD-084): three-rung ladder evaluated once at engine start.
Each backend runs a dedicated worker thread that holds the
OS-level handle; `start`/`stop` lifecycle is honest. Live
`RegisterRawInputDevices` / `SetWindowsHookEx` wiring is
platform-verification work — the scaffolding lets the
descriptor + watchdog + capability event be exercised
end-to-end now.
* `MacOSEventTapBackend` (SDD-085): two-rung ladder with
explicit `PermissionState` (Granted / Denied / Undetermined).
`Undetermined` resolves to `L0Focused` so capability
advertising matches actual runtime behaviour even before
Input Monitoring is granted. Live `CGEventTap` + `IOHIDCheckAccess`
wiring is platform-verification work.
* `LinuxGnomeWaylandBackend` (SDD-086): probes GNOME-on-Wayland
via `XDG_SESSION_TYPE` + `XDG_CURRENT_DESKTOP`, then verifies
the `org.freedesktop.portal.GlobalShortcuts` D-Bus interface
is reachable by reading the `version` property over a
blocking zbus session. Reports `gnome-wayland-portal` /
`L2GlobalHoldToTalk`. Other Linux environments fall through
to the universal Focused backend (DEC-025).
`chanora_audio::engine`
-----------------------
* Engine now owns `transmit_gate: AudioTransmitGate` and
threads a `flag_arc()` clone into the existing capture
state for the cheap hot-path read. `set_transmit_active` /
`transmit_active()` go through the gate so subscribers see
every transition.
* `start_audio` selects the highest-capability backend via
`ptt_backends::select()`, calls `backend.start(gate, none())`,
and spawns the watchdog. Both are released in `stop()` and
on Drop.
* New `engine.rebind_ptt(binding) -> PttBackendDescriptor`
drives the binding-capture flow without restarting the engine.
* New `engine.ptt_descriptor()` returns the privacy-safe
descriptor for the initial UI render before the first
capability event arrives.
`chanora_core`
--------------
* Re-exports `PttBinding` + `PttInputClass`.
* New `ChanoraSession::set_ptt_binding(binding)` — calls
`audio.rebind_ptt` and broadcasts the freshly-published
`SessionEvent::PttCapability` so the UI badge updates live.
* New `ChanoraSession::ptt_descriptor()` for the initial render.
`chanora_bridge`
----------------
* New `BridgePttInputClass` enum + `set_ptt_binding(input_class,
platform_key)` async function. The `platform_key` string is
opaque to the bridge and never logged.
* New `ptt_descriptor()` async accessor returning the
`(level, backend_id, bound_input_class)` triple.
Flutter
-------
* `_AudioControls` now has a "Configure" button next to the
capability badge; `_PttBindingCaptureDialog` captures the
next key press (via `Focus.onKeyEvent`) or mouse side button
(via `Listener.onPointerDown` filtered to button bitmasks
`0x08` / `0x10`). The captured value is the platform-neutral
`LogicalKeyboardKey.keyLabel` or `mouse-side-button:{button}`.
* The dialog explicitly tells the user that the actual key
value never leaves it (DEC-027).
* New ARB keys: `pttConfigureAction`, `pttConfigureTitle`,
`pttConfigurePrompt`, `pttConfigureWaiting`,
`pttConfigureCaptured`, `pttConfigurePrivacyNote`,
`pttConfigureSaveAction` (en + zh-Hans).
Dependencies
------------
* `chanora_audio` adds (Linux only) `zbus = "5"` with the
`tokio` runtime selector + `blocking-api` feature for the
GlobalShortcuts portal probe.
* `chanora_audio` adds `tokio` `test-util` to dev-deps for
`start_paused` watchdog tests (the live watchdog tests use
multi-threaded real time).
Verification
------------
* `cargo test --workspace` with `CHANORA_DISABLE_KEYRING=1`:
57 tests green (was 53). chanora_audio rises from 4 to 8.
* `cargo deny check`: advisories ok, bans ok, licenses ok,
sources ok.
* `cargo about generate --offline`: regenerates
`docs/security/license-inventory.{md,html}`. The crate count
rises from 364 to 383 with the addition of the zbus tree.
* `tools/dump_flutter_licenses.sh`: 94 packages, zero without
LICENSE (unchanged).
* `flutter analyze`: clean.
* `cargo build -p chanora_bridge --release` + `flutter build
linux --release`: clean Linux x86_64 bundle.
Documentation
-------------
* `docs/release/release-readiness-go-nogo-record.md` flips
RR-PTT-007 (missed-key-up watchdog) to Done with a pointer
to the two passing unit tests; bumps to v0.9.4. Live
per-platform traces (RR-PTT-001..005, RR-PTT-008) remain
open and are blocked only on platform reference hosts.
Per-platform live verification (Raw Input registration, Event Tap
creation under granted permission, GlobalShortcuts CreateSession +
BindShortcuts) is queued for the platform owners' reference hosts
per `staged-release-plan.md`.
|
||
|
|
02ffadfa52 |
docs(ptt): land Baseline Candidate v0.9.3 — capability-based desktop PTT
Applies the gen2 desktop-PTT review summary
(`gen2/chanora-desktop-ptt-review-summary-v0.9.2.md`) to our doc set
with the owner rulings PTT-OPEN-001 through PTT-OPEN-006 resolved as
accepted decisions DEC-023 through DEC-028:
* DEC-023 Windows Global PTT P0 / MVP
* DEC-024 macOS Global PTT P0 / MVP with permission UX
* DEC-025 Linux officially-tested env: GNOME on Wayland only
* DEC-026 Mouse side buttons supported (Win + macOS; Linux portal)
* DEC-027 PTT diagnostics: capability + availability only, no
raw key codes ever
* DEC-028 Missed-key-up watchdog: P0
Requirements (SysRS / SRS) and architecture (SysDes / SAD / SDD)
gain the desktop-PTT ID set the gen2 summary describes:
SysRS-296..302 -> SysDes-142..148
-> SRS-195..203
-> SAD-071..079
-> SDD-081..092
ID totals advance from 295 / 141 / 194 / 70 / 80 to 302 / 148 / 203
/ 79 / 92. The strict layered sourcing rule (`SRS -> SysDes` only,
`SAD -> SRS` only, `SDD -> SAD` only) is preserved; the
`tools/validate_docs.py` validator reports zero undefined refs and
zero direct-layer-rule violations.
New document:
* `docs/architecture/desktop-ptt-architecture.md` — capability
ladder (L0Focused, L1GlobalShortcut, L2GlobalHoldToTalk,
L3GlobalWithMouseButtons, L4DeviceAware reserved), Windows /
macOS / Linux strategies, privacy rule, audio-gate rule,
missed-key-up watchdog, release-readiness evidence requirement,
traceability summary.
Doc addenda (Baseline Candidate 0.9.3):
* `privacy/privacy-policy.md` — no raw key history, capability-
dependent Global PTT, UI reflects actual runtime capability
* `security/threat-model.md` — THREAT-PTT-001..006
* `security/diagnostic-redaction-audit-report.md` —
REDACT-PTT-001..006 banned field list enforced by `PttSanitizer`
* `release/platform-release-policy.md` — per-platform evidence
fields, no over-claim on untested Linux compositors
* `release/release-readiness-go-nogo-record.md` — RR-PTT-001..008
release-readiness items
* `verification/swe4-unit-verification-plan.md` —
SWE4-UV-035..039
* `verification/swe5-software-integration-verification-plan.md` —
SWE5-IV-015
* `verification/swe6-software-verification-plan.md` — SWE6-SV-017
* `verification/sys4-system-integration-verification-plan.md` —
SYS4-SIV-016
* `governance/traceability-matrix.md` — full PTT trace rows +
verification map
* `governance/decision-impact-assessment.md` — DEC-023..028
impact matrix
* `governance/product-decision-register.md` v0.9.9 entry
recording DEC-023..028 in the decision table and the status
table at §7
* `governance/document-index.md` — adds
`desktop-ptt-architecture.md` to the controlled set
* `architecture/proof-of-concept-plan.md` —
PoC-PTT-001..005 platform items
* `references/external-references.md` — Windows Raw Input,
macOS event-tap, Linux GlobalShortcuts portal references
* Both validation reports
(`baseline-candidate-validation-report.md`,
`repo-format-validation-report.md`) bumped to v0.9.3 with the
new ID totals (302 / 148 / 203 / 79 / 92).
README §"Desktop Push-to-Talk" added between Architecture Overview
and Repository Layout: capability levels, per-platform strategy,
privacy posture, missed-key-up watchdog.
Tooling:
* `tools/validate_docs.py` copied from the gen2 zip into the
repo tree (was previously available only inside the zip).
Reports zero undefined refs, zero direct-layer-rule violations,
English-only CJK check passes. The 35 "old package-style
filename" hits are pre-existing and identical to the gen2
baseline (they live in `path-migration-map.md` and config-ID
headers of governance docs and are intentional per the path
migration policy).
* `.gitignore` adds `/gen2/` so the externally-provided review
package does not enter the repo.
No code changes in this commit; B (the implementation split into
`transmit_active` / `capture_active`, `PttCapabilityLevel`
reporting, `PttSanitizer` diagnostics rule, and the UI capability
badge) follows in a separate commit.
|
||
|
|
b932dc1405 |
feat(legal): land cargo-about + cargo-deny + Flutter license inventory
Closes engineering deliverables 1–3 from the open-work table in `docs/governance/legal-review-readiness.md` so the DEC-012 legal review can actually run. With this commit, the only remaining engineering item blocking sign-off is signed Windows / macOS / iOS build artefacts, deferrable per the DEC-002 staged release plan. Tooling ------- * `about.toml` + `about.hbs` + `about-md.hbs` configure cargo-about with the DEC-020 license posture and the five-target matrix (Linux, Android, Windows, macOS, iOS). One per-crate clarification for `allo-isolate` (`flutter_rust_bridge` transitive that ships Apache-2.0 via `license-file` rather than an SPDX `license` field). `cargo about generate` runs with zero warnings. * `deny.toml` mirrors the cargo-about allow-list and adds minimal bans / sources / advisories config. `cargo deny check` reports `advisories ok, bans ok, licenses ok, sources ok` for the workspace; multiple-versions of `windows_x86_64_msvc` produce advisory `warn` (no fail) because three windows-targets versions reach the graph via `jni`, `cpal`, and `keyring` respectively. * `tools/dump_flutter_licenses.sh` + `tools/dump_flutter_licenses.dart` walk `apps/chanora_flutter/pubspec.lock`, resolve each dependency to its local pub-cache directory, read the LICENSE file, and emit `docs/security/flutter-license-inventory.md`. SDK-sourced packages (`flutter`, `flutter_localizations`, `flutter_test`, `flutter_web_plugins`, `sky_engine`) resolve to the Flutter framework BSD-3-Clause LICENSE under `$FLUTTER_ROOT` (or `$HOME/sdks/flutter`). Artefacts --------- * `docs/security/license-inventory.md` — 364 transitive Rust crates with full license texts. Apache-2.0 (276), MIT (55), Unicode-3.0 (19), BSD-3-Clause (7), ISC (7). Zero copyleft. * `docs/security/license-inventory.html` — same data rendered as styled HTML for reviewer convenience. * `docs/security/flutter-license-inventory.md` — 94 Dart / Flutter packages with their LICENSE texts. Zero packages without a resolvable LICENSE in this RC. CI -- * New `supply-chain` job runs `cargo deny check --workspace --all-features` via `EmbarkStudios/cargo-deny-action@v2`. Fails the build on any GPL / LGPL / AGPL / commercial-source license surfacing transitively. * New `license-inventory` job installs `cargo-about --features cli` and regenerates `docs/security/license-inventory.md`; diffs against the committed copy and fails on drift. Forces contributors who touch the Cargo.lock to refresh the inventory. * New `flutter-license-inventory` job runs `tools/dump_flutter_licenses.sh` against the just-resolved pub cache; same diff-on-drift semantics. Governance ---------- * `docs/governance/legal-review-readiness.md` §5 cross-links the three new artefacts in a "Reviewer artefacts" subsection. * The open-work table at the bottom of the doc is rewritten as a status grid: items 1–3 now read **Done**; item 4 (signed iOS / macOS builds) remains the only open engineering blocker, with a pointer back to `staged-release-plan.md`. Verification ------------ * `CHANORA_DISABLE_KEYRING=1 cargo test --workspace`: all 49 unit + integration tests green (unchanged from v1.0.0-rc.1). * `cargo deny check`: advisories ok, bans ok, licenses ok, sources ok. * `cargo about generate --output-file …`: zero warnings. * `tools/dump_flutter_licenses.sh`: 94 packages, 0 without LICENSE. * `flutter analyze`: clean. No code changes touch the runtime; this is governance-tooling only. |
||
|
|
50768a8f48 |
feat(mvp): v1.0.0-rc.1 — keyring-backed DEK, encrypted bookmarks, MVP release-gate docs
Closes the v0.4 dual-file weakness in identity-at-rest and turns the release into an MVP public release candidate. 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`. No decision rows in `product-decision-register.md` change; the register's change-history advances to 0.9.8. `chanora_storage` ----------------- * New public `Crypto` trait + `IdentityFileStore::crypto()` give callers an encrypt / decrypt pair anchored on the per-install 32-byte DEK without exposing the key material. * `IdentityFileStore` keyring-first DEK retrieval (Linux Secret Service via D-Bus, macOS Keychain, Windows Credential Manager, iOS Keychain via the `keyring` crate). Pre-existing `identity.dek` files are opportunistically migrated into the keyring on first run; the on-disk DEK copy is removed once the keyring acknowledges. `CHANORA_DISABLE_KEYRING=1` forces the file-fallback path for tests and headless / CI hosts where a real keyring call would prompt the user or block on a missing D-Bus session. * `BookmarkRepository::with_crypto(dir, crypto)` encrypts the server password into a new `password_blob` BLOB column under the same per-install DEK. Schema v2 migration is idempotent — legacy v0.4 rows with a plain `password TEXT` are read transparently and lifted into `password_blob` on the next `update()`. `BookmarkRepository::new` (no crypto) is preserved for tests and as a documented fallback when the DEK is unreachable. * Storage tests rise from 8 to 10: encrypted bookmark password round-trip + legacy-plaintext-bookmark upgrade. `chanora_core` -------------- * `ChanoraSession::init_storage(dir)` wires the bookmark repository with crypto by default. On any crypto-derivation failure it falls back to the plain-password repository and logs the gap — better than hard-failing init. * `supervisor_loop` now tracks a 64-bit `snapshot_signature` over channels (id + parent + order + name) and clients (id + channel + name) instead of the old `(channel_count, client_count)` tuple. Any in-channel client move, channel rename, or reorder now fires `SessionEvent::SnapshotChanged`. The signature sorts by id before hashing so it's stable under input-vector reordering. * Two new unit tests cover the signature behaviour; new `tests/mvp_storage.rs` integration test drives `ChanoraSession::init_storage` end-to-end and verifies the bookmark `password_blob` does not contain the plaintext. * Re-export `ChannelId` + `ClientId` from `chanora_protocol` so downstream callers and tests can construct DTOs directly. Flutter ------- * New About dialog (info icon in the AppBar) surfaces DEC-018 (public name "Chanora"), DEC-019 (non-affiliation statement), and DEC-020 (Apache-2.0 OR MIT dual license). New ARB keys in `app_en.arb` and `app_zh.arb`: `aboutAction`, `aboutVersion`, `aboutNonAffiliation`, `aboutLicenseHeading`, `aboutLicenseBody`, `aboutThirdPartyHeading`, `aboutThirdPartyBody`. * `pubspec.yaml` version bumps to `1.0.0-rc.1+5`. Governance ---------- * `docs/governance/legal-review-readiness.md` — DEC-012 handoff package. Enumerates trademark / non-affiliation / license-text / third-party-attribution / `tsclientlib`-posture / crypto- export / data-handling items the legal reviewer must confirm, and lists the concrete engineering deliverables they block on (`cargo about generate`, `cargo deny check licenses`, Flutter `LicenseRegistry` dump). * `docs/governance/staged-release-plan.md` — DEC-002 channel schedule. Linux + Android sideload promote to GA on DEC-012 sign-off; Play Store / Windows / macOS / iOS gate on per- platform signed-build availability. Rollback policy included. * `product-decision-register.md` change-history advances to 0.9.8 with a single entry summarising v0.3, v0.4, and v1.0-rc.1 progress against DEC-001. No decision rows mutate. Build + ops ----------- * `NOTICE` refreshed for the MVP product-code dependency set: adds `chacha20poly1305`, `rand`, `zeroize`, `base64`, `keyring`, `connectivity_plus`, `path_provider`, `freezed_annotation`; drops PoC-only entries. * `CHANGELOG.md` restructured: explicit version sections for v0.3.0-beta.1, v0.4.0-beta.2, v1.0.0-rc.1. Previous "Unreleased" contents migrated into their respective milestone sections. * `.github/workflows/ci.yml` exports `CHANORA_DISABLE_KEYRING=1` for the cargo-test job — CI runners have no D-Bus session and the keyring crate would otherwise block. * `run-chanora.sh` reads `CHANORA_BUNDLE_FLAVOUR` (default `release`) and self-copies the latest cdylib into the bundle's `lib/` if missing. Verification ------------ * `cargo test --workspace` with `CHANORA_DISABLE_KEYRING=1`: all green (49 unit tests across the workspace; up from 36 at v0.4.0-beta.2). * `cargo test -p chanora_core --release -- --ignored alpha_smoke` passes against the live `cn.teamspeak.app` (DNS → connect → snapshot → disconnect in ~2.5 s). * `flutter analyze`: clean. * `cargo build -p chanora_bridge --release` + `flutter build linux --release` produce a working Linux x86_64 bundle. No Android live test in this commit per the user's note that the physical device was removed; the Android arm64-v8a build path is mechanically identical to v0.4.0-beta.2. |
||
|
|
1324f478fe |
docs(release): add iOS build instructions + shell helper
The development host is Linux x86_64; the iOS toolchain (Xcode, xcrun,
codesign, iPhoneOS SDK) is macOS-only under Apple licence and cannot
be cross-compiled from Linux. This commit adds the instructions for
producing the iOS v0.2.0-beta.1 build on a macOS host plus a bash
helper that automates the build itself.
docs/release/ios-build.md (v0.1.0):
- Toolchain pin table (macOS 14+, Xcode 26+ per DEC-021, iOS SDK
26+, iOS deployment target 13.0 per DEC-003, Flutter 3.41.9,
Rust 1.95 stable with aarch64-apple-ios / aarch64-apple-ios-sim /
x86_64-apple-ios targets, CocoaPods 1.16+, FRB 2.12.0).
- macOS host options: owned hardware vs rental (MacStadium,
MacinCloud, Scaleway Apple silicon, AWS EC2 Mac) vs borrowed
Mac. Realistic cost ranges per option.
- Step-by-step Homebrew + Rust + Flutter + CocoaPods install.
- Pre-built libopus.a per arch via a CMake invocation that
targets the iOS SDK explicitly. Mirrors the Android build's
LIBOPUS_LIB_DIR wrap-dir trick.
- flutter create --platforms=ios to scaffold the ios/ folder
(the product Flutter app was created with only linux + android).
- Edits required to ios/Podfile and ios/Runner/Info.plist:
iOS 13 deployment target (DEC-003), NSMicrophoneUsageDescription
for the audio engine, UIBackgroundModes=audio for screen-locked
playback.
- Three cargo build --target invocations for device + both
simulator slices.
- lipo merge of the two simulator slices into one .a.
- xcodebuild -create-xcframework to produce
target/ChanoraBridge.xcframework with the right slices.
- flutter build ios --release --no-codesign or
flutter build ipa --release --export-method development for
a signed .ipa.
- Install paths: xcrun devicectl for wired install, altool for
TestFlight upload.
- Smoke-test instructions with the same hostname-resolution
caveat that affects the Android Beta (hickory-resolver does
not work on iOS; use the literal IP).
- Packaging into chanora-v0.2.0-beta.1-ios.ipa.
- Known-issue table covering: audiopus_sys cmake build failures
on iOS, microphone permission prompt prerequisites,
AVAudioSession category quirks for voice transmission, code-
signing failure modes, TestFlight rejection causes.
- Reproducibility note (build is not bit-reproducible).
tools/build-ios.sh:
- Parameter switches: --version, --no-codesign,
--regenerate-bindings, --export-method.
- Verifies xcodebuild, xcrun, cargo, rustc, flutter, pod, lipo
on PATH.
- Adds the three rustup iOS targets if missing.
- Verifies each pre-built libopus.a exists at the expected wrap
dir before starting.
- Optionally regenerates FRB bindings.
- Three cargo build runs (device + Apple-silicon sim + Intel
sim), each with LIBOPUS_LIB_DIR pointed at its arch's wrap dir
and the audiopus_sys build-cache wiped per target.
- lipo + xcodebuild -create-xcframework.
- flutter pub get + pod install + flutter build {ios,ipa}.
- Copies the .ipa to a versioned path under $HOME and prints
SHA-256.
This is documentation + helper only; no actual iOS binaries are
produced by this commit. The Linux development host cannot run
Xcode. To produce the binaries, follow §3-§14 of
docs/release/ios-build.md on a macOS host, or run
tools/build-ios.sh there.
DEC-011.1 iOS audio status remains Deferred; the doc notes that
cpal's iOS backend has not been empirically verified and the
AVAudioSession category likely needs configuration for voice
transmission. Both are Beta+ items.
|
||
|
|
8094ec7277 |
docs(release): add Windows build instructions + PowerShell helper
The development host is Linux x86_64; `flutter build windows` cannot
be cross-compiled and requires a Windows host with Visual Studio
2022's C++ Desktop workload. This commit adds the instructions for
producing the Windows v0.2.0-beta.1 Internal Beta build on an Azure
VM, plus a PowerShell helper that automates the build itself.
docs/release/windows-build.md (v0.1.0):
- Toolchain pin table (Windows Server 2022, VS 2022 Build Tools
+ C++ workload, Flutter 3.41.9, Rust 1.95 stable, FRB 2.12.0,
CMake, audiopus build dependency).
- Azure VM provisioning recipe: Standard_D4s_v5 (4 vCPU / 16 GiB),
Premium SSD 128 GiB, RDP locked to caller IP, auto-shutdown,
cost estimate (<USD 1 per build session).
- Step-by-step PowerShell to install VS 2022 Build Tools with the
required components, Git for Windows, rustup, Flutter SDK,
flutter_rust_bridge_codegen, and CMake.
- Two upload paths for source: temporary git remote OR zip archive
over RDP clipboard.
- flutter create --platforms=windows to scaffold the
windows/ platform folder (the product Flutter app was created
with only linux + android).
- cargo build -p chanora_bridge to produce chanora_bridge.dll.
- flutter build windows --release to produce chanora_flutter.exe
and the bundle.
- Drop the DLL next to the EXE so dart:ffi loads it.
- Smoke-test instructions including the cn.teamspeak.app UDP 9987
egress gotcha for some Azure regions.
- Packaging into chanora-v0.2.0-beta.1-windows-x64.zip.
- Known-issue / caveat table.
- Reproducibility note (build is not bit-reproducible in this Beta).
tools/build-windows.ps1:
- Parameter switches: -SkipRustBuild, -RegenerateBindings, -Version.
- Verifies flutter, cargo, rustc, cmake, git on PATH.
- Adds the x86_64-pc-windows-msvc target via rustup if missing.
- Runs flutter create --platforms=windows if the windows/ folder
is absent in apps/chanora_flutter/.
- Optionally regenerates FRB bindings.
- cargo build --release -p chanora_bridge --target x86_64-pc-windows-msvc.
- flutter pub get + flutter build windows --release.
- Copies the DLL into the Release bundle.
- Compress-Archive into chanora-<version>-windows-x64.zip.
- Prints final artefact paths.
This is documentation + helper only; no actual Windows binaries are
produced by this commit. To produce the binaries, follow §3-§13 of
docs/release/windows-build.md on a Windows host.
|
||
|
|
9790005c3e |
feat(beta): wire voice in/out end-to-end with push-to-talk (v0.2.0-beta.1)
Reaches the Internal Beta milestone of DEC-001's release sequence the
same day as Alpha. Adds voice capture and playback through the full
Flutter UI → FRB → Rust core → tsclientlib → server path.
Promotions from PoC:
poc/audio-capture-playback-spike → crates/chanora_audio/
New product code:
crates/chanora_audio/src/engine.rs — cpal capture and playback,
audiopus Opus VoIP encoder (48 kHz mono 20 ms frames), tsclientlib
AudioHandler for decode + jitter buffer + mix on playback,
push-to-talk gate, graceful playback-only fallback when capture
is unavailable.
crates/chanora_protocol/src/adapter.rs — extended with
voice_out_tx (clonable mpsc::Sender<OutPacket>) and
take_voice_in() (one-shot mpsc::Receiver<InboundVoice>); main
loop now interleaves outbound voice drain, event pumping, and
control-request handling.
crates/chanora_protocol/src/lib.rs — re-exports the few
tsproto_packets types (OutAudio, OutPacket, InAudioBuf,
AudioData, CodecType, Direction) that chanora_audio
legitimately needs. Documented as the single deliberate
cross-crate type re-export per SAD-067, justified by the
performance cost of a parallel type hierarchy on the 20 ms
voice frame.
core/chanora_core/src/lib.rs — ChanoraSession::start_audio,
set_ptt, audio_stats; disconnect now stops the engine first.
crates/chanora_bridge/src/api.rs — startAudio, setPtt,
audioStats commands and BridgeAudioStats DTO.
apps/chanora_flutter/lib/main.dart — "Start audio" button +
hold-to-talk PTT button with pressed/released visual state +
live stats line (TX/RX/PTT). Stats polled every 500 ms.
ARB:
Both en and zh-Hans gain startAudioAction, pttHoldToTalk,
pttTransmitting, audioStatsLine. Banner updated to
"Beta build — voice in/out wired; not production ready."
FRB config:
flutter_rust_bridge.yaml gains local: true so codegen resolves
the workspace member's library stem to "chanora_bridge" instead
of falling back to "UNKNOWN".
Empirical verification (2026-05-14, against cn.teamspeak.app):
cargo check + cargo test --workspace: all green.
flutter analyze: 0 issues.
flutter test: 4/4 passing including:
- test/alpha_e2e_test.dart (regression: Alpha still works)
- test/beta_e2e_test.dart (Beta: connect → startAudio →
PTT cycle → disconnect against cn.teamspeak.app).
Live smoke (cargo test alpha_smoke -- --ignored): 49 channels,
37 clients retrieved.
Capture stream open against the host PipeWire auto_null source
refused (snd_pcm_hw_params); engine correctly logged the warning
and continued in playback-only mode. TX=0 frames, RX=0 frames
reflects the headless null-source environment; on a real mic
host the encoder produces ~50 frames/second while PTT is held.
Honest Beta scope (NOT in this release):
- AEC / AGC / NS / HPF DSP (DEC-007..010): AudioEffects exists
as a struct but the filters are no-ops. Beta+ work.
- Production-quality resampler: current code is linear
interpolation. Beta+ work.
- Identity persistence via chanora_storage: still ephemeral.
- Push-to-Dart event stream: UI polls instead.
- chanora_diagnostics tracing-layer wiring: still scaffold.
- Mobile (Android) cdylib + UI: PoC-proven, not yet in product.
- Reconnect / network-loss recovery for the voice path.
Docs updates:
- docs/governance/product-decision-register.md bumped to v0.9.7
(Beta-milestone change-history entry; no row changes).
- docs/governance/poc-results-summary.md bumped to v0.6.0
(RISK-PoC-005 updated with Beta progress).
|
||
|
|
53b176b722 |
docs(governance): record Alpha milestone in PoC results summary (v0.5.0)
Updates RISK-PoC-005 to 'partially closed' and adds a v0.5.0 change
history entry documenting:
- the tsclientlib spike promotion into crates/chanora_protocol;
- the typed ChanoraSession in core/chanora_core wiring the
protocol API;
- the FRB 2.12.0 bridge wiring;
- the Flutter Alpha UI;
- the empirical verification path through alpha_e2e_test.dart
and alpha_smoke.rs;
- the v0.1.0-alpha.1 tag pointing at commit 3bb038c.
No other doc bumps are needed: the decision register stays at v0.9.6
(no new decisions), the audit reports stay at v0.9.3 (no new audit
evidence beyond what the PoCs already provided), the PoC plan stays
at v0.3.0 (all six PoC entries were already PASS).
|
||
|
|
e0f34009d9 |
docs(governance): record product scaffolding paths (DEC-022)
Updates two documents to reflect the workspace + Flutter app
scaffold landed in the previous commit.
path-migration-map.md v0.9.2 -> v0.9.3:
Adds §3 Implementation Path Layout. Lists each subsystem's
canonical crate path alongside its SAD / SysDes / DEC authority.
Notes that the Flutter app is owned by Flutter tooling and is
not a Cargo workspace member.
CHANGELOG entry under [Unreleased]:
- Documents the seven new Cargo workspace members and the
invariants pinned at the workspace level.
- Documents the Flutter app scaffold, the DEC-004 minSdk = 28
override, and the DEC-015 English + Simplified Chinese ARB
catalogue (with the ADR-008 server-content reaffirmation).
- Records the empirical verification (cargo check + cargo test
+ flutter analyze + flutter test all clean).
|