Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ above them, since the epoch anchor requires it.
- [Live largest location](/quest/m1/largest.md) - `largest()` replaces `latest()` in Rust and JS as a live stream of the track's largest location, known before the first group from the publisher's report
- [Untimed lite-07](/quest/m1/lite-untimed.md) - lite-07 carries an untimed track in both languages; lite-05/06 write send time
- [Live TS clock validation](/quest/m1/ts-live-clock.md) - resolve the local PCR-rate failure with reproducible timing evidence and CI controls
- [Slow source fails](/quest/m1/slow-source.md) - an export whose source runs further off real time than the output may follow fails promptly naming the rate, instead of dropping frames for hours
- [Same-instance TS resume](/quest/m1/ts-same-instance-resume.md) - prove valid continuation and fix the unexpected final exporter failure without weakening identity
- [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
- [Plan: a public model](/quest/m1/model-public-surface.md) - every crate-private model item is made public or unnecessary, so a custom publisher or subscriber builds from the public model alone
Expand Down
48 changes: 48 additions & 0 deletions quest/m1/slow-source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# [S] A source the output cannot follow fails the export promptly

## Goal

An export whose source arrives further off real time than the output's
clock may follow ends with an error naming the measured rate, once it has
used half its delay. It no longer drops nearly every frame for hours with
only per-frame "missed its deadline" warnings. A short stall, such as a
WebSocket-to-QUIC upgrade, still drops late frames and recovers.

## Plan

Found on #5435: before #5292, `moq import` fed a 20 s TS clip about 22%
slow on CI's debug build. The TS export measured -222,000 ppm, dropped
1,273 frames as late, and exited clean with 3.2 s captured.

`jitter::Buffer` (`rs/moq-mux/src/jitter.rs`) already bails when the source
is out of tolerance, but only once the steered drift sits at `MAX_DRIFT`.
At `MAX_SLEW` (0.075 Hz/s of 27 MHz) the steered clock needs about 3 hours to
reach 30 ppm, so a grossly slow source never trips it. The rate itself is
known within a few `STEER` steps.

Decided with the maintainer on 2026-10-13:

- Fail loud, not just warn: a source the output can never follow is refused.
- The check lives in the shared jitter buffer, so TS, FLV, and MKV export
fail the same way. Audio decode is out of scope: `moq-audio` sizes its
delay with its own estimator and doesn't steer a clock.
- The rule is the existing one minus "the steered clock is at its limit":
the measured rate is past `MAX_DRIFT` and half the delay is gone. No new
constant. Rejected: a run of a delay's worth of consecutive drops, a new
heuristic beside the rate the buffer already measures.
- Prove with mocked time that a stall shorter than half `RATE_WINDOW` (the
envelope's own bound) doesn't trip it, including an early stall when only
a few floors exist. If the envelope can't tell the two apart that early,
fix the measurement rather than adding a minimum span.
- Regressions: a source 22% slow fails within a few seconds of decode time
with the rate in the error; one 400 ppm off (the existing counted case)
fails once half the delay is gone; sources within 30 ppm never fail.
- Update any doc or comment that says late frames only drop, inline.

Public API: none; an export that silently degraded now returns an error.
Wire: none.

## Related

- [Live TS clock validation](/quest/m1/ts-live-clock.md) - a local run measured -1382 ppm and exited clean; with this rule it fails loudly, which is evidence for that quest, not a blocker
- [#5435](https://github.com/moq-dev/moq/pull/5435) - the duration-fidelity investigation that found this
Loading