5. Non-Functional Requirements (ART 0507)

5.1 Performance Requirements

ID Requirement Target Priority Verification
NFR-001 RX audio latency < 500ms end-to-end (radio speaker → browser speaker) Critical Listening test
NFR-002 Control response UI command ack within 200ms on LAN High WebSocket round-trip observation
NFR-003 Spectrum bandwidth Tiered by spectrum_profile (AD-025): high = 1701 B/frame every broadcast tick, mid = 851 B every 2nd tick, low = 851 B every 4th. The loop ticks at 30 Hz but real scope frames go out only when the hardware counter advances — measured 11.1 fps on the FT-710 ⇒ ~151 kbps payload for high, ~38 for mid, ~19 for low. The S-meter fallback regenerates a frame on every tick (~30 fps ⇒ ~408 kbps for high) and passes through the same divider. A socket that never sends spectrumCaps always gets high. These are payload figures: browsers negotiate permessage-deflate (measured 1701 B → ~441 B on the wire) while Android’s OkHttp does not, so a phone pays the payload Medium dev_tools/spectrum_profile_probe.py; session_metrics spectrum_profiles
NFR-004 Audio transport bandwidth Opus ~48–64kbps at 48kHz mono; PCM ~768kbps fallback Medium Network monitor
NFR-005 CPU stability No sustained overload from serial polling + audio + scope High Activity Monitor/top observation
NFR-006 Serial port throughput < 300 bytes/sec polling at 38400 baud (FT-710) or 115200 baud (IC-7300), well under limit High Serial monitor
NFR-007 Waterfall render quality 120-row history, adaptive colormap, frequency scale alignment Medium Visual inspection
NFR-008 PTT response < 100ms from touch to TX command Critical Timing logs

5.2 Availability Requirements

ID Requirement Target Priority Verification
NFR-010 Service restart start.sh / stop.sh manage background service High Script execution
NFR-011 WebSocket reconnect Frontend auto-reconnects with exponential backoff (1s→30s) High Connection loss test
NFR-012 PTT release safety TX0; always sent on release, even if connection lost Critical Force-close browser during TX

5.3 Security Requirements

ID Requirement Target Priority Verification
NFR-020 Session authentication All routes and WS endpoints require valid auth token (mrrc_auth cookie + ?token= query param) High Unauth curl test
NFR-021 Password configurable MRRC_WEB_PASSWORD env var; never hardcoded in repo Critical Config review
NFR-022 Token lifetime 30-day session tokens, persisted across restarts (data/auth-tokens.json, 0600; a routine upgrade restart must not log operators out) Medium Cookie inspection
NFR-023 Open redirect prevention Login redirect validates same-origin target High Code review of _auth_middleware and /login

5.4 Compatibility Requirements

ID Requirement Target Priority Verification
NFR-030 iOS Safari RX audio, touch controls, PWA support High iPhone test
NFR-031 Desktop Chrome/Safari/Firefox Full functionality High Desktop browser test
NFR-032 Radio firmware Protocol compatible with current vendor firmware for the selected backend: the eleven registry keys ft710, ic7300, ic7300mk2, ic705, ic7610, ic7760, ftdx10, ftdx101d, ftdx101mp, ftx1, ft891 Critical Radio connection fails with a logged error; the operator can switch models
NFR-033 macOS + Linux Server runs on both platforms High Cross-platform build test
NFR-034 opus_rx.py Works on arm64 (Apple Silicon) and x86_64 High ctypes libopus loading test

5.5 Operability Requirements

ID Requirement Target Priority Verification
NFR-040 Logging Startup, CAT connect, scope status, audio device selection logged High logs/ directory output
NFR-041 Configuration MRRC_RADIO_MODEL, IC7300_CIV_ADDR, MRRC_ALLOW_UNVERIFIED_TX (transmit gate for hardware-unverified models), MRRC_RECORDINGS_DIR / MRRC_RECORDINGS_BITRATE / MRRC_RECORDINGS_MAX_SESSION_MIN (recording), MRRC_SERIAL_PORT, MRRC_WEB_PORT, MRRC_WEB_PASSWORD, MRRC_WEB_HOST env vars Medium Env var test
NFR-042 PID file .ft710-server.pid tracks running process Medium start.sh / stop.sh behavior
NFR-043 Static cache safety Service worker bypasses JS/HTML cache High sw.js review

5.6 Maintainability Requirements

ID Requirement Target Priority Verification
NFR-050 Module boundaries CAT, audio, scope, state, poll, config each in separate files Medium Code review
NFR-051 Explicit gaps Documented in SDD until implemented or removed High SDD review
NFR-052 No external middleware Zero Hamlib/rigctld/TCI dependency High Import review

5.7 Audio Quality Requirements

ID Requirement Target Priority Verification
NFR-060 RX sample rate FT-710: 44.1kHz native capture, resampled to 48kHz for Opus; IC-7300/MK2 and the IC-705/IC-7610/IC-7760 profiles: 48kHz native capture, no resample; the Yaesu FTDX10/FTDX101D/FTDX101MP/FTX-1F profiles assume the family 44.1kHz value (TODO(hw-verify), per-profile audio_rx_rate); the FT-891 profile carries 48kHz because it has no USB sound card — its USB port is CAT only, so audio comes from an external interface on the DATA/ACC port (TODO(hw-verify); 48kHz is the normal rate for such an interface and is already the IC-7300 family’s resample-free path) Important A wrong per-model rate is audible as pitch shift and is the first thing _diag_yaesu.py reports
NFR-061 Opus bitrate 64kbps default, 16-128kbps adjustable Medium Codec config
NFR-062 TX audio quality Clean mic audio reaches radio without distortion High On-air listening test
NFR-063 AudioWorklet playback Jitter buffer: 220ms prebuffer, 90ms recovery, 800ms max High Listening under network jitter
NFR-064 PCM fallback Automatic when libopus unavailable (server or browser) High Start without libopus
NFR-066
QSO recording Server-side 16 kHz mono MP3 at ≤64 kbps written incrementally to recordings/; timeline length within ±50 ms of elapsed real time regardless of scheduler jitter; disk usage observable in the UI (no automatic deletion by design) Medium tests/test_recorder.py (gap fill / tolerance / drift), tests/test_recorder_api.py (routes, Range)
NFR-065 PyAudio device selection Auto-detect per-backend device hints (e.g., “FT-710”/“YAESU” for FT-710; “ic-7300”/“ic-705”/“ic-7610”/“ic-7760” then generic “USB Audio CODEC”/“USB Audio Device” for the Icom family), then mono/full-duplex heuristics; fallback to system default. The FT-891 carries no radio hints at all (audio_name_hints=()) because it has no USB codec: selection falls through to the generic USB-audio tier (which finds an external interface) or to the operator’s explicit MRRC_AUDIO_RX_DEVICE/MRRC_AUDIO_TX_DEVICE, and the connection dialog says so Medium Device enumeration log
NFR-067 Verification honesty A radio model without hardware evidence must report verified=false, gate transmit behind MRRC_ALLOW_UNVERIFIED_TX=1, list its unverified meters, record a provenance source per table and never be presented as verified in the UI, README or SDD (AD-019) Critical Operators cannot mistake documentation-derived tables for measured behaviour; the five Yaesu models and the three Icom experimental models follow this rule
NFR-068 Data ownership Operator data leaves the machine only in a redacted, operator-initiated diagnostics bundle: passwords, keys/tokens, certificates, recordings, memory channels and ATR learning values are never included; the bundle is built server-side and the hit count is published in its manifest AD-021, tests/test_support_bundle.py, tests/test_support_api.py
NFR-069 Factory-preset disclosure A ship-ready (--preflash) image’s three credentials (root / service user / web) are public knowledge by construction: they are documented in docs/W103D_GUIDE.md §7 and packaging/box/README.md, all three can be changed on the box, and the guide states the trade-off (one image, one batch, one password) rather than presenting them as secrets High Docs carry the values and the trade-off; a build without --preflash has no fixed values at all (tests/test_preflash.py, artifact check §8.2 of the 2026-10-17 design)