54f667f5bd
Two production-path bugs surfaced during a full interop sweep (`./gradlew :nestsClient:jvmTest -DnestsInterop=true` + `-DnestsHangInterop=true`) plus the toolchain / harness friction that was hiding them. Production fixes: - ReconnectingNestsSpeaker's hot-swap path opens publishers via `openPublisherForHotSwap` instead of `startBroadcasting`, so the underlying `MoqLiteNestsSpeaker`'s state machine never made the Connected -> Broadcasting transition. The reconnect wrapper mirrors that state, so callers waiting on Broadcasting (the VM, `connectReconnectingNestsSpeaker` interop tests) hung on Connected forever. Adds `HotSwappablePublisherSource.reportBroadcasting(isMuted)`, implemented in `MoqLiteNestsSpeaker`, and the hot-swap pump now calls it each iteration so a JWT-refreshed session re-enters Broadcasting too. - The stale-group filter on listener reconnect assumes monotonic group lineage across publisher session-restarts (true for ReconnectingNestsSpeaker, which seeds each new publisher with the prior `nextSequence`; false for external publishers like kixelated's hang-publish reference, which mints a fresh state on every reconnect and restarts at 0). Without compensation, the watermark from a session-1 max ~18 dropped the entire post-restart stream from session 2. The collect now resets the watermark on the first object of a new subscription when its group id arrives well below the current watermark — a publisher-restart signal that a relay-cache replay (which carries exactly the prior max) wouldn't produce. Test harness fixes — these are what blocked the suites from running at all on a clean Apple-Silicon box: - NostrNestsHarness: the cloned `docker-compose-moq.yml` declares no `depends_on`, so on a cold `up -d` moq-relay raced moq-auth's Node boot, got `Connection refused` on its JWKS GET, exited with no retry, and every later QUIC handshake failed with "read loop exited (socket closed or peer closed)". Gate on moq-auth's /health first, then idempotent `up -d moq-relay` so the relay always boots against a live auth sidecar. - nestsClient/build.gradle.kts: cargo builds inside the hang-interop task panic under CMake 4.x because `audiopus_sys` / rustls' aws-lc-sys ship a `CMakeLists.txt` that predates CMake 4's minimum-version floor. Set `CMAKE_POLICY_VERSION_MINIMUM=3.5` on each cargo Exec. - JvmOpusEncoder + the hang-interop Test task: opus-java 1.1.1's bundled `natives/darwin/libopus.dylib` is x86_64-only, so its in-jar loader reports unsupported on Apple Silicon. Probe a small set of canonical system libopus locations (`brew install opus` on macOS, distro paths on linux) and `System.load` by absolute path so the symbols are in the process when JNA's lazy `Opus.INSTANCE` init falls back to RTLD_DEFAULT. Gradle also threads `/opt/homebrew/opt/opus/lib` onto `jna.library.path` for completeness; both paths are no-ops where the in-jar binary already loads. After these: - :nestsClient:jvmTest -DnestsInterop=true — 312/312, 0 fail - :nestsClient:jvmTest -DnestsHangInterop=true — 312/312, 0 fail - quic/interop/run-matrix.sh -s aioquic — 19 passed, 0 failed, 3 unsupported (E/V2/CM are documented amethyst gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>