Skip to content

refactor(rs): move every crate onto moq-clock - #6135

Merged
kixelated merged 17 commits into
mainfrom
quest/m1/time/crates
Oct 22, 2026
Merged

kixelated merged 17 commits into
mainfrom
quest/m1/time/crates

Conversation

@kixelated

@kixelated kixelated commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Finishes quest/m1/time/crates.md: every crate's production clock reads and timers move onto moq-clock, and every crate except kio is ratcheted. The quest file is deleted; the public SystemTime to moq_clock::Wall move is split into its own quest, quest/m1/time/wall.md.

Changes

  • Reads and timers. std::time::Instant, tokio::time::{Instant, sleep, sleep_until, timeout, timeout_at, interval, interval_at, Sleep, Interval, MissedTickBehavior}, and SystemTime::now become their moq_clock equivalents in hang (example), moq-audio, moq-video, moq-gst, moq-rtsp, moq-srt, moq-hls, moq-shaper, moq-boy, moq-cli (including the new stats report), moq-tokio, moq-relay, moq-quic, moq-bench, moq-ice, and moq-rtc, including the macOS and Windows capture paths (unverified here: they do not build on Linux).
  • Mixed clocks. The video capture test fixture no longer correlates two clocks, since capture now reads the same clock as the broadcast. Device threads that read std Instant beside async code on tokio time now read moq_clock::now(), which falls back to the host clock off a runtime.
  • moq-clock.
    • Adds timeout_at and interval_at, mirroring tokio's, for the seven timeout_at sites and moq-shaper's delayed first report tick.
    • Adds Instant::into_std and Instant::from_std, native only, mapped through the runtime clock's origin. They are exact on a running clock and keep only durations on paused tokio or the simulator. into_std panics outside std's range; from_std saturates. The crate docs and doc/lib/rs/moq-clock.md no longer say an instant never converts back.
  • Third-party boundaries. str0m (moq-ice, moq-rtc, moq-tokio webrtc), srt-tokio's pacing, winit's WaitUntil, qlog's epoch, and retina's arrival stamps convert with into_std / from_std at the call, so the per-site #[allow]s and moq-srt's host_instant helper are gone. noq's congestion controller trait keeps one #[allow(clippy::disallowed_types)], since the trait's signature is std's.
  • Device threads. std::thread::sleep on threads outside any runtime (audio buffer and driver, bench host, boy main, V4L2, X11) stays under a per-site #[allow]: such a thread has no ambient clock to wait on, and the simulator never runs it.
  • Ratchet. Every crate except kio (moq-clock's own substrate) has a clippy.toml banning direct clock reads and timers, matching moq-archive's. Crates that still expose SystemTime (hang, moq-bench, moq-cli, moq-gst, moq-hls, moq-quic, moq-relay, moq-rtc, moq-tokio) allow that type until it moves to moq_clock::Wall. Test modules, integration tests, and benches carry #[allow], as in moq-dev/moq#5987; their conversion is the m2 sweep.
  • moq-rtsp's tokio dependency is now optional, behind test-support, and moq-ice drops tokio's time feature.

Decision

Settled by the maintainer (option 1): a native-only moq-clock conversion to and from std::time::Instant through the runtime origin, with std::thread::sleep kept under #[allow] on device threads. Recorded in quest/m1/time/README.md.

Public API and wire

  • moq-clock: adds timeout_at, interval_at, Instant::into_std, and Instant::from_std. Additive.
  • No other public signature changes; every rewritten instant is private or crate-visible. No MIGRATE.md entry.
  • Wire: none.

Checks

  • just check on the merge with main at ee4653a507: passes (lint, fmt, docs, JS, bench harness, and 9317 + 516 + 223 Rust tests). An earlier run hit moq-cli export::redundant_importers_switch_through_bufferbloat_on_lite_07 under heavy machine load; it passes alone and on every rerun.
  • cargo nextest run -p moq-clock: the new timeout_at, interval_at, and std conversion tests (exact on a running clock, durations on paused tokio, saturation) pass.

Follow-ups

  • quest/m1/time/wall.md: move public wall times to moq_clock::Wall, then ban SystemTime in the remaining ratchets.
  • moq-audio's decode consumer keeps a hand-rolled test clock override (tests::CLOCK) that the sim or Manual could replace (m2 sweep).

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 6 commits October 20, 2026 17:55
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Production clock reads and timers in hang, moq-audio, moq-video, moq-gst,
moq-rtsp, moq-srt, moq-hls, moq-shaper, moq-boy, moq-cli, moq-tokio,
moq-relay, moq-quic, and moq-bench now go through moq-clock, and each
finished crate gets the per-crate clippy ratchet. moq-clock gains
timeout_at and interval_at, mirroring tokio's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Outcome: left as a draft because one maintainer decision is open. The quest asks for clock support where third-party APIs (str0m, srt-tokio, winit) take std instants. My recommendation is a native-only moq-clock conversion to and from std::time::Instant (option 1 in the body), which would let moq-ice and moq-rtc join the ratchet. Device-thread std::thread::sleep stays under #[allow]. The public SystemTime to moq_clock::Wall migration is listed in the quest as remaining work. just check passed before push.

(Written by Claude Opus 5.5)

kixelated and others added 4 commits October 20, 2026 19:17
Add native-only Instant::into_std and Instant::from_std, mapped through
the runtime clock's origin. Use them for str0m (moq-ice, moq-rtc,
moq-tokio webrtc), srt-tokio, winit, qlog, and retina, replacing the
per-call-site host reads, and ratchet moq-ice and moq-rtc. Record the
decision, finish the crates quest, and split the public SystemTime move
into its own quest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title refactor(rs): move the remaining crates onto moq-clock refactor(rs): move every crate onto moq-clock Oct 21, 2026
@kixelated
kixelated marked this pull request as ready for review October 21, 2026 03:22
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-22T06:15:17.377409Z 9c11c4b New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

# Conflicts:
#	Cargo.lock
#	rs/moq-gst/Cargo.toml
@kixelated

Copy link
Copy Markdown
Collaborator Author

@codex review

(Written by Claude Opus 5.5)

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: ee4653a507

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@kixelated

Copy link
Copy Markdown
Collaborator Author

Merging at ee4653a507a6236876d278cebcd78ee92f483ca5: Codex reviewed this head with no findings, and CI is green apart from CodeQL, which is still running.

  • Decision (maintainer, option 1): moq-clock gains native-only Instant::into_std and Instant::from_std through the runtime origin; str0m, srt-tokio, winit, qlog, and retina convert at their call sites; device threads keep std::thread::sleep under a per-site #[allow].
  • Every crate except kio is on moq-clock with a clippy ratchet, and quest/m1/time/crates.md is done.
  • Public wall times on SystemTime move to moq_clock::Wall in quest/m1/time/wall.md.
  • Public API: additive in moq-clock only. Wire: none.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 21, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 21, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated added this pull request to the merge queue Oct 21, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f8a9d5e369

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +105 to +109
pub(crate) fn into_std(at: Instant) -> Option<std::time::Instant> {
let base = std_base();
match at.since_origin().checked_sub(LEAD) {
Some(after) => base.checked_add(after),
None => base.checked_sub(LEAD - at.since_origin()),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Map std conversions through the active ambient clock

When a Manual clock is installed or code runs under #[moq_clock::test], the ambient instant starts at Instant::ZERO, but this conversion still uses the runtime's std_base and subtracts the 2^32-second LEAD. On ordinary systems, converting any such near-zero instant therefore returns None and Instant::into_std() panics; the inverse also produces values on the runtime scale rather than the active clock's scale. Consequently, migrated third-party boundaries such as QlogConfig::into_stream, the ICE agent, and RTC dispatch cannot be exercised with the repository's controlled clocks. The conversion needs a stable std anchor belonging to the active simulator/manual backend.

AGENTS.md reference: AGENTS.md:L19-L20

Useful? React with 👍 / 👎.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 21, 2026
# Conflicts:
#	quest/m1/time/README.md
#	rs/moq-cli/src/main.rs
#	rs/moq-relay/src/relay.rs
@kixelated

Copy link
Copy Markdown
Collaborator Author

Merged main (2305f58) to clear the conflict, in edb6866.

  • moq-relay drain and moq-cli drain: took main's version, which moved the drain deadline into shutdown::Observer::drained(), so the PR's moq_clock::sleep_until there is gone with it.
  • moq-relay/src/shutdown.rs: main's new GOAWAY deadline wait used tokio::time::sleep_until on a moq_clock::Instant; now moq_clock::sleep_until.
  • moq-gst/src/sink/imp.rs: main's new linger test reads tokio time, so the test module carries the same #[allow(clippy::disallowed_methods, clippy::disallowed_types)] as the other test modules.
  • Quests: dropped the crates.md link from quest/m1/time/README.md and main's new quest/m1/time/js-deadlines.md, since this PR deletes that quest.

just check passes (9394 + 516 + 224 Rust tests, lint, JS); quest check passes.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 21, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: edb6866353

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

//! the [`Stream`](super::Stream) drops, the device is released, and no
//! blocking thread is left pinned.

use moq_clock::Instant;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the active clock across capture callback threads

When capture runs under an installed Manual clock or the simulator, FrameChannel::new records an epoch from that controlled clock, but push is explicitly called from foreign callback threads where Instant::now() cannot discover the runtime-local clock and falls back to the host scale near LEAD. at() consequently assigns the first real camera frame a timestamp roughly 136 years after the controlled epoch, which capture_loop then publishes instead of the simulated acquisition time. Capture the active clock in the channel and read that same clock from callbacks so these device paths remain usable under mocked time.

AGENTS.md reference: AGENTS.md:L20-L20

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining. Foreign-thread pushes only come from real device backends (AVFoundation, ScreenCaptureKit, V4L2, WGC, Media Foundation), and those only run on an unpaused runtime, where the off-runtime fallback counts from the same origin as the runtime clock, so the epoch and every push stay on one timeline. Nothing pairs a controlled clock with a device thread: the simulator never runs device threads, the only Manual::install consumer is moq-ffi's testing feature, which does not build capture, and capture tests feed Synthetic::push_at with instants read in the async context. Carrying a runtime handle into every callback to enter it would add cost for a combination nothing uses; this matches the device-thread decision recorded in quest/m1/time/README.md.

(Written by Claude Opus 5.5)

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 21, 2026
kixelated and others added 2 commits October 21, 2026 16:10
The test raced a direct std::time::Instant::now() against a moq-clock read,
so it could flake under load. Its subject, moq-srt's host_instant helper, is
gone; moq-clock's std_conversion_is_exact_on_a_running_clock checks the same
conversion deterministically.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Merged main (3f45b2f) to clear the conflict, in 3b93e92, plus one test change in 3c91b56.

  • quest/m1/time/crates.md: main added a note about the flaky moq-srt test a_late_payload_keeps_its_past_host_instant; kept the PR's deletion of the quest.
  • That note asked the SRT migration to rewrite the test on controlled time. It raced a direct std::time::Instant::now() against a moq-clock read, and its subject (host_instant) is gone, so 3c91b56 drops it: moq-clock's std_conversion_is_exact_on_a_running_clock covers the same conversion deterministically.
  • No new main code reads tokio or std time directly; main's additions already use moq_clock.
  • Replied to the open Codex finding on moq-video capture threads (declined, see the thread).

just check passes (9413 + 516 + 224 Rust tests, lint, JS, quest). The flake module was skipped locally: its runner VM image needs user namespaces this machine's sandbox refuses. One run hit moq-uring a_raw_socket_sees_an_unreachable_send_fail failing on the shared machine's exhausted RLIMIT_MEMLOCK; it passed on rerun.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 22, 2026
@kixelated

Copy link
Copy Markdown
Collaborator Author

Queued as trivial on head 3c91b56. Codex's last completed review stands: the only changes since are a quest-only conflict fix and one deleted flaky test. The head merges cleanly with current main. Main's new time-API uses since the merge base are in moq-ffi (no clippy.toml here) or in test modules this PR already allows, so the new disallowed lists shouldn't trip.

(Written by Claude Opus 5.5)

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 22, 2026
kixelated and others added 2 commits October 21, 2026 22:41
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The resolve wait it measures now runs on moq_clock::timeout, and the
crate's ratchet bans tokio's Instant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Merged main (bce217e) to clear the conflict, in 53d8014, plus one test change in 9c11c4b.

Both are mechanical applications of this PR's migration to code main added, so the last completed review stands. Checks on the merge: lint, fmt, clippy, docs, quest, markdown, and 9292 + 511 + 220 Rust tests pass. nix flake check could not build the runner VM image in the local sandbox (unshare not permitted), unrelated to this diff.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 22, 2026
Merged via the queue into main with commit 151fa48 Oct 22, 2026
11 checks passed
@kixelated
kixelated deleted the quest/m1/time/crates branch October 22, 2026 09:18
kixelated added a commit that referenced this pull request Oct 22, 2026
ietf/session.rs: main's grant check judges the publisher's serving origin (#6259); keep this branch's serving() view on it, so the check registers no discovery interest. moq-rtc whep.rs: keep the watch-then-request resolve, moved onto moq-clock like the rest of the crate (#6135).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated added a commit that referenced this pull request Oct 22, 2026
Main disallows tokio::time in moq-rtc since #6135.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant