Files
chanora/docs/P0_MVP_AGENT_SPEC.md
T

15 KiB
Raw Blame History

P0 MVP Agent Spec — Build This First

Objective

Create the smallest complete Chanora MVP that can connect to one TS3-compatible server, render channel/user state, support basic voice workflow, persist local non-secret settings, protect secrets, and pass platform P0 acceptance gates.

Scope

Implement only P0/MVP. Treat P1/P2 items as backlog unless the user explicitly requests them.

Accepted MVP Decisions

  • DEC-001: Release type = Internal Alpha first, then External Beta, then MVP Public / Store Release
  • DEC-002: MVP platform scope = MVP target remains Windows, macOS, Linux, Android, and iOS; first release may be staged by channel/platform
  • DEC-003: Minimum iOS version = iOS 13 minimum for Flutter support baseline; test latest iOS release separately
  • 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 original cpal-on-Oboe Android spike was built with minSdk = 24 and cargo-ndk -P 26; product code in apps/chanora_flutter uses minSdk = 28 and the Android product audio backend is now direct Oboe, so Chanora no longer carries the API 24/25 OpenSL ES fallback branch.
  • 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
  • DEC-006: Multiple server connections in MVP = Not in MVP; support one active server connection per client instance
  • DEC-007: AEC default state = Enabled by default on platforms/audio backends where supported and stable
  • DEC-008: AGC default state = Enabled by default, with user setting to disable
  • DEC-009: Noise suppression default state = Enabled by default, with user setting to disable
  • DEC-010: High-pass filter default state = Enabled by default
  • 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
  • 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 direct oboe-rs for Android product code. The earlier cpal-on-Oboe spike remains evidence that Rust audio reaches Oboe/AAudio on a Motorola Moto G Stylus 5G (2023) running Android 14 arm64-v8a, but product code chooses direct Oboe because P0 Android needs explicit VoiceCommunication input preset, VoiceCommunication/Speech output attributes, low-latency/exclusive stream requests with shared fallback, audio-session ids for hardware AEC/NS/AGC binding, and diagnostics of requested/achieved stream values. iOS crate TBD pending an iOS spike that requires macOS + Xcode hardware
  • 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
  • DEC-013: Local database choice = Use SQLite or equivalent embedded local database for non-secret local state; secrets remain in platform secure storage
  • 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
  • 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
  • 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)
  • 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).
  • DEC-016: Diagnostics upload policy = No automatic upload for MVP; user-initiated local diagnostic export only
  • DEC-017: Crash reporting = Disabled for MVP unless explicit opt-in provider and privacy policy are approved
  • DEC-018: Public product name = Chanora
  • 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
  • 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.
  • 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
  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • 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).
  • 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).
  • DEC-001: Product Owner = Release type sequence
  • DEC-002: Product Owner / Engineering = MVP platform strategy
  • DEC-003: Product Owner / iOS Owner = Minimum iOS version
  • DEC-004: Product Owner / Android Owner = Minimum Android version
  • DEC-005: Android Owner / Release Manager = Android target SDK
  • DEC-006: Product Owner / Software Architect = Multiple server connections in MVP
  • DEC-007: Audio Owner / Product Owner = AEC default
  • DEC-008: Audio Owner / Product Owner = AGC default
  • DEC-009: Audio Owner / Product Owner = Noise suppression default
  • DEC-010: Audio Owner = High-pass filter default
  • DEC-011: Software Architect / Audio Owner = Audio processing path
  • DEC-011.1: Software Architect / Audio Owner = Audio crate (desktop / mobile)
  • DEC-012: Legal / Compliance = SDK/trademark/licensing review
  • DEC-013: Software Architect / Storage Owner = Local database
  • DEC-013.1: Software Architect / Storage Owner = SQLite crate
  • DEC-013.2: Software Architect / Storage Owner / Security Reviewer = Linux secure-storage backend policy
  • DEC-014: Software Architect = Bridge choice
  • DEC-015: Product Owner = Product language for MVP
  • DEC-016: Product Owner / Legal / Security = Diagnostics upload policy
  • DEC-017: Product Owner / Legal / Security = Crash reporting
  • DEC-018: Product Owner = Public product name
  • DEC-020: Product Owner / Legal = License model
  • DEC-021: iOS Owner / Release Manager = Apple App Store SDK gate
  • DEC-022: Software Architect = Canonical implementation directory layout
  • DEC-023: Product Owner / Windows Platform Owner = Windows desktop Global PTT priority
  • DEC-024: Product Owner / macOS Platform Owner = macOS desktop Global PTT priority
  • DEC-025: Product Owner / Linux Platform Owner = Officially-tested Linux environment
  • DEC-026: Product Owner / UX Owner = Mouse side-button support
  • DEC-027: Security / Privacy Reviewer = PTT diagnostics privacy posture
  • DEC-028: Audio Owner / Software Architect = Missed-key-up watchdog
  • DEC-029: Software Architect / Audio Owner = Flutter global-hotkey packages rejected for PTT
  • DEC-030: Audio Owner / Product Owner = Voice activity detection deferred to P1

Required P0 Capability Groups

  1. App shell: routing, startup, theme, localization, adaptive layout, platform-service initialization.
  2. UI/design: Material 3, Chanora design tokens, responsive desktop/tablet/mobile layouts, accessible controls, keyboard focus, safe areas/insets.
  3. Protocol: TS3-compatible adapter through tsclientlib; no direct UI coupling to protocol internals.
  4. Connection: one active server connection; visible connecting/connected/reconnecting/disconnected/error states.
  5. Channel/user tree: preserve Unicode server content; do not translate server names/messages.
  6. Voice basics: capture/playback path, push-to-talk where platform-supported, mute/deafen indicators, native processing defaults.
  7. Audio defaults: AEC on where stable, AGC on with user toggle, noise suppression on with user toggle, high-pass filter on.
  8. Storage: SQLite for non-secret state; platform secure storage for identities/tokens/password-equivalent secrets.
  9. Diagnostics: local export only; redact secrets; machine fields remain language-neutral.
  10. Builds: reproducible platform builds for Windows, macOS, Linux, Android, and iOS with staged release allowed.
  11. Verification: unit, widget, integration, platform acceptance, and release go/no-go evidence.

P0 Architecture Boundaries

  • Flutter owns UI, navigation, Material 3 theming, accessibility, and adaptive presentation.
  • Rust core owns domain state, protocol/session orchestration, storage, diagnostics, and platform-abstracted services.
  • Bridge owns typed DTOs/events/errors only. Do not leak Rust internals into Flutter or Flutter objects into Rust core.
  • Platform adapters own OS-specific audio, hotkey, secure storage, build, and permission behavior.

P0 Definition of Done

  • User can launch app, enter/connect to a TS3-compatible server, see server/channel/user state, and disconnect cleanly.
  • App supports the selected P0 voice path without telemetry or automatic upload.
  • Secrets are never stored in SQLite/plaintext.
  • English and zh-Hans product strings are available; server-originated Unicode remains unchanged.
  • All diagnostic exports are local/user-triggered and redacted.
  • Platform P0 acceptance docs pass or contain explicit blocker records.
  • Every code change cites at least one requirement or decision ID.

P0 Requirement Index

  • Count: 500
  • ID groups: SAD-001..SAD-096 (71 ids); SDD-001..SDD-121 (98 ids); SRS-001..SRS-219 (178 ids); SysDes-001..SysDes-158 (153 ids)

P0 Source Weighting

  • requirements/srs.md: 178
  • architecture/sysdes.md: 153
  • architecture/sdd.md: 98
  • architecture/sad.md: 71

P0 Allocation Hotspots

  • Unallocated: 98
  • Flutter UI: 68
  • Rust Core: 52
  • Verification: 43
  • Audio Subsystem: 42
  • Software: Audio Subsystem: 39
  • System Engineering: 33
  • Protocol Adapter: 31
  • Diagnostics: 28
  • State Sync: 24
  • Design System: 22
  • Bridge: 21
  • Storage: 21
  • Software: Diagnostics: 21
  • Platform: 20
  • Software: Protocol Adapter: 20
  • Platform Adapters: 19
  • Software: Rust Core: 19
  • Audio: 18
  • Operations: 17

Agent Compression Rule

Do not paste all P0 requirement statements into prompt context. Use this file as the execution contract and phase_index.json only when an exact ID/source lookup is required.