Skip to content

feat(net)!: subscriptions take a track Delay { min, max } - #7597

Merged
kixelated merged 19 commits into
mainfrom
quest/m1/subscription-delay
Nov 2, 2026
Merged

kixelated merged 19 commits into
mainfrom
quest/m1/subscription-delay

Conversation

@kixelated

@kixelated kixelated commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Claims quest/m1/subscription-delay.md. Subscriptions took a bare max delay while the media consumers took Delay { min, max } (moq-dev/moq#7311), and a subscriber's target latency never reached the wire.

Decisions

  • Unstated minimum: decided 2026-11-02 (maintainer), option 1 of this PR's earlier ## Decisions needed: the shared public Delay has a nullable minimum, Option<Duration> in Rust and an explicit null in JS (and FFI, in the bindings follow-up), with explicit absence flags in C and Go so zero-initialized values stay a stated zero. Media consumers read an unstated minimum as zero locally, and subscription metadata keeps it.
  • Recorded earlier in the quest Plan (2026-10-30): Delay moves to moq-net with no re-export, min rides lite-07 SUBSCRIBE and SUBSCRIBE_UPDATE, a relay forwards the smallest stated min, and older wires decode it as not stated.
  • Choices made here, for review:
    • The wire field is Subscriber Min Age, mirroring Subscriber Max Age, encoded as milliseconds plus one with zero meaning not stated (the FETCH Subscriber Max Age convention).
    • Rust Subscription::with_max_delay(d) becomes with_delay(Delay), with Delay::with_min / with_max builders. group::Fetch::max_delay, @moq/net's FetchGroupOptions.maxDelay, and the exporters' with_max_delay stay: none is a subscription, and a fetch has no minimum.
    • container::Consumer::set_delay now puts the whole delay, min included, on the subscription, and Consumer::new inherits both from it. The native video, audio, and C decoders subscribe with that same delay from the first request, so a publisher never sees a stated zero min before the container's update. @moq/watch puts its playout delay on its media subscriptions as min; its max-delay decoder's subscription and consumer share one delay, the playout and max delays each plus the catalog warmup, as Rust's does.
    • @moq/net refuses the old maxDelay key at runtime, as it already did maxAge.
    • moq-audio / moq-video keep their decode::Delay re-export, now pointing at moq_net::track::Delay.

Scope

The quest is [L] and spans every binding, so this PR lands the Rust and JS half and rewrites the quest to the bindings: FFI MoqSubscription (and MoqDelay.min going nullable), moq-c, and the Python, Swift, Kotlin, Go, Dart, and C++ wrappers, with the Dart/Go/C omitted-max fixes. Until then the bindings keep max_delay, mapped onto delay.max with a stated zero min. It also drops the quest from lite07-finalize's Required, since the wire half lands here.

Impact

  • Rust (breaking): moq_net::track::Delay { min: Option<Duration>, max: Option<Duration> }; track::Subscription::max_delay is delay: Delay. moq_mux::container::Delay is gone; use moq_net::track::Delay, wrapping min in Some. MIGRATE notes in moq-net and moq-mux.
  • JS (breaking): Track.Delay { min?: Milli | null; max?: Milli | null }; Track.Subscription.maxDelay is delay. @moq/hang's Container.Delay is gone; ConsumerProps.delay takes Track.Delay. MIGRATE notes in @moq/net and @moq/hang.
  • Wire: moq-lite-07 (still -wip) SUBSCRIBE and SUBSCRIBE_UPDATE gain Subscriber Min Age after Subscriber Max Age; the draft is updated. Older moq-lite versions and moq-transport are unchanged.
  • Bindings: no public change yet; see Scope.

Validation

  • quest gate nix develop --ignore-environment --keep HOME --keep USER --keep PATH --command just ci origin/main on f593745380 (against origin/main 2738588cfc): passed, every module, 9519/9519 Rust tests.
  • just test interop --all passed on the pre-merge head 9451b41d98 (Rust, js-native node and bun, Python; moq-lite-05 through 07 and moq-transport); not rerun after the merge.
  • New tests: min_delay_roundtrips_only_on_lite07 (Rust codec), relay_forwards_the_smallest_stated_min_delay (a lite-07 relay with lite-07 and lite-06 subscribers), the randomized counted_demand_matches_a_full_fold now draws stated and unstated minimums, the_first_subscription_states_the_min_delay in moq-video and moq-audio (fail with min: Some(0ns) without the fix), and JS covers the codec, the aggregation (only unstated minimums aggregate to an unstated one), rounding, and refusal of the old maxDelay key.
  • moq-tokio backend::quic_client_close_drains_finished_track failed once under host load on the pre-merge head (subscribe failed: Unroutable, before any delay code runs) and then passed 10/10 on the branch and 10/10 on origin/main.

Iteration (2026-11-02)

  • Merged origin/main (conflicts in js/watch/src/video/decoder.ts, quest/m2/intra-refresh/dual-decoder.md, rs/moq-net/MIGRATE.md), and moved main's new Subscription::with_max_delay / maxDelay callers onto delay.
  • Pullfrog: removed the dead minDelay prop from the lite JS SubscribeOk (thread), and rewrote the stale "min never reaches the subscription" docs in moq-c, moq-ffi, the Kotlin/Swift/Go/Dart wrappers, and the mux test, which now asserts delay.min.

Second round, after the merge queue dropped fa98b72fd7 with merge_conflict:

  • Merged origin/main twice (moq-dev/moq#7489, routes with an instance and per-instance epoch; then moq-dev/moq#7609, JS ordered reads wait for owed groups). Conflicts in js/e2ee/src/transport.test.ts, js/net/src/lite/subscriber.ts, rs/moq-net/tests/integration/route_change.rs, js/net/MIGRATE.md, and js/net/src/track.ts keep main's structure (the route-change test's follow flow, Epoch.of, the instance import, fix(net): wait for subscription-owed groups in JS ordered reads #7609's MIGRATE entry and "null reaches back" wording) with this PR's delay: { max } / with_delay names. fix(net): wait for subscription-owed groups in JS ordered reads #7609's new ordered-read tests moved from maxDelay to delay: { max }.
  • Codex review finding, fixed in 6a8380f916: the CLI's video subscription (rs/moq-cli/src/play/media.rs) stated a zero min while it waited for the live edge; it now subscribes with the container's whole Delay, as moq-video's reader does.
  • Pullfrog's latest review (on fa98b72fd7) had no findings; no unresolved review threads.

Third round, after the merge queue dropped 296c9b9690 with merge_conflict:

  • Merged origin/main 2738588cfc in 1fdeb62565. Conflicts in rs/moq-net/src/model/subscription.rs, rs/moq-net/src/model/track.rs, rs/moq-net/src/model/track/demand.rs, rs/moq-net/src/ietf/publisher.rs, rs/moq-net/src/lite/publisher.rs, rs/moq-net/MIGRATE.md, and rs/moq-mux/MIGRATE.md keep main's live-feed tracking (Subscription::feed, aggregated as any, set by the ietf publisher's serving subscription), the lite publisher's accepted-update cursor (self.named moves only once update succeeds), main's imports (Layered, Runs, Seen), and main's MIGRATE entries (moq-dev/moq#7624, the fMP4 terminal-error note), alongside this PR's Delay. The aggregate's scalars are (priority, Delay, order, feed).
  • Moved main's new Subscription::with_max_delay callers onto with_delay(Delay::default().with_max(..)): rs/moq-net/benches/ranges.rs, rs/moq-net/src/lite/subscriber.rs and rs/moq-net/src/model/track/miss.rs tests, rs/moq-net/tests/integration/{fetch_only,route_health}.rs, and rs/moq-tokio/tests/integration/receive_credit.rs; formatted the bench in f593745380. quest/m2/audio-flush-group.md and its quest/m2/README.md link now say delay.max.
  • No new automated review findings since the last round; no unresolved review threads. The land fixer's tentative resolution couldn't build without ALSA; this one ran in the Nix dev shell.

Review

  • Reviewer: Codex gpt-6.1-sol, medium effort (quest review), session 01a19e7e, round 1 (a new session: the merged base changed the review instructions since session 01a19de7).
  • Head f593745380e0bb24682ae613e4ce971df354cd5c against origin/main 2738588cfc: no findings.
  • Session 01a19de7: round 2 on 296c9b9690, no findings; round 1 on 5c92ae8f4a, one finding (the CLI's first video subscription stated a zero min), fixed in 6a8380f916.
  • Earlier, session 01a19d7c: round 2 on 3c71c501ec, no findings; round 1 on 5283982f2c, one finding (the native decoders' first subscription stated a zero min), fixed in 473c05499c. Before that, on 9451b41d98: Codex gpt-6-astra, medium, no findings.

Follow-ups

  • The rewritten quest/m1/subscription-delay.md: the binding half (FFI, moq-c, Python, Swift, Kotlin, Go, Dart, C++).
  • moq-tokio backend::quic_client_close_drains_finished_track can fail with Unroutable under heavy load; worth a flake quest if it recurs.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 2 commits November 1, 2026 18:04
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
@kixelated kixelated changed the title Subscriptions take a Delay { min, max } quest: settle subscription minimum delay representation Nov 2, 2026
kixelated and others added 6 commits November 1, 2026 20:58
moq-net's track::Subscription and @moq/net's Track.Subscription carry a
Delay with a nullable min in place of a bare max delay, and moq-lite-07
SUBSCRIBE and SUBSCRIBE_UPDATE carry it as Subscriber Min Age. Delay
moves out of moq-mux and @moq/hang.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l mutation

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 kixelated changed the title quest: settle subscription minimum delay representation feat(net)!: subscriptions take a track Delay { min, max } Nov 2, 2026
@kixelated
kixelated marked this pull request as ready for review November 2, 2026 07:51

@kixelated kixelated left a comment

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.

Automated review by review (OpenAI)

Reviewed commit: 9451b41d984d75d44868dcf1b8cee8e1fd65938c.

No actionable bugs found in the reviewed changes. The direction is sound: sharing track::Delay removes the competing media/network shapes, while preserving the distinction between an unstated minimum and stated zero. The smallest-stated-min aggregation and version-gated lite-07 encoding keep older peers from falsely lowering the upstream target; reusing the existing demand aggregation is preferable to a parallel latency-signaling mechanism.

Checked the Rust/JS subscription defaults, aggregation, wire encode/decode and update paths, media-consumer propagation, binding adapters, and focused regression tests. The remaining binding API work is explicitly deferred; this review does not certify that follow-up. Static review only: I did not run tests, builds, browser playback, or interop, and have not independently verified the validation reported in the PR.

(Written by OpenAI)

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No critical issues — minor suggestions inline.

Reviewed changes

Subscriptions take a track::Delay { min, max }, and the subscriber's target latency (min) now reaches the moq-lite-07 wire. This is the Rust and JS half of quest/m1/subscription-delay; I read the full 207-file diff against main (a546cac).

  • Wire (moq-lite-07, -wip): Subscriber Min Age added to SUBSCRIBE and SUBSCRIBE_UPDATE between Subscriber Max Age and Range Count, encoded as milliseconds + 1 with 0 = not stated. The draft and its changelog are updated; older wires and moq-transport are unchanged.
  • Rust model (breaking): moq_net::track::Delay { min: Option<Duration>, max: Option<Duration> }; Subscription.max_delay becomes delay; moq_mux::container::Delay is gone, with MIGRATE notes in moq-net and moq-mux.
  • JS model (breaking): Track.Delay { min?, max? }; Track.Subscription.maxDelay becomes delay; @moq/hang's Container.Delay is gone, with MIGRATE notes in @moq/net and @moq/hang.
  • Aggregation: a relay forwards the smallest stated min (unstated when none states one); delay.max aggregation is unchanged.
  • Consumers: container::Consumer::set_delay/new now carry the whole delay, min included, onto the subscription; @moq/watch and the audio/video decoders put their playout delay on media subscriptions as min. The lite publisher stores but never reads min to move a start.

The wire codec is byte-identical between Rust and JS, pre-lite-07 layouts are unchanged, and the aggregate rule is correct on join/update/leave in both languages.

ℹ️ Stale "min never reaches the subscription" comments and a test name

container::Consumer::set_delay now writes the whole delay, min included, onto the subscription, and the media consumers feed their playout delay through it. Three comments and one test name still assert the opposite, so they now describe behavior this PR removed:

  • rs/moq-mux/src/container/consumer.rs:3705 (doc) and :3707 (test the_min_delay_never_reaches_the_subscription). reach_consumer calls .with_delay(Delay { min: Some(min), .. }), so set_delay does update subscription.delay.min; the test passes only because it never checks .min.
  • rs/moq-c/src/api.rs:718-721 — moq_delay.min_us "stays on the consumer and never reaches the subscription".
  • rs/moq-ffi/src/media.rs:28 — the same sentence, left behind when line 24's type reference was updated.
Technical details
# Stale "min never reaches the subscription" claims

## Affected sites
- `rs/moq-mux/src/container/consumer.rs:3705` — doc: "The min delay stays on the consumer: the subscription carries the max delay plus the warmup."
- `rs/moq-mux/src/container/consumer.rs:3707` — test name `the_min_delay_never_reaches_the_subscription`.
- `rs/moq-c/src/api.rs:718-721` — `moq_delay.min_us` "stays on the consumer and never reaches the subscription".
- `rs/moq-ffi/src/media.rs:28` — same sentence for `MoqDelay.min`.

## Required outcome
- Every claim that the playout minimum does not reach the subscription is updated to match the new behavior, or removed where it is no longer meaningful. The mux test should ideally assert the minimum does reach `subscription.delay.min` (or be renamed) so it stops passing for the wrong reason.

## Why it is now false
- `container::Consumer::set_delay` builds `delay.with_max(delay.max + warmup)` (min preserved) and calls `track.update(track.subscription().with_delay(delay))`, so `subscription.delay.min` follows the requested `min` (`rs/moq-mux/src/container/consumer.rs:1139-1142`).
- `moq-audio`/`moq-video` decode consumers call `container::Consumer::new(...).with_delay(options.delay)` (`rs/moq-audio/src/decode/consumer.rs:244`, `rs/moq-video/src/decode/consumer.rs:357`), so the FFI/C `min` reaches the subscription too.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Comment thread js/net/src/lite/subscribe.ts Resolved
kixelated and others added 5 commits November 2, 2026 09:44
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s the subscription' docs

SUBSCRIBE_OK carries no min age on any draft, so the lite JS SubscribeOk's
minDelay prop was accepted and silently dropped. The media consumers now put
the whole delay, min included, on the subscription, so the FFI, C, wrapper,
and mux docs that said otherwise are rewritten, and the mux test asserts min.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The native video, audio, and C consumers subscribed with a default Delay
carrying only the max, so the first request stated a zero min until the
container's update corrected it, dragging a relay's aggregate min to zero
meanwhile. Subscribe with the delay the container keeps instead.

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

Re the pullfrog review's stale "min never reaches the subscription" note: agreed, fixed in e190b0d. The moq-c and moq-ffi docs and the Kotlin, Swift, Go, and Dart wrapper docs now say the subscription carries it, and the mux test is renamed to the_subscription_carries_the_min_delay_and_the_warmed_max_delay and asserts delay.min.

The local Codex review then found that the native decoders' first SUBSCRIBE still stated a zero min until the container's update. Fixed in 473c054 for moq-video, moq-audio, and moq-c, with regression tests that check the first aggregate.

(Written by Claude Opus 5.5)

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

@kixelated kixelated left a comment

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.

Automated review by review (OpenAI)

Reviewed commit: 3c71c501ec23f312d3314c921debe73afbba6d47.

No new actionable bugs found in the update since my previous review, accounting for the merged base changes. The native audio/video/C paths now carry the whole delay on the first subscription instead of briefly advertising a stated-zero minimum; the audio/video first-request tests exercise the live-edge wait before a container could correct it. Sharing the JS dual-decoder delay between subscription and consumer also keeps their warmup budgets aligned.

The direction remains sound: initialize the existing Delay correctly rather than add another correction path. The stale propagation comments/test noted in Pullfrog's review are fixed, with a minimum assertion added; the unused SubscribeOk minimum is removed. No new parallel API or wire mechanism is needed for these fixes.

Static review only. I did not run tests, builds, playback, or interop, and did not independently verify the PR's reported validation.

(Written by OpenAI)

@kixelated
kixelated added this pull request to the merge queue Nov 2, 2026

@kixelated kixelated left a comment

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.

Automated review by review (OpenAI)

Reviewed commit: 296c9b9690098373f2a08f2d15b662e7a33c350b.

No new actionable bugs found since the previous review, accounting for the main-branch merges. rs/moq-cli/src/play/media.rs:282–300 now gives the first video subscription the same full Delay used by its container, including the warmup decoder's minimum, before waiting for the live edge. This closes the analogous CLI initialization gap without a new update mechanism; reusing that already-computed Delay is the simpler, appropriate fix. The merged JS ordered-read call sites and migration notes retain their max-delay semantics under delay.max.

Earlier fixed findings remain fixed. Static review only: I did not run tests, builds, playback, or interop; this delta adds no dedicated CLI first-subscription test.

(Written by OpenAI)

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes

The commits since the prior pullfrog review (fa98b72) are the CLI first-subscription fix and two merges of origin/main that brought in routes-with-an-instance (#7489) and the JS ordered-read change (#7609). No new issues.

  • CLI states the min delay on its first subscription: rs/moq-cli/src/play/media.rs now subscribes with the container's whole Delay instead of Delay::default().with_max(...), so the video subscription a cold join makes never advertises a stated-zero minimum before the container's update. The primary decoder passes { min: playout, max }; the intra-refresh decoder passes both plus warmup, matching moq_video::decode::Consumer.
  • origin/main merges: The conflict resolutions keep main's instance/epoch routing and ordered-read logic under this PR's delay: { max } spelling, and the JS SubscribeOk still carries no dead minDelay. The wire codec, aggregation rule, and pre-lite-07 layouts are unchanged.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Nov 2, 2026
@moq-bot

moq-bot Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

quest land watch: the merge queue removed this pull request at 296c9b9 because it conflicts with main (merge_conflict).

The land fixer works on it in the background, and the watcher re-enqueues it at the back of the queue once it is fixed or judged flaky, or hands it back here with what it needs.

(written by quest land watch)

@moq-bot

moq-bot Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

codex / Codex land fixer note:

The failure log records conflicts in this PR's overlapping changes:

7: CONFLICT (content): Merge conflict in rs/moq-mux/MIGRATE.md
13: CONFLICT (content): Merge conflict in rs/moq-net/src/ietf/publisher.rs
16: CONFLICT (content): Merge conflict in rs/moq-net/src/lite/publisher.rs
18: CONFLICT (content): Merge conflict in rs/moq-net/src/model/subscription.rs
20: CONFLICT (content): Merge conflict in rs/moq-net/src/model/track.rs
22: CONFLICT (content): Merge conflict in rs/moq-net/src/model/track/demand.rs
26: Automatic merge failed; fix conflicts and then commit the result.

A tentative mechanical resolution retained the PR's Delay API alongside base's feed field and aggregation, accepted-update cursor handling, added imports, and fMP4 migration notes. cargo fmt --all -- --check and git diff --cached --check passed. The build command cargo test --workspace --no-fail-fast exited 101: "No package 'alsa' found" and "The system library alsa required by crate alsa-sys was not found." This prevents the required validation.

bun install --frozen-lockfile --ignore-scripts and builds for net, hang, json, e2ee, sign, publish and watch passed. The corresponding bun test --only-failures js/net js/hang js/json js/e2ee js/sign js/publish js/watch run was stopped after the Rust validation blocker; it is not a passing test result. The tentative merge was aborted and the PR branch remains at its pinned head. Please resolve and validate in an environment with the required native libraries.

(written by codex / Codex)

@moq-bot

moq-bot Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

codex / Codex land fixer: &#35;7597 conflicts with base in six files; validation of the mechanical resolution is blocked: &#96;cargo test --workspace --no-fail-fast&#96; exits 101 with "No package 'alsa' found".. Recommendation: Merge base preserving the Delay migration together with base live-feed tracking, accepted-update handling, imports and migration notes; rerun builds and tests in an environment with the required nativ

Auto-merging rs/moq-mux/MIGRATE.md
CONFLICT (content): Merge conflict in rs/moq-mux/MIGRATE.md
Auto-merging rs/moq-mux/src/container/fmp4/import.rs
Auto-merging rs/moq-mux/src/container/fmp4/import_test.rs
Auto-merging rs/moq-mux/src/container/mkv/import_test.rs
Auto-merging rs/moq-net/src/fuzz.rs
Auto-merging rs/moq-net/src/ietf/publisher.rs
CONFLICT (content): Merge conflict in rs/moq-net/src/ietf/publisher.rs
Auto-merging rs/moq-net/src/ietf/subscriber.rs
Auto-merging rs/moq-net/src/lite/publisher.rs
CONFLICT (content): Merge conflict in rs/moq-net/src/lite/publisher.rs
Auto-merging rs/moq-net/src/model/subscription.rs
CONFLICT (content): Merge conflict in rs/moq-net/src/model/subscription.rs
Auto-merging rs/moq-net/src/model/track.rs
CONFLICT (content): Merge conflict in rs/moq-net/src/model/track.rs
Auto-merging rs/moq-net/src/model/track/demand.rs
CONFLICT (content): Merge conflict in rs/moq-net/src/model/track/demand.rs
Auto-merging rs/moq-net/src/model/track/miss.rs
Auto-merging rs/moq-relay/tests/integration/goaway_cluster.rs
Auto-merging rs/moq-relay/tests/integration/upstream_links.rs
Automatic merge failed; fix conflicts and then commit the result.

(written by codex / Codex)

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes

The commits since the prior pullfrog review (296c9b9) are a merge of origin/main 2738588cfc and a bench-format commit. The merge is a faithful combination of main's subscription live-feed work with this PR's Delay model; no new issues.

  • Merged main's subscription live-feed: Subscription now carries both delay: Delay and main's feed: bool; the demand aggregate's scalars are (priority, Delay, order, feed), with feed aggregated as any and min_delay still counting only stated minimums. The ietf publisher's serving_subscription keeps delay: { min: None, max: None } (moq-transport has no minimum) alongside feed: true.
  • Kept the lite publisher's accepted-update cursor: TrackRun::update builds Subscription { priority, delay: { min: upd.min_delay, max: serving_max_delay(..) }, order, ..groups } and advances self.named only once track.update succeeds, so a refused update cannot move the cursor.
  • Migrated main's new call sites and reformatted: main's added with_max_delay callers in the benches and integration tests moved to with_delay(Delay::default().with_max(..)) (a stated-zero minimum, matching the model default), and the ranges bench was reformatted with no semantic change.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

@kixelated
kixelated added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit 5ab8786 Nov 2, 2026
9 of 10 checks passed
@kixelated
kixelated deleted the quest/m1/subscription-delay branch November 2, 2026 23:52
kixelated added a commit that referenced this pull request Nov 3, 2026
…nto main's cursors

Decided 2026-11-03 (maintainer): re-port in place. Main rewrote the JS
cursor paths this PR changed (#7486 clean-close completion, #7597
`Delay { min, max }`, #7609 owed-hole waits, #7542 Rust window walks),
so the ranges, window, and lite-07 serving go on top of main's versions.

- Bounded reads end, as Rust's do since #7545 and #7625, replacing the
  2026-10-31 decision to park: a plain reader judges its window as Rust's
  `Cursor::is_exhausted` does, and a reader following route copies judges
  it on the serving copy as Rust's `Reader::exhausted` does. Wire
  publishers and route copies park through `hooks.parked`.
- Main's `delay: { min, max }` replaces this PR's `maxDelay`, with
  `NO_MAX_DELAY`/`maxDelayOf` as the no-limit value.
- The arrival grace is no longer capped at CACHE_EXPIRY: main bounds it
  by the publisher's max age instead, and an unlimited ordered reader
  waits for its hole (#7609, #7169).
- Owed holes count only inside the reader's ranges.
- lite-07: a SUBSCRIBE goes out alongside its TRACK, as on main, unless a
  time anchor needs the track's timescale, as the Rust `pipeline` does.
  The covered FIN without SUBSCRIBE_END stays lite-07 only, now that
  `waitsForSubscriberFin` covers lite-05+.
- Rust: the waiting time start is ported onto main's window walks as a
  placeholder span, as a lookup is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated added a commit that referenced this pull request Nov 3, 2026
…survey/hang-buffered

Resolve the buffered bench onto main's micro harness (bandwidth, replay,
resume-history), keep both the backlog-start tests and the span test, move
the bench and test subscriptions to `delay: { max }` (#7597), and drop the
hang-buffered item from audit-perf's renumbered list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated added a commit that referenced this pull request Nov 3, 2026
…benches in any package

#7597 moved the delay type to `Track.Delay`. The nightly coverage test read
every browser smoke bench from `js/net/bench`, but `buffered` lives in
`js/hang/bench`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated added a commit that referenced this pull request Nov 3, 2026
main replaced Subscription::with_max_delay with a Delay { min, max } in #7597.

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