Bus: WebviewBridge.sendRaw audioLevel allows NaN → null JSON → JS decode error #47

Closed
opened 2026-05-12 19:08:41 +00:00 by KofTwentyTwo · 0 comments
KofTwentyTwo commented 2026-05-12 19:08:41 +00:00 (Migrated from github.com)

Summary

WebviewBridge.sendRaw propagates JSON-throwing through the public API. encoder.encode(.audioLevel(rms: .nan)) succeeds (Float.nan encodes as null), but decodeOutbound JS-side rejects (typeof null === "object", not "number"). Result: per-frame decode error in onDecodeError for every audio frame containing NaN. Currently masked because audioLevel consumer is a no-op (S2-2); becomes S1 the moment audioLevel is wired through.

Evidence

  • File: packages/Bus/Sources/Bus/WebviewBridge.swift:180-194

Recommended fix

Clamp rms to 0.0...1.0 in AudioLevelEmitter, OR have BusOutbound.audioLevel.encode substitute 0.0 for non-finite floats:

case .audioLevel(let rms):
    let safe = rms.isFinite ? rms : 0.0
    // encode safe

Test

  • Unit: encode BusOutbound.audioLevel(rms: .nan) → JS-side decode succeeds with rms == 0.0

Source

  • Audit: .planning/audit-2026-05-12/bus-hud-audit.md (2026-05-12) — finding S3

Cross-references

  • Becomes S1 when #42 (S2-2 audioLevel consumer wired)
## Summary `WebviewBridge.sendRaw` propagates JSON-throwing through the public API. `encoder.encode(.audioLevel(rms: .nan))` succeeds (`Float.nan` encodes as `null`), but `decodeOutbound` JS-side rejects (`typeof null === "object"`, not `"number"`). Result: per-frame decode error in `onDecodeError` for every audio frame containing NaN. Currently masked because `audioLevel` consumer is a no-op (S2-2); becomes S1 the moment audioLevel is wired through. ## Evidence - File: `packages/Bus/Sources/Bus/WebviewBridge.swift:180-194` ## Recommended fix Clamp `rms` to `0.0...1.0` in `AudioLevelEmitter`, OR have `BusOutbound.audioLevel.encode` substitute `0.0` for non-finite floats: ```swift case .audioLevel(let rms): let safe = rms.isFinite ? rms : 0.0 // encode safe ``` ## Test - Unit: encode `BusOutbound.audioLevel(rms: .nan)` → JS-side decode succeeds with `rms == 0.0` ## Source - Audit: `.planning/audit-2026-05-12/bus-hud-audit.md` (2026-05-12) — finding S3 ## Cross-references - Becomes S1 when #42 (S2-2 audioLevel consumer wired)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: KofTwentyTwo/Jarvis#47