From 29bcb5192f788c58a8e8e5aab444904347c9aa70 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Thu, 12 Nov 2026 20:10:50 -0800 Subject: [PATCH 1/2] chore(quest): claim quest/m2/cluster-routes/handoff-revival.md Quest-Claim: 3365d83b78bc3708 From 3d5ee100c39639689690da2e8109cff3aa72d4eb Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 13 Nov 2026 02:05:19 -0800 Subject: [PATCH 2/2] test(net): pin handoff scenario 16316 as a plain test, and sweep 20,000 nightly Scenario 16316 of sweep_handoff failed its false-END assertion, not the revival one, at 688312b9eb. #8540 fixed it: undoing that fix's one line brings the failure back. The shrunk case is now a plain test, and nightly runs the handoff sweeps over 20,000 scenarios. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/nightly.yml | 1 + quest/m2/cluster-routes/handoff-revival.md | 33 ---------------------- rs/moq-net/src/route/tests/handoff.rs | 31 ++++++++++++++++++++ test/route-sweep.sh | 2 ++ 4 files changed, 34 insertions(+), 33 deletions(-) delete mode 100644 quest/m2/cluster-routes/handoff-revival.md diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 4109238a0e2..27c5654660e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -363,6 +363,7 @@ jobs: # `test resume-model` sweeps resume against its model from a fresh seed; PRs run a fixed 64. # `test route-key-model` proves the route key proof with Tamarin, and that each variant breaks what it names. # `test route-sweep` checks random lite-07 meshes against the route rules from a fresh seed; PRs run a fixed 8. + # It also runs the router's handoff sweeps over 20,000 fixed scenarios; PRs run 150. # It also runs the bandwidth probe's acceptance suite, of which PRs run the short cases. # `test drill impaired` runs the relay drills over a freshly seeded shaper; PRs run loopback. # `rs cli-export` runs moq-cli's export process tests, which take tens of seconds of real time. diff --git a/quest/m2/cluster-routes/handoff-revival.md b/quest/m2/cluster-routes/handoff-revival.md deleted file mode 100644 index c75c2bed94d..00000000000 --- a/quest/m2/cluster-routes/handoff-revival.md +++ /dev/null @@ -1,33 +0,0 @@ -# [M] The handoff sweep revives no ended claim - -## Goal - -`sweep_handoff` in `rs/moq-net/src/route/tests/handoff.rs` reports no revival -over 20,000 scenarios: no reader sees one life of a claim start again after -it saw that life end, unless it forgot the claim in between. A publisher that -withdraws a claim and announces it again starts a new life, which is no -revival. The scenario that revives one today is a plain test. - -## Plan - -Found 2026-11-11 by running the sweep past its 150 scenarios: scenario 16316 -revives a claim, on `main` at `688312b9eb`, and no earlier one does. It is -the same whichever neighbours the router believes. It has not been traced. -Decided the same day (maintainer, /quest-plan): ✅ plan it. - -- Reproduce it: the sweep draws every scenario from one random stream, so run - the first 16,317 with `MOQ_ROUTE_SCENARIOS=16317`. Record the scenario's - steps as it runs and remove them one at a time while the revival remains. -- Decide whether it is a revival the contract forbids or one it excuses: a - replay after a collection or a restart is allowed only until the - withdrawal behind it lands - ([epic](/quest/m2/cluster-routes/README.md), handoff contract). If - the fixture's `revivals` count misses an excuse, fix the count and say so. -- Otherwise fix the cause and keep the shrunk case as a test. -- If the cause is in what the path rule replaces (the distance, the seqno, - route requests, the echo, or which neighbours certify a region), pin it as - a `residual_` test naming - [the route per scope](/quest/m2/cluster-routes/scope.md), whose - router must pass it, instead of fixing it twice. - -Public API: none. Wire: none. diff --git a/rs/moq-net/src/route/tests/handoff.rs b/rs/moq-net/src/route/tests/handoff.rs index 7b6ca299a5a..248910b1f83 100644 --- a/rs/moq-net/src/route/tests/handoff.rs +++ b/rs/moq-net/src/route/tests/handoff.rs @@ -594,6 +594,37 @@ fn widening_past_a_changed_claim_moves_it_up() { assert_eq!(false_ends(&sim.events), 0); } +/// A client widens past a claim that changed while its relay had lost the +/// origin. When the relay gets the origin back, the client's narrow +/// presentation moves up to the changed claim without ending. +#[test] +fn widening_while_the_relay_lost_the_origin_moves_the_claim_up() { + let (origin, relay, client) = (0, 1, 2); + let mut sim = Sim::new(3); + sim.leaf(origin); + sim.leaf(client); + sim.join(origin, relay, 1); + sim.join(client, relay, 1); + sim.originate(origin, 7, 0); + assert!(sim.run()); + sim.announce(origin, "live/", 2, None); + sim.watch(client, "live/b"); + for (from, to) in [(origin, relay), (origin, relay), (relay, client), (relay, client)] { + assert!(sim.deliver(from, to)); + } + assert_eq!(sim.shows(client, 7, "live/b"), Some(true)); + + // The relay's answer to the old interest is still queued when the client widens. + sim.disconnect(origin, relay); + sim.announce(origin, "live/", 0, None); + sim.watch(client, ""); + sim.connect(origin, relay); + assert!(sim.run()); + assert_eq!(sim.shows(client, 7, "live/"), Some(true)); + assert_eq!(sim.shown(client).len(), 1); + assert_eq!(false_ends(&sim.events), 0); +} + /// A claim withdrawn below one its origin still has ends: the claim above /// covers its path but is not the claim it was. #[test] diff --git a/test/route-sweep.sh b/test/route-sweep.sh index 9c9d12c718a..e946d8dec8a 100755 --- a/test/route-sweep.sh +++ b/test/route-sweep.sh @@ -10,3 +10,5 @@ echo "Route sweep: MOQ_ROUTE_SEED=$MOQ_ROUTE_SEED MOQ_ROUTE_CASES=$MOQ_ROUTE_CAS # Release keeps the sweep inside nextest's hang budget; the checks stay on so it still catches what a debug run would. export CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS=true CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS=true just rs test -p moq-net --release --features async --test integration -E 'test(=mesh_sweep::seeded_meshes_hold_the_route_rules)' +# The router's handoff sweeps replay their fixed scenarios past the gate's 150. +MOQ_ROUTE_SCENARIOS=${MOQ_ROUTE_SCENARIOS:-20000} just rs test -P sweep -p moq-net --release -E 'test(/^route::tests::handoff::sweep_/)'