Plans the path from 'infra shipped' to 'full coverage with correct behaviours'. Five new plan docs in nestsClient/plans/: 1. 2026-05-07-t16-closure-roadmap.md — index + priority order. Three sequential steps + one independent track. 2. 2026-05-07-moq-relay-routing-investigation.md (Priority 1) — root-cause the moq-relay 0.10.x per-broadcast subscribe- routing race. Step-by-step: capture relay-side trace, write minimum reproducer, file upstream OR bump moq-relay version. Smoking gun + hypotheses already in place from the late-join-flake investigation; this plan turns that into actionable next steps. 3. 2026-05-07-tighten-cross-stack-assertions.md (Priority 2) — once the routing race is closed, replace the five soft- pass scenarios in BrowserInteropTest with hard floors. Lists each scenario, its current soft-pass behavior, and the proposed hard threshold. 4. 2026-05-07-cross-stack-interop-ci-gating.md (Priority 3) — re-add the hang-interop + browser-interop GitHub Actions jobs that were dropped in6829ab727/b94737de7. Includes the exact YAML to restore and a 10/10 sweep stability bar before merge. 5. 2026-05-07-framespergroup-production-rerun.md (independent track) — re-run the HCgOY two-phone field tests against current nostrnests production at multiple framesPerGroup values to settle whether the test pin (5) and production default (50) can converge. Estimated total: 2.5-3.5 days of focused work to fully close T16. After these four: I7 post-reconnect cliff and I12 GOAWAY remain open as genuinely upstream-territory items, tracked in their existing investigation docs.
4.5 KiB
Plan: tighten cross-stack interop assertions to hard-pass
Status: specced — pickup ready.
Depends on: 2026-05-07-moq-relay-routing-investigation.md
must be closed first (the soft-passes exist because of that flake;
removing them while the flake is unresolved produces fail-flakes,
not regression catches).
Why soft passes exist today
Five scenarios currently soft-pass (vacuous-pass on listener-side
0-frame outcomes) to keep the test suite from fail-flaking on the
upstream relay-routing race documented in
2026-05-07-late-join-catalog-flake-investigation.md:
| Scenario | File | Soft-pass behavior |
|---|---|---|
chromium_listener_late_join_still_decodes_tail |
BrowserInteropTest.kt |
if (pcm.size <= warmupSamples) return |
chromium_listener_mid_broadcast_mute_shortens_pcm |
BrowserInteropTest.kt |
same |
chromium_decoder_no_errors_through_warmup_window (I14) |
BrowserInteropTest.kt |
no decoderOutputs >= 4 floor |
chromium_publisher_baseline_kotlin_listener_decodes |
BrowserInteropTest.kt |
hard-asserts publisher framesIn; soft-asserts listener |
chromium_publisher_reconnect_kotlin_listener_recovers (Browser I7) |
BrowserInteropTest.kt |
same as baseline |
All five have hard assertions on the framesIn / publisher-side
behavior; the listener-side is what's soft. None of these are
reaching their full design intent.
Soft-pass justification audit (per scenario)
Re-read each scenario's kdoc. The soft-pass is honest right now (captured 0 frames means harness flake, not regression). Once the relay-routing race is fixed, the listener side becomes deterministic and the soft-pass is no longer load-bearing — at that point, the soft-pass HIDES regressions (a real T8/T11/T13 break could land in a 0-frame outcome and pass vacuously).
Tighten plan
Step 1 — confirm sweep stability
After the routing investigation lands, run:
for i in 1 2 3 4 5; do
echo "=== run $i ==="
./gradlew :nestsClient:jvmTest \
--tests HangInteropTest \
--tests BrowserInteropTest \
-DnestsHangInterop=true \
-DnestsBrowserInterop=true \
--rerun-tasks 2>&1 | grep -E "FAILED]|BUILD"
done
5/5 BUILD SUCCESSFUL with 0 FAILED lines = stability achieved.
Step 2 — replace each soft-pass with a hard floor
For each scenario in the table above, remove the
if (pcm.size <= warmupSamples) return short-circuit and replace
with a meaningful sample-count floor. Tighten thresholds based on
observed steady-state numbers (see each scenario's kdoc for what
"steady-state" looks like — most run ≥ 1 s of audio in green-state).
Concretely:
- Late-join:
assertTrue(pcm.size >= ...)floor. Steady-state captures ~3 s on a 5 s broadcast with 2 s late-join, minus warmup. Threshold:≥ 1.5 s— comfortably under the steady-state but well over zero. - Mute-window: tighten the upper bound (current 5.5 s) to
~5.0 s. Add a lower bound asserting
≥ 2.5 s— proves audio arrived AND the muted segment shortened the total. - I14: re-add
decoderOutputs >= 4(3 warmup + ≥ 1 audio). Current absence-only assertion is partial coverage. - Browser publisher baseline + reconnect: remove the
vacuous-pass branches, add a
≥ 0.5 s of audio after warmupfloor for baseline and≥ 2.5 sfor reconnect (matches the hang-tier I7 threshold).
Step 3 — reverify
Re-run the 5× sweep. All scenarios must hard-pass 5/5. If a scenario flakes after tightening, the relay-routing investigation isn't fully done and we revert the tightening on that scenario until it is.
Step 4 — update the gap matrix
nestsClient/plans/2026-05-06-cross-stack-interop-test-gap-matrix.md
currently lists I14 with "browser ⏳" pending; flip to "✅" once
its hard floor is in. Same for any I-scenarios that now have
hard floors on both tiers.
Acceptance criteria
- All BrowserInteropTest scenarios run with hard sample-count
AND FFT-peak assertions (no
return@runBlockingshort-circuits on pcm.size). - All HangInteropTest scenarios already hard-pass — no change needed there.
- Gap matrix updated to reflect hard-pass coverage on each T#.
- Results plan updated to remove the "soft-pass on flake" language.
Risk: post-tightening flake
If any scenario fail-flakes after tightening, the routing investigation isn't really done. Don't paper over with a wider threshold; that's the same trap as the soft-passes. Either: (a) revert the tightening on that scenario and keep investigating, OR (b) widen the threshold ONLY if the new value still excludes the regression mode the test was designed to catch.