137 lines
15 KiB
Markdown
137 lines
15 KiB
Markdown
# 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 ~8–16 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.
|