diff --git a/quest/m0/qmux-credit.md b/quest/m0/qmux-credit.md index df04b21d68..bb8d5ac92f 100644 --- a/quest/m0/qmux-credit.md +++ b/quest/m0/qmux-credit.md @@ -40,7 +40,9 @@ Work: close issued mid-write. - Release on both lines (0.5.x after 0.5.2 from [qmux reset race](/quest/m0/qmux-reset-race.md), and 0.6.x), then bump - `main`'s pin. `dev` picks up 0.6.x. + `main`'s pin to that 0.5.x. `main` stays on 0.5: 0.6 needs + web-transport-trait 0.5, a breaking change that belongs on `dev`, which + picks up 0.6.x. Why m0: the WebSocket fallback and the planned edge-to-core `tls://` links both run on qmux, and MoQ drops streams constantly. diff --git a/quest/m1/README.md b/quest/m1/README.md index 07ed63e03f..329514cfc8 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -41,6 +41,7 @@ QUIC studies there on that rule. - [WebTransport close upstream](/quest/m1/wt-close-upstream.md) - web-transport-moq delivers the close capsule itself, and moq-tokio's `CLOSE_LINGER` is deleted - [Browser close code](/quest/m1/browser-close-code.md) - a playwright case proves the page reads a relay's close code and reason, on every web-transport backend - [Resumed groups](/quest/m1/resume-latest.md) - a half-delivered group ends once the new copy is past it, so a group-only reader never parks after a mid-group failover +- [Truncated groups fail finished()](/quest/m1/finished-truncated.md) - a spliced group whose continuation can never arrive fails `finished()` instead of reporting a clean end at the seam - [SUBSCRIBE_DROP](/quest/m1/subscribe-drop.md) - every stream group in a lite subscription arrives or is dropped by name, and lite-07 drops its stream count for it - [Late lower groups](/quest/m1/lite-late-lower-group.md) - a moq-lite subscriber with a floor receives a group created below the first served one, as moq-transport does - [Parked reads wake](/quest/m1/parked-read-wakes.md) - a read parked on an evicted or aborted group wakes and re-judges, for resume successors and plain tracks alike @@ -52,6 +53,7 @@ QUIC studies there on that rule. - [Watch and publish under CSP](/quest/m1/csp-assets.md) - blob workers stay the default; strict-CSP apps host the files and set a base URL - [More tests under load](/quest/m1/test-flakes-2/README.md) - the second round of load-only failures, one quest per flake, fixed at the cause - [A week of nightly interop after #4529](/quest/m1/interop-week.md) - the nightly traces the stall diagnosis reads +- [Nightly tests on macOS and Windows](/quest/m1/nightly-platform-tests.md) - `moq-auth`, `hang`, `moq-tokio`, and `moq-native` tests run nightly where `Instant` and sockets differ, not just compile - [CI runner stalls](/quest/m1/ci-runner-stalls.md) - the 0.4 to 0.8 s freezes of both interop tracks on CI are attributed from a week of nightlies and fixed or told apart from playback bugs - [Catalog estimate rate](/quest/m1/catalog-estimate-rate.md) - a rising `jitter`/`delay` estimate republishes the catalog at most once a second, in js/publish and moq-mux - [Rewind detail](/quest/m1/timestamp-rewind-detail.md) - a refused timestamp rewind names the frame's timestamp and the live edge diff --git a/quest/m1/finished-truncated.md b/quest/m1/finished-truncated.md new file mode 100644 index 0000000000..9e052dd2fe --- /dev/null +++ b/quest/m1/finished-truncated.md @@ -0,0 +1,37 @@ +# [S] A truncated group never reports a clean end + +## Goal + +`group::Consumer::finished()` on a spliced group succeeds only at the +original group's real end. When the continuation past a bounded copy can never +arrive (pruned, or the new route skip-declared the group), `finished()` fails +with the error that killed that route instead of returning `Ok(cap)`, so a +caller can't mistake a truncated group for a complete one. + +## Plan + +`poll_finished` in `rs/moq-net/src/model/resume.rs` returns `Ok(cap)` when +`poll_covering` finds no route for the seam, and its doc comment calls that +"the logical group's total frame count". That contradicts `group.rs`, where +`finished()` answers for the cursor and only a real end is clean. +[#4651](https://github.com/moq-dev/moq/pull/4651) fixed the same mismatch on +the path where the continuation answers. + +Decisions (2026-10-01): + +- ✅ `finished()` means the original group's end; a truncated group fails. + Rejected: redefining `finished()` as wherever the copy stopped, and dropping + the mismatch as too small. +- ✅ The error is the one the dead route recorded (`bury()`), falling back to + an existing variant. Rejected: a new public `Error::Truncated`. + +Work: change the no-route arm, fix the doc comment, and rewrite +`finished_resolves_for_a_pruned_bounded_group` and +`finished_resolves_when_the_successor_skips_the_seam` to expect the error. +Check `moq-mux`'s consumer still drops such a group as aborted. + +Public API: behavior only (an error where `Ok` was returned). Wire: none. + +## Related + +- [Resumed groups](/quest/m1/resume-latest.md) - same `poll_finished` subscription path diff --git a/quest/m1/nightly-platform-tests.md b/quest/m1/nightly-platform-tests.md new file mode 100644 index 0000000000..ea3c75c7c1 --- /dev/null +++ b/quest/m1/nightly-platform-tests.md @@ -0,0 +1,25 @@ +# [S] Nightly tests on macOS and Windows + +## Goal + +A nightly job runs `cargo test` for `moq-auth`, `hang`, `moq-tokio`, and +`moq-native` on macOS and Windows runners and alerts like the other nightly +jobs, so platform-only behavior is tested and not just compiled. + +## Plan + +Today `.github/workflows/platform.yml` runs `just rs windows|macos`, which only +`cargo check`s (`sh/rs/select.sh`), and every `nightly.yml` job runs on +`ubuntu-24.04-arm`. [#4600](https://github.com/moq-dev/moq/pull/4600)'s +regressions exercise different clocks: `Instant` overflow in `moq-auth` fails on +macOS and `SystemTime` overflow in `hang` fails on Windows. On Linux they only +prove no panic, so CI never runs them where they matter. + +Decision (2026-10-01): ✅ the platform-sensitive crates above. Rejected: the +whole workspace (slower, more flake surface) and only `moq-auth` + `hang`. + +Add a `just` recipe per platform beside the existing check, wire it into +`nightly.yml`'s matrix, and make sure `alert.yml` covers it. Fix or quarantine +anything that only fails there at its cause. + +Public API: none. Wire: none. diff --git a/quest/m1/test-flakes-2/media-late-join.md b/quest/m1/test-flakes-2/media-late-join.md index c795da647c..943532ef8b 100644 --- a/quest/m1/test-flakes-2/media-late-join.md +++ b/quest/m1/test-flakes-2/media-late-join.md @@ -2,8 +2,8 @@ ## Goal -`just test media` late join holds its one-GOP budget under load, or the -regression behind it is fixed. +Late join holds its one-GOP budget under load in both `just test media` and +the interop browser lane, or the regression behind it is fixed. ## Plan @@ -13,3 +13,10 @@ It failed once after [#4181](https://github.com/moq-dev/moq/pull/4181): joining at the previous GOP's keyframe) or an off-by-one in how the fixture samples the live edge. Fix whichever it is; don't widen the budget without a reason. + +The interop browser check "late join starts live" +(`test/interop/clients/js/media.ts`, `MAX_LATE_JOIN_LAG_FRAMES`, one GOP +compared with `<=`) fails the same way on `main`: 16 frames behind with a +15-frame GOP on 09-24, 09-25, 09-28, and in +[#4577](https://github.com/moq-dev/moq/pull/4577). It samples `live` just +before the page opens. Treat it as the same flake (decided 2026-10-01). diff --git a/quest/m2/README.md b/quest/m2/README.md index 9aaa4dc6fd..5e97fa80d4 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -99,6 +99,7 @@ waiting on an upstream release waits in [m4](/quest/m4/README.md). - [Per-program SI](/quest/m2/ts-program-si.md) - a selected TS program's broadcast carries only its own service's SDT and EIT - [TS import health](/quest/m2/ts-import-health.md) - `moq import ts` counts the TR 101 290 errors of the feed it receives, PCR and PTS graded on its own values - [TS health stats](/quest/m2/ts-health-stats.md) - the TS counters ride the stats plumbing beside the media counters +- [TS stopped log: audio and video only](/quest/m2/ts-stopped-av-only.md) - sparse data PIDs like SCTE-35 stop logging "stopped delivering" every quiet second - [Teleoperation](/quest/m2/teleop/README.md) - MoQ carries robot video down and control up on one session as a library capability - [Media QA on other engines](/quest/m2/browser-media-qa-engines.md) - the media harness measures a Firefox or WebKit player over the fallback and names what each engine lacks - [Windows.Graphics.Capture](/quest/m2/capture-wgc.md) - one WGC backend for display and window capture with the cursor, replacing Desktop Duplication and GDI diff --git a/quest/m2/ts-stopped-av-only.md b/quest/m2/ts-stopped-av-only.md new file mode 100644 index 0000000000..e5d97c52dc --- /dev/null +++ b/quest/m2/ts-stopped-av-only.md @@ -0,0 +1,34 @@ +# [XS] TS stopped log grades only audio and video + +## Goal + +The TS import and export stats log ("elementary stream stopped delivering +access units") fires only for audio and video PIDs. Sparse data PIDs such as +SCTE-35 and ID3 are still counted but never logged as stopped. + +## Plan + +`ts::Log::sample` (`rs/moq-mux/src/container/ts/stats.rs`), added for SRT +ingest in [#4506](https://github.com/moq-dev/moq/pull/4506) and used for export +since [#4577](https://github.com/moq-dev/moq/pull/4577), logs any PID whose +access-unit count did not move in a 1 s interval. That assumes a continuous +stream; SCTE-35 sends a section now and then, so it logs nearly every quiet +second after each cue. + +Decision (2026-10-01): ✅ grade only audio/video. Rejected: learning each +PID's usual gap (more logic) and leaving the noise. + +`Log::sample` only sees `Stats`, and `StreamStats` carries no stream type; the +`track` suffix can't tell (`.ts` is any verbatim data, `""` is MPEG-1/2 video). +Carry the classification import already resolved into `StreamStats` for active, +retired, and section rows, not the raw PMT `stream_type`: `0x86` is DTS or, +with a CUEI descriptor, SCTE-35, and import routes the latter to sections. +Test a sparse CUEI-marked `0x86` PID beside a stalled video PID. + +Public API: an additive field on the `#[non_exhaustive]` `StreamStats`. Wire: +none. + +## Related + +- [TS stats module](/quest/m1/ts-stats-module.md) - renames these types on dev +- [TS health stats](/quest/m2/ts-health-stats.md) - publishes the same per-PID liveness