Files
chanora/docs/governance/product-decision-register.md
T
EdisonJwa 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).
2026-05-16 01:04:40 +08:00

224 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CHANORA_CFG_Product_Decision_Register_v0.9.7.0.0
**Document type:** Configuration / Product Decision Register
**Version:** 0.9.7
**Status:** Baseline Candidate
**Language:** English
**Product:** Chanora
**Repo path:** `docs/governance/product-decision-register.md` ---
## 1. Purpose
This document records key product, architecture, release, legal, and engineering decisions that affect Chanora scope, testing, architecture, app store eligibility, and release readiness.
A decision marked **Proposed / Owner Confirmation Required** is a recommended decision that should be confirmed by the owner before Final / Approved Baseline.
## 2. Decision Status Legend
| Status | Meaning |
|---|---|
| Proposed / Owner Confirmation Required | Recommended decision; owner must confirm before Final. |
| Accepted | Confirmed and part of baseline. |
| Deferred | Not decided for this release; must not block scope if explicitly deferred. |
| Rejected | Not selected. |
## 3. Key Blocking Decisions
| Decision ID | Decision | Recommended decision | Status | Owner | Why it matters |
|---|---|---|---|---|---|
| DEC-001 | Release type | Internal Alpha first, then External Beta, then MVP Public / Store Release | Accepted | Product Owner | Controls release gate, verification bar, legal/privacy requirements, and platform scope. |
| DEC-002 | MVP platform scope | MVP target remains Windows, macOS, Linux, Android, and iOS; first release may be staged by channel/platform | Accepted | Product Owner + Engineering Owner | Controls verification matrix, build artifacts, store readiness, and support load. |
| DEC-003 | Minimum iOS version | iOS 13 minimum for Flutter support baseline; test latest iOS release separately | Accepted | Product Owner + iOS Owner | Controls iOS compatibility, test devices, and app store eligibility. |
| DEC-004 | Minimum Android version | **Android API 28 (Android 9.0)** minimum, raised from the original recommendation of API 24 by explicit owner ruling on 2026-05-14. Rationale: simplifies the audio path (AAudio is unconditionally available from API 26+ and stable from API 28), narrows the TLS / privacy / scoped-storage compatibility surface, and matches typical 2026 Android baselines. The cpal-on-Oboe Android spike was built with `minSdk = 24` and `cargo-ndk -P 26`; product code in `apps/chanora_flutter` must move `minSdk` to 28 and may simplify the AAudio-vs-OpenSL-ES fallback logic accordingly. | Accepted | Product Owner + Android Owner | Controls Android device support, runtime permissions, and Play Store eligibility. |
| DEC-005 | Android target SDK | Target the Google Play-required API level on the upload date; current release gate uses API 35+ unless newer Google policy applies | Accepted | Android Owner + Release Manager | Required for new apps and updates submitted to Google Play after the current policy date. |
| DEC-006 | Multiple server connections in MVP | Not in MVP; support one active server connection per client instance | Accepted | Product Owner + Software Architect | Reduces state synchronization, audio routing, UI complexity, and verification scope. |
| DEC-007 | AEC default state | Enabled by default on platforms/audio backends where supported and stable | Accepted | Audio Owner + Product Owner | Affects echo quality, CPU usage, platform behavior, and user experience. |
| DEC-008 | AGC default state | Enabled by default, with user setting to disable | Accepted | Audio Owner + Product Owner | Affects perceived loudness consistency and may affect advanced user preference. |
| DEC-009 | Noise suppression default state | Enabled by default, with user setting to disable | Accepted | Audio Owner + Product Owner | Improves typical voice quality but may affect voice naturalness and CPU usage. |
| DEC-010 | High-pass filter default state | Enabled by default | Accepted | Audio Owner | Removes low-frequency rumble and usually improves speech capture. |
| DEC-011 | Audio processing implementation path | Use platform-native audio processing first where available; use Rust/WebRTC-style processing as controlled fallback or later architecture option | Accepted | Software Architect + Audio Owner | Controls architecture, latency, CPU use, platform compatibility, and testing. |
| DEC-011.1 | Audio crate choice | `cpal` for desktop (empirically verified on Linux/PipeWire by `poc/audio-capture-playback-spike` on 2026-05-13) and for Android (cpal-on-Oboe, empirically verified on a Motorola Moto G Stylus 5G (2023) running Android 14 arm64-v8a by `poc/audio-capture-playback-android-spike` on 2026-05-13); iOS crate TBD pending an iOS spike that requires macOS + Xcode hardware | Accepted (desktop + Android) / Deferred (iOS) | Software Architect + Audio Owner | Pins the desktop and Android audio dependencies; iOS remains an open risk surface. |
| DEC-012 | Official SDK / trademark / licensing review | Public/store release is blocked until legal confirms TeamSpeak non-affiliation wording, trademark usage, OSS licenses, and `tsclientlib` license posture | Accepted (as a release gate) | Legal / Compliance + Product Owner | Public release risk and store metadata risk. Owner accepted the gate on 2026-05-14; the legal review itself is still to be performed and remains a public-release blocker. |
| DEC-013 | Local database choice | Use SQLite or equivalent embedded local database for non-secret local state; secrets remain in platform secure storage | Accepted | Software Architect + Storage Owner | Controls storage schema, migrations, backup/delete policy, and portability. |
| DEC-013.1 | SQLite crate | `rusqlite` with the `bundled` feature (SQLite statically linked into the binary; no system libsqlite3 dependency); verified by `poc/sqlite-storage-spike` on 2026-05-13 | Accepted | Software Architect + Storage Owner | Pins the embedded-DB dependency; locks reproducibility. |
| DEC-013.2 | Linux secure-storage backend policy | Prefer Secret Service (libsecret / gnome-keyring / kwallet / KeePassXC) on Linux; if the default collection is locked or D-Bus is unavailable, fall back to kernel keyutils with a clear user notice. Both backends are "equivalent" per SysRS-053 / SysRS-162; verified by `poc/secure-storage-spike` on 2026-05-13 | Accepted | Software Architect + Storage Owner + Security Reviewer | Closes the SysRS-162 ambiguity surfaced by the secure-storage PoC. |
| DEC-014 | Bridge choice | Use a stable typed Flutter/Rust bridge with generated or schema-controlled DTOs; **`flutter_rust_bridge` 2.x pinned** (empirically verified at 2.12.0 by `poc/flutter_rust_bridge_hello` on 2026-05-13) | Accepted | Software Architect | Controls API stability, maintainability, async event flow, and long-term code generation. |
| DEC-015 | Product language for MVP | **English + Chinese (Simplified) for MVP**, raised from the original recommendation of English-only by explicit owner ruling on 2026-05-14. Rationale: the demonstrated test-server population (verified live against `cn.teamspeak.app`) and broader TS3 audience include substantial Chinese-speaking users; shipping zh-Hans alongside en at MVP avoids a launch-window UX gap. Architecture remains i18n-ready so additional languages can be added later mechanically. Server-provided content is preserved verbatim and never translated (ADR-008 UTF-8 boundary, DEC-015 server-content rule retained). | Accepted | Product Owner | Controls localization scope and release schedule. |
| DEC-016 | Diagnostics upload policy | No automatic upload for MVP; user-initiated local diagnostic export only | Accepted | Product Owner + Legal + Security | Controls privacy policy, support workflow, and security review scope. |
| DEC-017 | Crash reporting | Disabled for MVP unless explicit opt-in provider and privacy policy are approved | Accepted | Product Owner + Legal + Security | Avoids privacy/legal complexity before public release. |
| DEC-018 | Public product name | Chanora | Accepted | Product Owner | Branding and legal identity. Trademark / registrability check remains under DEC-012 legal review before public release. |
| DEC-019 | Public non-affiliation statement | Use legal-approved wording; drafted text accepted as working copy: "Chanora is independent and is not affiliated with, endorsed by, sponsored by, or officially associated with TeamSpeak." Subject to final legal review under DEC-012 before public release. | Accepted (drafted wording) | Legal / Compliance | Required for public release and store metadata. |
| DEC-021 | Apple App Store submission SDK | Use Xcode 26 or later and the iOS 26 / iPadOS 26 SDK or later for App Store submission on or after 2026-04-28, unless Apple publishes a newer applicable requirement before upload | Accepted | iOS Owner + Release Manager | Controls App Store Connect upload eligibility and release pipeline. |
| DEC-020 | License model | **Dual-licensed under Apache-2.0 OR MIT (recipient's choice)**, the standard Rust-ecosystem permissive license model. Accepted on 2026-05-14. Compatible with every direct dependency in the PoC tree (`tsclientlib` MIT-OR-Apache-2.0, `flutter_rust_bridge` MIT, `cpal` Apache-2.0, `rusqlite` MIT, `keyring` MIT-OR-Apache-2.0, etc.) and with the Flutter framework's BSD-3-Clause. The license texts ship as `LICENSE-APACHE` and `LICENSE-MIT` at the repository root; an aggregator `LICENSE` points to both. `NOTICE` enumerates current direct-dependency attributions. The full OSS legal review (transitive deps, license obligations, OSS notices) remains under DEC-012 and is still required before public release. | Accepted | Product Owner + Legal | Business and OSS compliance decision. No longer a public-release blocker by itself; legal review under DEC-012 is the remaining gate. |
| DEC-022 | Canonical implementation directory layout | Accept the README's sketch as canonical: `apps/chanora_flutter/`, `core/chanora_core/`, `crates/chanora_protocol/`, `crates/chanora_audio/`, `crates/chanora_state/`, `crates/chanora_storage/`, `crates/chanora_diagnostics/`, `crates/chanora_bridge/`. Matches SAD §7.2 module decomposition | Accepted | Software Architect | Unblocks product-crate scaffolding; was not formalised by any prior doc. |
| DEC-023 | Windows desktop Global PTT priority | **P0 in MVP.** Resolves PTT-OPEN-001 from `gen2/chanora-desktop-ptt-review-summary-v0.9.2.md`. The Windows backend ladder (Raw Input → low-level keyboard hook → Focused fallback) is mandatory for the first public release; release notes shall not claim Global PTT support on Windows until live measurement confirms a Global level from a non-fallback rung. | Accepted | Product Owner + Windows Platform Owner | Sets the MVP commitment level for the most common desktop platform. |
| DEC-024 | macOS desktop Global PTT priority | **P0 in MVP, with explicit permission UX flow.** Resolves PTT-OPEN-002. The macOS backend shall request the Input Monitoring / Accessibility permission, accept user denial gracefully (continue at `L0Focused` without functional regression), and upgrade to Global asynchronously when the user grants the permission. | Accepted | Product Owner + macOS Platform Owner | Forces the permission UX to ship with the rest of the macOS audio path rather than as a follow-up. |
| DEC-025 | Officially-tested Linux environment for first public release | **GNOME on Wayland (only).** Resolves PTT-OPEN-003. The Linux backend shall use the freedesktop `org.freedesktop.portal.GlobalShortcuts` interface on GNOME-on-Wayland and fall back to Focused PTT on every other Linux environment (X11, sway, KDE, untested compositors). Release notes shall not claim Global PTT support outside the tested compositor. | Accepted | Product Owner + Linux Platform Owner | Bounds the verification matrix; honest claim on Linux. |
| DEC-026 | Mouse side-button support in first desktop PTT release | **Supported on Windows and macOS; Linux follows whatever the GlobalShortcuts portal exposes.** Resolves PTT-OPEN-004. The Raw Input backend (Windows) and the Event Tap backend (macOS) shall accept Mouse4 / Mouse5 bindings; the Linux portal binding accepts whatever the session exposes and the release notes shall not over-claim. | Accepted | Product Owner + UX Owner | Common dedicated PTT input class; shipping in MVP avoids a follow-up. |
| DEC-027 | PTT diagnostics privacy posture | **Capability and availability state only — no raw key codes ever leave the device.** Resolves PTT-OPEN-005. The diagnostic export shall name only `PttCapabilityLevel`, `backend_id`, `bound_input_class`, and `fallback_exercised`; the user's actual key value (scan code, virtual key, keysym) shall never be logged, persisted, or exported. `PttSanitizer` enforces this at write time. | Accepted | Security Reviewer + Privacy Reviewer | Closes a clear privacy risk that the gen2 review flagged; aligns with DEC-016. |
| DEC-028 | Missed-key-up watchdog requirement | **P0.** Resolves PTT-OPEN-006. The audio engine shall include a missed-key-up watchdog that clears `transmit_active` after a configured ceiling (default 30 s) when no key-up event arrives. The watchdog is a P0 release-gate item rather than an implementation-level concern because the failure mode (stuck transmission after the user has released the binding) is user-visible and reputation-relevant. | Accepted | Audio Owner + Software Architect | Prevents stuck-PTT bug class regardless of platform-input quirks. |
| DEC-029 | Flutter global-hotkey packages rejected for PTT | **Use the native Rust `DesktopPttBackend` trait + per-OS implementations (already specified in SDD-083 / SDD-084 / SDD-085); do not adopt `hotkey_manager`, `super_hot_key`, or any equivalent pub.dev package for PTT.** Rationale: those packages wrap the OS `RegisterHotKey` / `RegisterEventHotKey` semantics — they consume the key (suppressing it from other applications), they do not deliver a key-up event, and they do not support mouse side-buttons. PTT requires the opposite primitive (observe, do not consume, deliver both up and down). | Accepted | Software Architect + Audio Owner | Locks the v1 PTT capture path to the native backend; removes ambiguity for future maintainers tempted to "simplify" via a Flutter package. |
| DEC-030 | Voice activity detection deferred to P1 | **`TransmitMode::VoiceActivity` ships as a reserved enum variant with no v1 implementation.** The settings UI shows it as a disabled "coming soon" option. The actual implementation choice is deferred to a future baseline. Rationale: three viable backends were compared (RMS energy threshold — trivial but quality-poor; WebRTC VAD via the `webrtc-vad` crate — frozen-but-stable C++ BSD-3 dep, ~200 KB binary, industry baseline; Silero VAD via ONNX Runtime — best quality but ~816 MB binary uplift per platform plus an ONNX-runtime dependency surface). The v1 dependency-surface budget does not have room for the trade-off review required to pick correctly. Choosing too early risks either user-visible quality regression (RMS) or a forced ONNX adoption (Silero) before there is a comparable need for ML inference elsewhere (noise suppression, AEC). | Accepted | Audio Owner + Product Owner | Locks v1 to PTT + Continuous; preserves the enum surface so a P1 increment is non-breaking. |
| DEC-031 | Missed-key-up watchdog disabled on P0; redesign deferred to P1 | **The `MissedKeyUpWatchdog` is constructed and unit-tested but is NOT spawned by `ChanoraSession::start_audio` in the P0 baseline.** Supersedes DEC-028 for the v1 ship. Rationale: the original 30 s ceiling cut real users off mid-sentence when speaking through PTT for longer than the timeout — Mumble and TeamSpeak do not ship a comparable watchdog, so the protection is stricter than industry baseline while imposing a real UX cost. The watchdog's purpose (catching OS-level key-up loss when the app loses focus / is minimised / hits App Nap) remains valid; the fixed-timeout shape is the wrong implementation. P1 will reintroduce a redesigned variant using one of: (a) raised ceiling (~5 min, owner-tunable) only, (b) active OS-level key-state polling via `GetAsyncKeyState` / `CGEventSourceKeyState` / `XQueryKeymap` so we detect the actual OS desync directly, (c) audio-activity (RMS-silence) fallback once the level meter lands, or (d) a combination. The Rust unit tests for `MissedKeyUpWatchdog::spawn_on_signal` remain in `crates/chanora_audio/src/ptt.rs` so the P1 re-enable is non-breaking. | Accepted | Audio Owner + Product Owner | Eliminates a P0-class UX regression (long PTT speech cut off at 30 s) while preserving the implementation surface for P1. |
## 4. Accepted MVP Defaults
The "Recommended" defaults below have all been confirmed by the owner;
two were modified from the original recommendation (marked **MODIFIED**).
| Area | Accepted MVP default |
|---|---|
| Release sequence | Internal Alpha → External Beta → MVP Public |
| MVP platforms | Windows, macOS, Linux, Android, iOS (staged release allowed) |
| Active connections | One active server connection |
| UI design system | Material 3 + Chanora Design System |
| Product language | **MODIFIED** — English + Chinese (Simplified) at MVP; i18n-ready architecture |
| Server content | Preserve and display Unicode; do not translate |
| Diagnostics | Local, user-initiated export only |
| Telemetry | None |
| Crash reporting | None unless later approved |
| Secret storage | Platform secure storage |
| Non-secret local storage | SQLite (`rusqlite` bundled) |
| Audio processing | Platform-native first; fallback strategy documented |
| AEC | Enabled by default where supported |
| AGC | Enabled by default (user-toggleable) |
| Noise suppression | Enabled by default (user-toggleable) |
| High-pass filter | Enabled by default |
| Android minimum | **MODIFIED** — API 28 (Android 9.0), raised from the original recommendation of API 24 |
| Android target | API 35 or newer per current Google Play policy on upload date |
| iOS minimum | iOS 13 |
| Apple App Store SDK gate | Xcode 26+ / iOS 26 SDK+ for uploads on or after 2026-04-28 |
| Audio crate | `cpal` (desktop, Android); iOS deferred |
| Bridge | Stable typed Flutter/Rust bridge; `flutter_rust_bridge` 2.x pinned |
| Implementation directory layout | `apps/chanora_flutter/`, `core/chanora_core/`, `crates/chanora_*` |
| License | **Dual-licensed under Apache-2.0 OR MIT**, recipient's choice (DEC-020) |
## 5. Decision Impact Matrix
| Decision | Affects SysRS | Affects SysDes | Affects SRS | Affects SAD | Affects SDD | Affects Verification | Affects Release |
|---|---|---|---|---|---|---|---|
| Minimum iOS / Android versions | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Android target SDK | No | No | Yes | No | No | Yes | Yes |
| Multiple active connections | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| AEC/AGC/NS/HPF defaults | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Audio implementation path | No if behavior unchanged | Yes | Possibly | Yes | Yes | Yes | Yes |
| SDK/trademark/legal review | Yes | No | No | No | No | Yes | Yes |
| SQLite/equivalent choice | Possibly | Yes | Yes | Yes | Yes | Yes | Yes |
| Bridge choice | No if API behavior unchanged | Yes | Possibly | Yes | Yes | Yes | Yes |
| Apple App Store SDK gate | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Diagnostics upload policy | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Crash reporting | Yes if included | Yes if included | Yes if included | Yes if included | Yes if included | Yes | Yes |
| Flutter hotkey packages rejected for PTT (DEC-029) | No | Yes | Yes | Yes | Yes | Yes | No |
| VAD deferred to P1 (DEC-030) | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
## 6. Decisions That Must Be Confirmed By You
All decisions in the register have been addressed by the owner. The
remaining release-gating *work* (not decisions) is the legal review
itself under DEC-012, which must complete before any public/store
release but is not an open decision:
| Priority | Item | Status |
|---|---|---|
| P0 | DEC-012 legal/trademark/licensing review — perform the actual review work (non-affiliation wording final sign-off, trademark registrability check, transitive-dependency OSS obligations, `tsclientlib` license posture confirmation). | Pending; gate Accepted. |
## 7. Open Decision Log
| Decision ID | Owner | Decision | Status | Date | Notes |
|---|---|---|---|---|---|
| DEC-001 | Product Owner | Release type sequence | Accepted | 2026-05-14 | Internal Alpha → External Beta → MVP Public. |
| DEC-002 | Product Owner / Engineering | MVP platform strategy | Accepted | 2026-05-14 | All five platforms as target; staged release allowed. |
| DEC-003 | Product Owner / iOS Owner | Minimum iOS version | Accepted | 2026-05-14 | iOS 13. |
| DEC-004 | Product Owner / Android Owner | Minimum Android version | Accepted | 2026-05-14 | **API 28** (modified from the recommendation of API 24). |
| DEC-005 | Android Owner / Release Manager | Android target SDK | Accepted | 2026-05-14 | Google Play-required API on upload date (currently API 35+). |
| DEC-006 | Product Owner / Software Architect | Multiple server connections in MVP | Accepted | 2026-05-14 | Single connection in MVP. |
| DEC-007 | Audio Owner / Product Owner | AEC default | Accepted | 2026-05-14 | Enabled by default where supported. |
| DEC-008 | Audio Owner / Product Owner | AGC default | Accepted | 2026-05-14 | Enabled by default with user toggle. |
| DEC-009 | Audio Owner / Product Owner | Noise suppression default | Accepted | 2026-05-14 | Enabled by default with user toggle. |
| DEC-010 | Audio Owner | High-pass filter default | Accepted | 2026-05-14 | Enabled by default. |
| DEC-011 | Software Architect / Audio Owner | Audio processing path | Accepted | 2026-05-14 | Platform-native first; Rust/WebRTC-style fallback. |
| DEC-011.1 | Software Architect / Audio Owner | Audio crate (desktop / mobile) | Accepted (desktop: `cpal`; Android: `cpal`-on-Oboe) / Deferred (iOS) | 2026-05-13 | Closed by `poc/audio-capture-playback-spike` (desktop) and `poc/audio-capture-playback-android-spike` (Android). iOS crate TBD pending iOS spike. |
| DEC-012 | Legal / Compliance | SDK/trademark/licensing review | Accepted as a release gate | 2026-05-14 | Required before public/store release; legal review work still to be performed. |
| DEC-013 | Software Architect / Storage Owner | Local database | Accepted | 2026-05-14 | SQLite or equivalent for non-secret state. |
| DEC-013.1 | Software Architect / Storage Owner | SQLite crate | Accepted (`rusqlite` bundled) | 2026-05-13 | Closed by `poc/sqlite-storage-spike` 11/11. |
| DEC-013.2 | Software Architect / Storage Owner / Security Reviewer | Linux secure-storage backend policy | Accepted (Secret Service preferred, keyutils fallback) | 2026-05-13 | Closed by `poc/secure-storage-spike` 6/6. Resolves SysRS-053 / SysRS-162 ambiguity. |
| DEC-014 | Software Architect | Bridge choice | Accepted (`flutter_rust_bridge` 2.x pinned) | 2026-05-13 | Closed by `poc/flutter_rust_bridge_hello` 3/3. |
| DEC-015 | Product Owner | Product language for MVP | Accepted | 2026-05-14 | **English + Chinese (Simplified)** (modified from the recommendation of English-only). |
| DEC-016 | Product Owner / Legal / Security | Diagnostics upload policy | Accepted | 2026-05-14 | User-initiated local export only; no automatic upload. |
| DEC-017 | Product Owner / Legal / Security | Crash reporting | Accepted | 2026-05-14 | Disabled for MVP. |
| DEC-018 | Product Owner | Public product name | Accepted | 2026-05-14 | Chanora. Trademark check still required under DEC-012. |
| DEC-019 | Legal / Compliance | Public non-affiliation statement | Accepted (drafted wording) | 2026-05-14 | Final legal sign-off still required under DEC-012. |
| DEC-020 | Product Owner / Legal | License model | Accepted (Apache-2.0 OR MIT dual-license) | 2026-05-14 | Compatible with every direct dependency; texts ship as LICENSE-APACHE / LICENSE-MIT. Full OSS legal review remains under DEC-012. |
| DEC-021 | iOS Owner / Release Manager | Apple App Store SDK gate | Accepted | 2026-05-14 | Xcode 26+ / iOS 26 SDK+ on or after 2026-04-28. |
| DEC-022 | Software Architect | Canonical implementation directory layout | Accepted (README sketch) | 2026-05-13 | Closes the absence flagged during PoC review. |
| DEC-023 | Product Owner / Windows Platform Owner | Windows desktop Global PTT priority | Accepted (P0 / MVP) | 2026-05-15 | Resolves PTT-OPEN-001 from the gen2 desktop-PTT review. |
| DEC-024 | Product Owner / macOS Platform Owner | macOS desktop Global PTT priority | Accepted (P0 / MVP, permission-UX required) | 2026-05-15 | Resolves PTT-OPEN-002. |
| DEC-025 | Product Owner / Linux Platform Owner | Officially-tested Linux environment | Accepted (GNOME on Wayland only) | 2026-05-15 | Resolves PTT-OPEN-003. |
| DEC-026 | Product Owner / UX Owner | Mouse side-button support | Accepted (Windows + macOS; Linux portal-dependent) | 2026-05-15 | Resolves PTT-OPEN-004. |
| DEC-027 | Security / Privacy Reviewer | PTT diagnostics privacy posture | Accepted (capability + availability only, no key codes) | 2026-05-15 | Resolves PTT-OPEN-005. |
| DEC-028 | Audio Owner / Software Architect | Missed-key-up watchdog | Accepted (P0) | 2026-05-15 | Resolves PTT-OPEN-006. |
| DEC-029 | Software Architect / Audio Owner | Flutter global-hotkey packages rejected for PTT | Accepted | 2026-05-15 | Native `DesktopPttBackend` is the v1 PTT capture path; pub.dev hotkey packages consume the key, drop key-up events, and skip mouse side-buttons. |
| DEC-030 | Audio Owner / Product Owner | Voice activity detection deferred to P1 | Accepted (deferred to P1) | 2026-05-15 | `TransmitMode::VoiceActivity` reserved on the enum surface; UI shows "coming soon"; backend choice (RMS / WebRTC / Silero) deferred for dependency-surface review. |
| DEC-031 | Audio Owner / Product Owner | Missed-key-up watchdog disabled on P0; redesign deferred to P1 | Accepted (supersedes DEC-028 for P0) | 2026-05-16 | Watchdog implementation + tests retained; not spawned by `ChanoraSession::start_audio` in v1. P1 chooses between raised ceiling / OS key-state polling / RMS-silence fallback. |
## 8. Change History
| Version | Date | Description |
|---|---|---|
| 0.9.0 | 2026-05-14 | Updated decision register with proposed decisions for mobile minimum versions, audio defaults, audio implementation path, legal review, local database, bridge choice, diagnostics policy, and MVP release scope. |
## Baseline Candidate 0.9.1 Update
| Version | Date | Description |
|---|---|---|
| 0.9.1 | 2026-05-14 | Updated baseline after product decision closure: Apple App Store SDK gate uses Xcode 26+ and iOS 26 / iPadOS 26 SDK+ for App Store Connect upload on or after 2026-04-28, platform baselines and decision traceability propagated across the document set. |
## Baseline Candidate 0.9.2 Update
| Version | Date | Description |
|---|---|---|
| 0.9.2 | 2026-05-14 | Corrected Apple App Store Connect upload gate to 2026-04-28 and checked full-package naming, references, and coverage. |
## Baseline Candidate 0.9.3 Update
| Version | Date | Description |
|---|---|---|
| 0.9.3 | 2026-05-14 | Recorded owner-confirmed decisions surfaced during the initial PoC phase: DEC-014 Accepted (`flutter_rust_bridge` 2.x pinned); added DEC-011.1 Accepted for desktop (`cpal`) / Deferred for mobile; added DEC-013.1 Accepted (`rusqlite` bundled); added DEC-013.2 Accepted (Linux Secret Service preferred with keyutils fallback); added DEC-022 Accepted (canonical implementation directory layout per README sketch and SAD §7.2); DEC-020 explicitly Deferred and remains a public-release blocker. Evidence pointers: `poc/flutter_rust_bridge_hello/VERIFICATION.md`, `poc/secure-storage-spike/VERIFICATION.md`, `poc/sqlite-storage-spike/VERIFICATION.md`, `poc/audio-capture-playback-spike/VERIFICATION.md`. |
## Baseline Candidate 0.9.4 Update
| Version | Date | Description |
|---|---|---|
| 0.9.4 | 2026-05-14 | Promoted DEC-011.1 mobile half from Deferred to Accepted (Android), keeping iOS Deferred. Evidence: `poc/audio-capture-playback-android-spike/VERIFICATION.md` records empirical playback (22,050 frames at 44.1 kHz mono out of the device speaker) and capture (42,624 frames written to a valid 85,292-byte RIFF/WAVE mono 16-bit PCM file) on a physical Motorola Moto G Stylus 5G (2023) running Android 14 arm64-v8a, verifying the full Rust → cpal → Oboe → AAudio → Android audio HAL path. |
## Baseline Candidate 0.9.5 Update
| Version | Date | Description |
|---|---|---|
| 0.9.5 | 2026-05-14 | Owner confirmation pass on all previously-Proposed decisions. Accepted: DEC-001, DEC-002, DEC-003, DEC-005, DEC-006, DEC-007, DEC-008, DEC-009, DEC-010, DEC-011, DEC-012 (as a release gate), DEC-013, DEC-015, DEC-016, DEC-017, DEC-018, DEC-019 (drafted wording), DEC-021. Two decisions modified from their original recommendations: **DEC-004 Android minimum** raised from API 24 to **API 28** (simpler audio path, narrower compatibility surface); **DEC-015 product language** expanded from English-only to **English + Chinese (Simplified)** for MVP (reflects the demonstrated TS3-compatible-server audience). DEC-020 license model remains Open / Deferred — the only public-release blocker outstanding. §4 renamed from "Recommended MVP Defaults" to "Accepted MVP Defaults" with MODIFIED rows annotated. §6 collapsed to the single remaining DEC-020 item. §7 dated and statused. |
## Baseline Candidate 0.9.6 Update
| Version | Date | Description |
|---|---|---|
| 0.9.6 | 2026-05-14 | DEC-020 license model closed: **Apache-2.0 OR MIT** dual-license (standard Rust-ecosystem permissive model). The license is compatible with every direct dependency in the PoC tree (tsclientlib, flutter_rust_bridge, cpal, rusqlite, keyring, hound, etc.) and with the Flutter framework's BSD-3-Clause. License texts added as `LICENSE-APACHE` and `LICENSE-MIT` at the repository root; the existing `LICENSE` file now aggregates both with the dual-license declaration and the standard Apache-2.0 inbound-contribution clause. `NOTICE` populated with current direct-dependency attributions. README §License rewritten. §4 updated. §6 collapsed: there is no longer any open decision — DEC-012 legal review remains a pending *work* item, not a pending decision. With this change, every previously-Proposed or Open decision in the register has been resolved; the only outstanding release-gating activity is the DEC-012 legal review itself (which is sign-off work, not an architectural choice). |
## Baseline Candidate 0.9.7 Update
| Version | Date | Description |
|---|---|---|
| 0.9.7 | 2026-05-14 | DEC-001 release-sequence progress recorded: Internal Alpha (`v0.1.0-alpha.1`, commit 3bb038c) completed on 2026-05-14; **Internal Beta first build (`v0.2.0-beta.1`)** reached the same day. Beta milestone adds voice in/out: `crates/chanora_audio` promoted from scaffold to a cpal-based capture + playback engine with `audiopus` Opus encoding and tsclientlib `AudioHandler` for decode + jitter buffer + mix; `crates/chanora_protocol` extended to forward inbound voice packets and accept outbound `OutPacket`s via mpsc channels; `core/chanora_core::ChanoraSession` exposes `start_audio`, `set_ptt`, and `audio_stats`; `crates/chanora_bridge` adds matching DTOs; the Flutter UI gains a "Start audio" action and a hold-to-talk PTT button with live frame counters. Verified end-to-end against `cn.teamspeak.app`; capture runs in graceful playback-only mode on hosts with no usable microphone (e.g. the PipeWire `auto_null` source on the verification host). No decision rows change; this entry documents progress against DEC-001 only. |
| 0.9.8 | 2026-05-15 | DEC-001 release-sequence progress recorded for the polished Internal Beta and the External Beta milestones, plus the first MVP-public release candidate. **`v0.3.0-beta.1`** ("Internal Beta polish") added the supervisor + reconnect-with-watchdog path (A.6), OS-connectivity-aware backoff (A.6.1), persistent identity at rest as a plain 0600 file (A.2), the redacted in-memory log sink + user-initiated diagnostic export per DEC-016 (A.3), the `SnapshotChanged` lifecycle event for UI auto-refresh (A.4), and the `mobile_voice_preset` config-surface plumb-through (A.5). **`v0.4.0-beta.2`** ("External Beta") added the server-password input, channel join via tap, self mute (input + output), master output gain, SQLite-backed bookmark list, ChaCha20-Poly1305 encryption of the identity at rest with the DEK in a separate `identity.dek` file, Android `AudioManager.setMode(MODE_IN_COMMUNICATION)` routing engagement via JNI, and the `.github/workflows/ci.yml` pipeline. **`v1.0.0-rc.1`** ("MVP Public release candidate") closes the v0.4 DEK-on-disk weakness on every keyring-reachable platform: `chanora_storage::IdentityFileStore` now stores the DEK in the OS keyring (Linux Secret Service via D-Bus / macOS Keychain / Windows Credential Manager / iOS Keychain via the `keyring` crate) and migrates pre-existing file-fallback installs into the keyring opportunistically; bookmark server passwords are ChaCha20-Poly1305-encrypted under the same per-install DEK and the legacy plain `password TEXT` column is upgraded into a new `password_blob BLOB` column on the next `update()`; `SessionEvent::SnapshotChanged` now fires on any tree mutation (the in-channel-move blind spot from A.4 is closed); the in-app About dialog surfaces DEC-018 / DEC-019 / DEC-020. New `docs/governance/legal-review-readiness.md` carries the DEC-012 handoff package (trademark check, non-affiliation wording, third-party license posture, `cargo about` deliverables, `cargo deny` lifelines); new `docs/governance/staged-release-plan.md` enumerates the DEC-002 platform staging (Linux + Android sideload GA on DEC-012 sign-off; Windows, macOS, iOS gate on per-platform signed-build availability). No decision rows change; DEC-012 remains the sole outstanding release gate. |
| 0.9.9 | 2026-05-15 | Recorded six new accepted decisions DEC-023 through DEC-028 closing the gen2 desktop-PTT review's open questions PTT-OPEN-001 through PTT-OPEN-006: Windows Global PTT is P0/MVP (DEC-023), macOS Global PTT is P0/MVP with permission UX (DEC-024), the officially-tested Linux environment is GNOME-on-Wayland only (DEC-025), mouse side buttons are supported on Windows + macOS and Linux follows the portal (DEC-026), PTT diagnostics carry capability/availability only with no raw key codes (DEC-027), and the missed-key-up watchdog is a P0 release-gate requirement (DEC-028). No prior decision rows are mutated. |
| 0.9.10 | 2026-05-15 | Code-side promotion: the Linux GNOME-Wayland backend (DEC-025) is now a live `org.freedesktop.portal.GlobalShortcuts` session — `CreateSession` + `BindShortcuts` + `Activated` / `Deactivated` signal subscription scoped to the session handle, owned by a dedicated tokio task per backend instance. The Flutter "Configure" button on Linux portal delegates to the portal's own system dialog (Q3a) rather than the in-app `_PttBindingCaptureDialog`. Descriptor transitions broadcast via a `watch::Sender` consumed by `chanora_core::ChanoraSession::start_audio` and forwarded to `SessionEvent::PttCapability`. Cancellation / failure path downgrades to `L0Focused` and re-emits. No decision rows mutate. |
| 0.9.11 | 2026-05-15 | Added DEC-029 and DEC-030 covering the v1 audio + PTT lifecycle redesign. DEC-029 rejects Flutter global-hotkey packages (`hotkey_manager`, `super_hot_key`, equivalents) for PTT — they consume the key, do not deliver key-up, and do not support mouse side-buttons; the native Rust `DesktopPttBackend` already specified in SDD-083 / SDD-084 / SDD-085 is the v1 capture path. DEC-030 defers Voice Activity Detection to P1: `TransmitMode::VoiceActivity` ships as a reserved enum variant with no v1 implementation pending a backend trade-off review (RMS vs WebRTC VAD vs Silero VAD differ by ~816 MB and an ONNX-runtime dependency surface). No prior decision rows mutate; §5 impact matrix and §7 open-decision log gain matching rows. |
| 0.9.12 | 2026-05-16 | Added DEC-031: missed-key-up watchdog is disabled on P0 (supersedes DEC-028 for the v1 ship). The 30 s default ceiling spec'd in DEC-028 was cutting real PTT users off mid-sentence whenever a single utterance crossed the timeout; the watchdog's intent (catching OS-level key-up loss) remains valid, but the fixed-timeout implementation is the wrong shape. The `MissedKeyUpWatchdog` Rust type and its unit tests remain in `crates/chanora_audio/src/ptt.rs`; only the `ChanoraSession::start_audio` spawn is removed. P1 will choose between a raised ceiling, OS key-state polling (`GetAsyncKeyState` / `CGEventSourceKeyState` / `XQueryKeymap`), an RMS-silence fallback paired with the audio level meter, or a combination. DEC-028 stays in the register as historical context. |