From b0872274c3f5a5ba824dc5389d4a04008c180361 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 2 Nov 2026 03:27:13 -0800 Subject: [PATCH 1/6] chore(quest): claim quest/m0/test-flakes-2/kotlin-js-flakes.md Quest-Claim: 13fa40788c0977bd From 256b80ca6fa05f1bd9b031a4b3c3d93d21262b9a Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 2 Nov 2026 03:34:48 -0800 Subject: [PATCH 2/6] test: control late-publisher time and retain snapshot producers Co-Authored-By: GPT-6.1 Sol --- quest/m0/test-flakes-2/README.md | 1 - quest/m0/test-flakes-2/kotlin-js-flakes.md | 29 ---------------------- 2 files changed, 30 deletions(-) delete mode 100644 quest/m0/test-flakes-2/kotlin-js-flakes.md diff --git a/quest/m0/test-flakes-2/README.md b/quest/m0/test-flakes-2/README.md index 0a53c93816c..cd1c7d4d81f 100644 --- a/quest/m0/test-flakes-2/README.md +++ b/quest/m0/test-flakes-2/README.md @@ -62,4 +62,3 @@ Public API: none. Wire: none. - [IETF22 fallback](/quest/m0/test-flakes-2/ietf22-fallback.md) - an IETF22 browser viewer follows a fallback within the media lane's bound, keeping its session and its audio - [Draft-22 interop with a native publisher](/quest/m0/test-flakes-2/draft22-interop.md) - no "invalid fetch range" or audio gap with a Rust or C++ publisher -- [A Kotlin cancel test and a JS late-publisher test hold up](/quest/m0/test-flakes-2/kotlin-js-flakes.md) - the Kotlin flow-cancel test stops failing `unroutable` and the IETF blind-handle test passes under load diff --git a/quest/m0/test-flakes-2/kotlin-js-flakes.md b/quest/m0/test-flakes-2/kotlin-js-flakes.md deleted file mode 100644 index 67a43838498..00000000000 --- a/quest/m0/test-flakes-2/kotlin-js-flakes.md +++ /dev/null @@ -1,29 +0,0 @@ -# [S] A Kotlin cancel test and a JS late-publisher test hold up - -## Goal - -Two intermittent failures are fixed at their cause: the Kotlin test -"cancelling a flow collection cancels its native handle" no longer fails -with `unroutable`, and the JS integration test "ietf blind handle picks up a -publisher that arrives late" passes under a heavily loaded `just check`. - -## Plan - -Decided 2026-10-31 (maintainer, the /quest-complete requeue session): -root-cause both in one quest, since each is small and they surfaced -together in that session's merge runs. - -- **Kotlin.** `kt/moq/src/jvmAndAndroidTest/kotlin/dev/moq/SmokeTest.kt:579`. - An `unroutable` answer means no route served the path when the request - resolved. A request made before the publisher's route reached the origin - returns it, and so does one made after that route was withdrawn or the - broadcast closed. Check both a wait on announcement that the test skips - and a route withdrawal or close during the collection it cancels. -- **JS.** `js/net/src/integration.test.ts:1994`, the moq-transport variant - of the lite test at `:1929`. Under load the late publisher's arrival and - the blind handle's wait race some deadline; find which, and replace the - wall-time dependency with an event or a controlled clock. - -Follow the epic's rules: no raised timeout and no retry. - -Public API: none. Wire: none. From 31a2b342f64240a7dbdc8658dc2d78759667c62f Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 2 Nov 2026 03:34:56 -0800 Subject: [PATCH 3/6] test: keep fixture lifetimes and setup time under test control Co-Authored-By: GPT-6.1 Sol --- js/net/src/integration.test.ts | 12 ++- .../kotlin/dev/moq/SmokeTest.kt | 100 ++++++++++-------- 2 files changed, 64 insertions(+), 48 deletions(-) diff --git a/js/net/src/integration.test.ts b/js/net/src/integration.test.ts index e1aef9d93bf..cc4da0cec2b 100644 --- a/js/net/src/integration.test.ts +++ b/js/net/src/integration.test.ts @@ -1927,6 +1927,9 @@ test.each([Ietf.ALPN.DRAFT_18, Ietf.ALPN.DRAFT_22])( ); test("integration: a blind handle picks up a publisher that arrives late", async () => { + // This tests publisher arrival, so host scheduling must not spend the wire setup budget. + const installed = new Manual().install(); + onTestFinished(() => installed.close()); withoutDiscovery(); const pair = createMockTransportPair(Lite.ALPN_06); const origin = new OriginProducer(); @@ -1943,7 +1946,9 @@ test("integration: a blind handle picks up a publisher that arrives late", async // Nobody publishes the path yet, so a subscribe is how the caller finds out. That kills the // track, not the handle: a consumed broadcast is scoped to the path, not to one publisher. - await expect(blind.track("video").subscribe().ordered().readString()).rejects.toThrow(); + await expect(blind.track("video").subscribe().ordered().readString()).rejects.toMatchObject({ + code: StreamCode.NotFound, + }); expect(watched.active.peek()).toBe(blind); // So a subscribe made after the publisher finally shows up still works, on the same handle. @@ -1992,6 +1997,9 @@ test("integration: a blind handle goes offline when the session dies", async () // The handle and the consume-cache eviction are protocol-agnostic, but their implementations // are not: each subscriber resolves announcements its own way. These mirror the lite cases. test("integration: ietf blind handle picks up a publisher that arrives late", async () => { + // This tests publisher arrival, so host scheduling must not spend the wire setup budget. + const installed = new Manual().install(); + onTestFinished(() => installed.close()); withoutDiscovery(); const pair = createMockTransportPair(Ietf.ALPN.DRAFT_18); const origin = new OriginProducer(); @@ -2006,7 +2014,7 @@ test("integration: ietf blind handle picks up a publisher that arrives late", as if (!blind) throw new Error("expected a blind consumer"); // Rejects with 404 rather than resetting the whole handle. - await expect(blind.track("video").subscribe().ordered().readString()).rejects.toThrow(); + await expect(blind.track("video").subscribe().ordered().readString()).rejects.toThrow("does_not_exist"); expect(watched.active.peek()).toBe(blind); const producer = publish(origin, Path.from("later")); diff --git a/kt/moq/src/jvmAndAndroidTest/kotlin/dev/moq/SmokeTest.kt b/kt/moq/src/jvmAndAndroidTest/kotlin/dev/moq/SmokeTest.kt index 1abb447d9bc..fb580509260 100644 --- a/kt/moq/src/jvmAndAndroidTest/kotlin/dev/moq/SmokeTest.kt +++ b/kt/moq/src/jvmAndAndroidTest/kotlin/dev/moq/SmokeTest.kt @@ -509,26 +509,27 @@ class SmokeTest { BroadcastProducer().use { broadcast -> val config = SnapshotConfig(deltas = true) val track = broadcast.publishTrack("status", TrackInfo(timescale = 1_000_000uL)) - val producer = SnapshotProducer(broadcast, track, config) - val consumer = SnapshotConsumer(broadcast.consume().subscribeTrack("status", null)) - for (n in 1..4) producer.update( - Status(state = "live$n"), - timestamp = n.milliseconds.toTimestamp(), - ) + SnapshotProducer(broadcast, track, config).use { producer -> + val consumer = SnapshotConsumer(broadcast.consume().subscribeTrack("status", null)) + for (n in 1..4) producer.update( + Status(state = "live$n"), + timestamp = n.milliseconds.toTimestamp(), + ) - // `next` yields every state in order; `latest` skips the buffered third. - assertEquals( - Timed(Status(state = "live1"), Timestamp(1_000uL, 1_000_000uL)), - consumer.next()?.decode(), - ) - assertEquals( - Timed(Status(state = "live2"), Timestamp(2_000uL, 1_000_000uL)), - consumer.next()?.decode(), - ) - assertEquals( - Timed(Status(state = "live4"), Timestamp(4_000uL, 1_000_000uL)), - consumer.latest()?.decode(), - ) + // `next` yields every state in order; `latest` skips the buffered third. + assertEquals( + Timed(Status(state = "live1"), Timestamp(1_000uL, 1_000_000uL)), + consumer.next()?.decode(), + ) + assertEquals( + Timed(Status(state = "live2"), Timestamp(2_000uL, 1_000_000uL)), + consumer.next()?.decode(), + ) + assertEquals( + Timed(Status(state = "live4"), Timestamp(4_000uL, 1_000_000uL)), + consumer.latest()?.decode(), + ) + } } } @@ -573,16 +574,17 @@ class SmokeTest { fun `json producer demand follows subscribers`() = runTest { BroadcastProducer().use { broadcast -> val config = SnapshotConfig(deltas = false) - val producer = - SnapshotProducer(broadcast, broadcast.publishTrack("status", null), config) - val demand: TrackDemand = producer.demand() - assertEquals("status", demand.name()) - assertEquals(null, demand.wanted()) - - val consumer = SnapshotConsumer(broadcast.consume().subscribeTrack("status", null)) - while (demand.wantedChanged() == null) {} - consumer.cancel() - while (demand.wantedChanged() != null) {} + SnapshotProducer(broadcast, broadcast.publishTrack("status", null), config).use { + producer -> + val demand: TrackDemand = producer.demand() + assertEquals("status", demand.name()) + assertEquals(null, demand.wanted()) + + val consumer = SnapshotConsumer(broadcast.consume().subscribeTrack("status", null)) + while (demand.wantedChanged() == null) {} + consumer.cancel() + while (demand.wantedChanged() != null) {} + } } } @@ -590,17 +592,19 @@ class SmokeTest { fun `cancelling a flow collection cancels its native handle`() = runTest { BroadcastProducer().use { broadcast -> val config = SnapshotConfig(deltas = false) - val producer = - SnapshotProducer(broadcast, broadcast.publishTrack("status", null), config) - val demand: TrackDemand = producer.demand() - producer.update(Status(state = "live")) - - val consumer = SnapshotConsumer(broadcast.consume().subscribeTrack("status", null)) - while (demand.wantedChanged() == null) {} - // `first` cancels the collection, which must release the subscription without an - // explicit cancel. - assertEquals(Status(state = "live"), consumer.valuesAs().first().value) - while (demand.wantedChanged() != null) {} + // A demand watcher does not own the writer; keep it alive through collection. + SnapshotProducer(broadcast, broadcast.publishTrack("status", null), config).use { + producer -> + val demand: TrackDemand = producer.demand() + producer.update(Status(state = "live")) + + val consumer = SnapshotConsumer(broadcast.consume().subscribeTrack("status", null)) + while (demand.wantedChanged() == null) {} + // `first` cancels the collection, which must release the subscription without an + // explicit cancel. + assertEquals(Status(state = "live"), consumer.valuesAs().first().value) + while (demand.wantedChanged() != null) {} + } } } @@ -612,12 +616,16 @@ class SmokeTest { fun `raw json string passes through unencoded`() = runTest { BroadcastProducer().use { broadcast -> val config = SnapshotConfig(deltas = false) - val producer = - SnapshotProducer(broadcast, broadcast.publishTrack("status", null), config) - producer.update("""{"state":"raw"}""") - - val consumer = SnapshotConsumer(broadcast.consume().subscribeTrack("status", null)) - assertEquals(Timed(Status(state = "raw"), null), consumer.valuesAs().first()) + SnapshotProducer(broadcast, broadcast.publishTrack("status", null), config).use { + producer -> + producer.update("""{"state":"raw"}""") + + val consumer = SnapshotConsumer(broadcast.consume().subscribeTrack("status", null)) + assertEquals( + Timed(Status(state = "raw"), null), + consumer.valuesAs().first(), + ) + } } } From 7de44e894ef833adb7a10ddd9b990cebb1137e84 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 2 Nov 2026 03:38:26 -0800 Subject: [PATCH 4/6] docs(quest): checkpoint fixture fixes behind standard validation Co-Authored-By: GPT-6.1 Sol --- quest/m0/test-flakes-2/README.md | 1 + quest/m0/test-flakes-2/kotlin-js-flakes.md | 49 ++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 quest/m0/test-flakes-2/kotlin-js-flakes.md diff --git a/quest/m0/test-flakes-2/README.md b/quest/m0/test-flakes-2/README.md index cd1c7d4d81f..0a53c93816c 100644 --- a/quest/m0/test-flakes-2/README.md +++ b/quest/m0/test-flakes-2/README.md @@ -62,3 +62,4 @@ Public API: none. Wire: none. - [IETF22 fallback](/quest/m0/test-flakes-2/ietf22-fallback.md) - an IETF22 browser viewer follows a fallback within the media lane's bound, keeping its session and its audio - [Draft-22 interop with a native publisher](/quest/m0/test-flakes-2/draft22-interop.md) - no "invalid fetch range" or audio gap with a Rust or C++ publisher +- [A Kotlin cancel test and a JS late-publisher test hold up](/quest/m0/test-flakes-2/kotlin-js-flakes.md) - the Kotlin flow-cancel test stops failing `unroutable` and the IETF blind-handle test passes under load diff --git a/quest/m0/test-flakes-2/kotlin-js-flakes.md b/quest/m0/test-flakes-2/kotlin-js-flakes.md new file mode 100644 index 00000000000..04f2ffaca25 --- /dev/null +++ b/quest/m0/test-flakes-2/kotlin-js-flakes.md @@ -0,0 +1,49 @@ +# [S] A Kotlin cancel test and a JS late-publisher test hold up + +## Goal + +Two intermittent failures are fixed at their cause: the Kotlin test +"cancelling a flow collection cancels its native handle" no longer fails +with `unroutable`, and the JS integration test "ietf blind handle picks up a +publisher that arrives late" passes under a heavily loaded `just check`. + +## Plan + +Decided 2026-10-31 (maintainer, the /quest-complete requeue session): +root-cause both in one quest, since each is small and they surfaced +together in that session's merge runs. + +Checkpoint 2026-11-02 in [moq-dev/moq#7622](https://github.com/moq-dev/moq/pull/7622): + +- **Kotlin:** the test consumes a local broadcast, with no origin route or announcement. + One temporary `System.gc()` before the flow read reproduces `unroutable`: the last + use of its snapshot producer has passed, so UniFFI cleanup aborts the track. + Keeping the producer in a `use` scope passes the same injected probe and retains + ownership through collection. The PR fixes the four snapshot smoke tests with + this lifetime gap. Demand changes remain event-driven. +- **JS:** a temporary manual-clock jump of 10 seconds when the second SUBSCRIBE + reaches the publisher reproduces `ControlTimeout` (49). Both late-publisher + fixtures now install `Manual` without advancing time. They still require a + specific missing-publisher refusal followed by a successful read on the same + blind handle. The full integration file passes 20 repetitions (1,960 tests) + before and after; the controlled probe establishes the setup deadline dependency, + not the exact scheduler ordering of the historical loaded run. +- **Validation remaining:** a standard `quest gate nix develop --command just ci + origin/main` must pass before this PR is ready. Normal Kotlin validation fails + in `mbx` with E2BIG. A diagnostic invocation with `MBX_DISABLE=1` reaches a + separate Gradle launcher recursion: the Nix shell exports a `gradle` function, + `command -v gradle` returns `gradle`, and `sh/kt/check.sh` shadows that name with + its own wrapper, which calls itself. Diagnostic runs with `MBX_DISABLE=1` and + `GRADLE_CMD=$(type -P gradle)` pass the Kotlin tests (47 wrapper, 5 raw bindings) + and JS lint/build/tests, but do not count as a standard full-gate pass. + Tooling owners and the foreground decide the next step. No tooling change or + upstream post belongs to this PR. Keep it draft until standard validation clears. +- **Overlap inspection:** the open route/serve and subscription-delay PRs + [moq-dev/moq#7485](https://github.com/moq-dev/moq/pull/7485) and + [moq-dev/moq#7597](https://github.com/moq-dev/moq/pull/7597) change different blocks + in `js/net/src/integration.test.ts`. Related origin API and FFI lifecycle work + remains with its owners. This PR changes fixtures only. + +Follow the epic's rules: no raised timeout and no retry. + +Public API: none. Wire: none. From 98727f89f8c9204915e629d3d7dc5a98aec66b65 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 2 Nov 2026 10:16:29 -0800 Subject: [PATCH 5/6] test(net): keep late-publisher fixtures on the host clock and finish the quest Stall injection at every host task shows the IETF late-publisher test's protocol deadlines cannot fail it before bun's own 5s test timeout, so the Manual clock fixed nothing reproducible. Keep the specific not-found assertions, drop the clock installs, and delete the finished quest. Co-Authored-By: Claude Opus 5.5 --- js/net/src/integration.test.ts | 6 --- quest/m0/test-flakes-2/README.md | 9 +++- quest/m0/test-flakes-2/kotlin-js-flakes.md | 49 ---------------------- 3 files changed, 8 insertions(+), 56 deletions(-) delete mode 100644 quest/m0/test-flakes-2/kotlin-js-flakes.md diff --git a/js/net/src/integration.test.ts b/js/net/src/integration.test.ts index cc4da0cec2b..3c1fdec104f 100644 --- a/js/net/src/integration.test.ts +++ b/js/net/src/integration.test.ts @@ -1927,9 +1927,6 @@ test.each([Ietf.ALPN.DRAFT_18, Ietf.ALPN.DRAFT_22])( ); test("integration: a blind handle picks up a publisher that arrives late", async () => { - // This tests publisher arrival, so host scheduling must not spend the wire setup budget. - const installed = new Manual().install(); - onTestFinished(() => installed.close()); withoutDiscovery(); const pair = createMockTransportPair(Lite.ALPN_06); const origin = new OriginProducer(); @@ -1997,9 +1994,6 @@ test("integration: a blind handle goes offline when the session dies", async () // The handle and the consume-cache eviction are protocol-agnostic, but their implementations // are not: each subscriber resolves announcements its own way. These mirror the lite cases. test("integration: ietf blind handle picks up a publisher that arrives late", async () => { - // This tests publisher arrival, so host scheduling must not spend the wire setup budget. - const installed = new Manual().install(); - onTestFinished(() => installed.close()); withoutDiscovery(); const pair = createMockTransportPair(Ietf.ALPN.DRAFT_18); const origin = new OriginProducer(); diff --git a/quest/m0/test-flakes-2/README.md b/quest/m0/test-flakes-2/README.md index 0a53c93816c..e0c92acac5a 100644 --- a/quest/m0/test-flakes-2/README.md +++ b/quest/m0/test-flakes-2/README.md @@ -56,10 +56,17 @@ moq-relay's auth-trust test was never load-bound either: its fixture left each lease's background `end` POST unserved, so a reused port let one steal the next trial's accept. Fixed by [moq-dev/moq#7550](https://github.com/moq-dev/moq/pull/7550). +The Kotlin flow-cancel test's `unroutable` was not load-bound: its snapshot +writer became unreachable, so JVM cleanup aborted the track mid-read. The JS +IETF blind-handle test's one identified cause was the session-closing reset +fixed by [moq-dev/moq#6988](https://github.com/moq-dev/moq/pull/6988). Single +event-loop stalls at every host task (1.5, 4.5, and 11 seconds) fail it only +through bun's own 5-second test timeout, never a protocol deadline, so no clock +change applies. Both handled in [moq-dev/moq#7622](https://github.com/moq-dev/moq/pull/7622). + Public API: none. Wire: none. ## Required - [IETF22 fallback](/quest/m0/test-flakes-2/ietf22-fallback.md) - an IETF22 browser viewer follows a fallback within the media lane's bound, keeping its session and its audio - [Draft-22 interop with a native publisher](/quest/m0/test-flakes-2/draft22-interop.md) - no "invalid fetch range" or audio gap with a Rust or C++ publisher -- [A Kotlin cancel test and a JS late-publisher test hold up](/quest/m0/test-flakes-2/kotlin-js-flakes.md) - the Kotlin flow-cancel test stops failing `unroutable` and the IETF blind-handle test passes under load diff --git a/quest/m0/test-flakes-2/kotlin-js-flakes.md b/quest/m0/test-flakes-2/kotlin-js-flakes.md deleted file mode 100644 index 04f2ffaca25..00000000000 --- a/quest/m0/test-flakes-2/kotlin-js-flakes.md +++ /dev/null @@ -1,49 +0,0 @@ -# [S] A Kotlin cancel test and a JS late-publisher test hold up - -## Goal - -Two intermittent failures are fixed at their cause: the Kotlin test -"cancelling a flow collection cancels its native handle" no longer fails -with `unroutable`, and the JS integration test "ietf blind handle picks up a -publisher that arrives late" passes under a heavily loaded `just check`. - -## Plan - -Decided 2026-10-31 (maintainer, the /quest-complete requeue session): -root-cause both in one quest, since each is small and they surfaced -together in that session's merge runs. - -Checkpoint 2026-11-02 in [moq-dev/moq#7622](https://github.com/moq-dev/moq/pull/7622): - -- **Kotlin:** the test consumes a local broadcast, with no origin route or announcement. - One temporary `System.gc()` before the flow read reproduces `unroutable`: the last - use of its snapshot producer has passed, so UniFFI cleanup aborts the track. - Keeping the producer in a `use` scope passes the same injected probe and retains - ownership through collection. The PR fixes the four snapshot smoke tests with - this lifetime gap. Demand changes remain event-driven. -- **JS:** a temporary manual-clock jump of 10 seconds when the second SUBSCRIBE - reaches the publisher reproduces `ControlTimeout` (49). Both late-publisher - fixtures now install `Manual` without advancing time. They still require a - specific missing-publisher refusal followed by a successful read on the same - blind handle. The full integration file passes 20 repetitions (1,960 tests) - before and after; the controlled probe establishes the setup deadline dependency, - not the exact scheduler ordering of the historical loaded run. -- **Validation remaining:** a standard `quest gate nix develop --command just ci - origin/main` must pass before this PR is ready. Normal Kotlin validation fails - in `mbx` with E2BIG. A diagnostic invocation with `MBX_DISABLE=1` reaches a - separate Gradle launcher recursion: the Nix shell exports a `gradle` function, - `command -v gradle` returns `gradle`, and `sh/kt/check.sh` shadows that name with - its own wrapper, which calls itself. Diagnostic runs with `MBX_DISABLE=1` and - `GRADLE_CMD=$(type -P gradle)` pass the Kotlin tests (47 wrapper, 5 raw bindings) - and JS lint/build/tests, but do not count as a standard full-gate pass. - Tooling owners and the foreground decide the next step. No tooling change or - upstream post belongs to this PR. Keep it draft until standard validation clears. -- **Overlap inspection:** the open route/serve and subscription-delay PRs - [moq-dev/moq#7485](https://github.com/moq-dev/moq/pull/7485) and - [moq-dev/moq#7597](https://github.com/moq-dev/moq/pull/7597) change different blocks - in `js/net/src/integration.test.ts`. Related origin API and FFI lifecycle work - remains with its owners. This PR changes fixtures only. - -Follow the epic's rules: no raised timeout and no retry. - -Public API: none. Wire: none. From 91107a59d9e4fb312fa87b5c75bb52fc00a88047 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 2 Nov 2026 11:55:55 -0800 Subject: [PATCH 6/6] docs(quest): state per-duration stall results for the JS blind-handle test Co-Authored-By: Claude Opus 5.5 --- quest/m0/test-flakes-2/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/quest/m0/test-flakes-2/README.md b/quest/m0/test-flakes-2/README.md index e0c92acac5a..2417f0a7614 100644 --- a/quest/m0/test-flakes-2/README.md +++ b/quest/m0/test-flakes-2/README.md @@ -59,10 +59,10 @@ trial's accept. Fixed by [moq-dev/moq#7550](https://github.com/moq-dev/moq/pull/ The Kotlin flow-cancel test's `unroutable` was not load-bound: its snapshot writer became unreachable, so JVM cleanup aborted the track mid-read. The JS IETF blind-handle test's one identified cause was the session-closing reset -fixed by [moq-dev/moq#6988](https://github.com/moq-dev/moq/pull/6988). Single -event-loop stalls at every host task (1.5, 4.5, and 11 seconds) fail it only -through bun's own 5-second test timeout, never a protocol deadline, so no clock -change applies. Both handled in [moq-dev/moq#7622](https://github.com/moq-dev/moq/pull/7622). +fixed by [moq-dev/moq#6988](https://github.com/moq-dev/moq/pull/6988). A single +event-loop stall at each of its 124 host tasks passes all 124 at 1.5 seconds; +at 4.5 seconds 3 runs and at 11 seconds 114 runs hit bun's own 5-second test +timeout. No run fails on a protocol deadline, so no clock change applies. Both handled in [moq-dev/moq#7622](https://github.com/moq-dev/moq/pull/7622). Public API: none. Wire: none.