Files
chanora/docs/P0_MVP_AGENT_SPEC.md
T

137 lines
15 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.
# 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.