zebra-report/docs/tickets
Russell Ballestrini caa0548113
zebra-spaces: fresh-stream wrap on mic ontrack + mute-gate mesh swap (kill fedora-chrome silence)
Fox 2026-06-07 telemetry on blanka-chrome ruled out the sink-routing
hypothesis from 467146a:

  audio via AudioContext 085b target=0.5s ctxState=running sink=default
  mesh stream swapped into worklet for 085b
  ...
  aud.recv pkt=14622 lost=1 bytes=9117575 jitter=0.0100 level=0.000 jbuf=? lp=0.1s

50 pps stereo Opus arriving on the SFU sub PC, sink routed to the
picked device, but jbuf=? (jitterBufferEmittedCount=0) + level=0 — the
native decoder consumes nothing because no MediaStreamSource is bound
to the SFU receiver's track. fxhp-phone same room same window decodes
fine (jbuf=0.49s level=0.001), so the SFU is healthy and the defect is
per-client wiring.

Two coupled defects:

(A) tracks=0 race in handleRemoteSfuTrack mic branch. Chrome can fire
ontrack with ev.streams[0] still empty at handler-time (the live track
arrives a microtask later, or MSID-supplant merges new+dead tracks).
Caching ev.streams[0] then handing it to attachSfuTrack drops the
listener into the silent <audio> fallback — telemetry: "sfu attach
b1a7 fresh=1 tracks=0" + "meter for b1a7: MediaStream has no audio
track". Screen/camera/game already wrap ev.track in a fresh
MediaStream; mic now does the same. Single track, guaranteed live,
every time.

(B) Mesh ontrack unconditionally swaps the worklet's source to the
mesh stream — even when the mesh track is still muted (no RTP). The
SFU receiver becomes orphaned (no decoder), and if the mesh track
never unmutes the listener hears silence with no automatic SFU
restore. Gate the swap on track-not-muted: swap immediately if mesh
is already flowing, otherwise wait for 'unmute'. Add a mute-watchdog
that swaps back to the cached SFU stream after MESH_MUTE_WINDOW_MS
of mesh silence — same shape as the existing
connectionState=='failed' restore path, but driven by track-level
mute instead of PC-level failure.

Hard refresh + leave/enter worked because the fresh negotiation
delivered the mesh track already unmuted, so the eager swap landed
on a live source. Now the same swap waits for live source instead of
hoping for one.

Tests:
  - handleRemoteSfuTrack: ev.streams[0] empty but ev.track live →
    fresh MediaStream wrap rescues the attach (chain built, audible
    path verified)

Ticket 0001 updated with the telemetry comparison and the new
diagnosis. Mesh-mute-watchdog has no dedicated test yet (the mesh
ontrack lives in connectToPeer which the listener test harness
doesn't extract) — pin in multi-peer-mesh.test.js next pass.
2026-06-07 11:33:57 -04:00
..
0001-fedora-chrome-cannot-hear-speakers.md zebra-spaces: fresh-stream wrap on mic ontrack + mute-gate mesh swap (kill fedora-chrome silence) 2026-06-07 11:33:57 -04:00
0002-fedora-firefox-cannot-share-camera.md docs: add tickets dir + first two open defects 2026-06-07 11:24:17 -04:00
README.md docs: add tickets dir + first two open defects 2026-06-07 11:24:17 -04:00

Tickets

Defect tracker for zebra-report. Anything that takes more than 15 minutes or needs to be reproduced across browsers, devices, or sessions lives here as a numbered markdown file.

File format

Each ticket is docs/tickets/NNNN-slug.md where NNNN is monotonically increasing. New tickets get the next number.

# NNNN: Short title

**Status:** open | in-progress | blocked | fixed | won't-fix
**Priority:** P0 (silent regression / data loss) | High | Medium | Low
**Surface:** browser / OS / role (e.g. "fedora chrome listener")
**First seen:** YYYY-MM-DD (reporter's local date)
**Reporter:** handle

## Symptom
What the user sees. Plain language, no implementation details.

## Telemetry / Repro
What the signal log / browser console / pcap shows. Concrete lines if
available. How to reproduce.

## Hypothesis
What we think is going on. List candidates if not yet narrowed.

## Fix
What was tried, what landed, what commit. Empty until something ships.

## Status notes
Running log of attempts, observations, retests. Newest at the top.

Priority

  • P0 — silent regression: the app appears to work but doesn't (no error surfaced, audio routes nowhere, video goes black). Trust-eroding because the user can't tell what's wrong.
  • High — feature unavailable (can't share camera, can't enter room). Visible error or empty state.
  • Medium — degraded UX with workaround (slight latency, wrong tile order).
  • Low — cosmetic, log noise, tooling.

How tickets are resolved

  1. Reproduce or grab telemetry from the signal-server log (/var/log/zebra-spaces-signal.log — grep CLIENT_LOG + the reporter's handle).
  2. Write a failing test in test/ that pins the contract the defect violates. The test failing IS the diagnosis.
  3. Fix the code so the test passes. Commit with the test name in the message body.
  4. make stamp, push both zebra-report and the deploy repo (www.unturf.com/zebra-report/).
  5. Update the ticket Status to fixed, link the commit, note what to re-test in production.

Open

# Title Priority Surface Status
0001 fedora chrome cannot hear speakers P0 fedora chrome (any role) in-progress
0002 fedora firefox cannot share camera High fedora firefox (speaker/host) open

Fixed

(none yet)