Skip to content

Merge main into dev#2013

Merged
kixelated merged 73 commits into
devfrom
claude/merge-main-into-dev-iykq46
Jul 2, 2026
Merged

Merge main into dev#2013
kixelated merged 73 commits into
devfrom
claude/merge-main-into-dev-iykq46

Conversation

@kixelated

@kixelated kixelated commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Merge main into dev

Merges main (63 commits) into dev (137 commits since the last sync). The branches had diverged heavily because several dev crates (moq-mux, moq-hls, moq-rtc, moq-rtmp, moq-srt) were squash-backported to main and then evolved independently on both sides, producing ~180 conflicted files including whole-crate add/add conflicts.

Resolution policy

  • dev wins on architecture: the moq-lite-05 wire protocol, the reshaped moq-net API (infallible request_broadcast/subscribe, Arc<Info> ownership, two-phase accept, mandatory timestamps, no per-frame compression), and the moq-mux restructure (per-codec splitters, import/ module).
  • main's features and fixes were ported onto dev's shapes. Where the same change landed on both sides in different form (backports/double-lands), dev's form was kept.

Main-side features preserved

Deliberate drops (flagged for review)

  • Dev's --video-width-max/--video-height-max/--video-pixels-max/--video-bitrate-max/--audio-bitrate-max CLI flags: main's moq-mux: API cleanup before the semver bump #1941 deleted the catalog::Target soft-matching API they rode on, so there is no surviving library surface. Can be re-added if targets return.
  • Main's leading-/ SETUP path validation from feat(moq-net): moq-lite-05 SETUP message + PATH parameter #1954: not ported because dev exposes the raw path via Request::path() and stricter validation could break UDS ?path= callers. Say the word if you want it enforced on dev.
  • --internal-tier: gone with the [internal] listener fold (Fold the internal listener into --server-bind (one authenticated accept path) #1974); tier now comes from the auth layer (--auth-mtls-tier / auth API tier). Docs updated.
  • hang::Catalog::compressed_track() (main-only helper): removed; it used the pre-reshape moq_net::Track type and had no callers. COMPRESSED_NAME + default_track_info() cover its use.

CI fixes made along the way

  • moq-net SETUP regression (the big one): the merge initially ported main's behavior of closing the session when the uni SETUP-stream send fails. On dev's protocol that send is best-effort (a failure just means the peer treats us as having no capabilities), and on the qmux/WebSocket transport it can fail benignly. Closing on it turned a tolerable transient into a fatal connection closed: 4, severing every WebSocket/TCP session right after version negotiation. This broke the moq-native broadcast_websocket* and moq-relay internal_tcp_* tests and every rust/python publisher leg of the smoke matrix. Reverted to dev's best-effort behavior; lite/session.rs is now byte-identical to dev.
  • bun.lock regenerated to match the merged package.json set.
  • deny.toml: ignore the fresh quick-xml RUSTSEC-2026-0194/0195 (unreachable fix: plist pins quick-xml 0.39; only parses local macOS config via netdev), drop the dead bincode ignore.
  • moq-cli: the stdin/capture pipeline now runs on the main task (the platform capture stream is not Send, so Publish::run cannot ride the JoinSet under --all-features).
  • moq-mux: doc links repointed from the removed Filter/Target to Stream::select.
  • flake.nix: restored cargo-nextest (main added it with the justfile's nextest switch; the auto-merge dropped it).
  • smoke harness: the Python client now awaits the async subscribe_media (feat(moq-ffi)!: defer dynamic track accept so media tracks declare a timescale #1761 made it a coroutine; fix(smoke): update interop clients to the current dev APIs #1952 fixed only subscribe_catalog); the C client link gets -lstdc++ -lva -lva-drm for the openh264/vaapi objects in libmoq.a; publisher + relay logs are dumped on failure.

Verification

  • cargo check --workspace --all-targets, cargo clippy -D warnings, cargo doc -D warnings, cargo fmt/sort pass locally (excluding moq-video's nvenc/vaapi defaults and moq-gst, which need CUDA/libva/GStreamer system libs absent in the sandbox; moq-video --no-default-features and the capture-feature moq-cli build pass).
  • The WebSocket/TCP nextest cases and the libmoq session test need IPv6, which the sandbox lacks ([::]:0 won't bind), so they were verified by root-causing against CI plus the byte-for-byte revert to dev; CI has IPv6 and exercises them.
  • bun run check passes for all JS packages including the demo; bun test passes 454/454.
  • rust→rust smoke passes locally end to end (relay + ffmpeg + moq import avc3 / moq export fmp4).
  • The nvidia-video-codec-sdk git patch entry is intentionally absent from Cargo.lock, matching dev's state (the fork is unreachable from the sandbox).

Cross-package sync

Docs updated alongside code: doc/bin/cli.md (new moq grammar), doc/bin/relay/config.md (--server-bind fold, tier flags), doc/concept/layer/hang.md, doc/lib/rs/crate/moq-mux.md, rs/CLAUDE.md (crate map: moq-cli/moq-rtc roles), demo/pub/justfile. The swift/kt/go/py wrappers had no conflicting changes; note that main's #1978 (TLS system root control in moq-ffi) shipped without wrapper/doc updates on main, so that gap predates this merge.

(Written by Claude Fable 5)

dependabot Bot and others added 30 commits June 24, 2026 11:59
…#1903)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…pport (#1902)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…#1905)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…nt-tls-* flags consistent (#1901)

Co-authored-by: Claude <noreply@anthropic.com>
…ds (#1908)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…enchmark) (#1912)

Co-authored-by: Claude <noreply@anthropic.com>
…r::request_broadcast (#1913)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#1914)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…xport) (#1915)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Codex <codex@openai.com>
…ks) (#1918)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Luke Curley <luke.curley@discordapp.com>
…1858)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…updates (#1832)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
) (#1925)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…1942)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Luke Curley <kixelated@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Replace the consume-side-only catalog::Filter with one selection type that reads
the same at both ends of the pipeline.

- New moq_mux::select module: Broadcast/Video/Audio fluent builders (default
  selects nothing; opt a role in, narrow by name/codec, empty field = any).
- catalog::Select replaces Filter/FilterVideo/FilterAudio; Stream::filter() ->
  Stream::select(selection). The adapter is immutable, dropping the old reactive
  set-mid-stream machinery.
- fmp4::Import::with_select restricts which roles are published (new() unchanged,
  so existing callers still import everything).
- moq-hls uses it on both ends: per-rendition export selects only its own axis,
  and import publishes master-playlist variants video-only beside a separate
  audio rendition (the track-selection half of #1940).

Breaking moq-mux change, targeting main during the pre-semver-bump window. The
discontinuity-sequence change from #1940 is intentionally left for a separate PR.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
kixelated and others added 16 commits June 30, 2026 22:41
…1968)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…pt path) (#1974)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a devTools group so `gh` is available under `nix develop` for opening
and reviewing PRs. Build-only groups are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1998)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Reconciles main's backported crates and new features with dev's architecture.
Dev's shapes win on wire protocol (moq-lite-05), the moq-net API, and the
moq-mux restructure; main's features are ported on top, notably:

- moq-mux/hang: FLAC, MP3, and Opus-over-TS codec support, select::Broadcast
  rendition selection, fMP4 zero-duration and discontinuity fixes
- moq-cli: unified endpoint grammar (binary renamed to moq), CORS origins,
  per-sink frame-drop latency, HLS import via moq-hls
- moq-rtmp/srt/rtc: library-only crates with client (dial-out) roles, ICE
  timeout, SDP rejected m-line fix, session runner
- moq-native/relay: unified client TLS verification (OS platform verifier),
  client TLS reuse for auth HTTP, internal listener folded into --server-bind,
  HTTPS cert arrays
- moq-net: announcement byte-usage stats ported onto dev's tier labels
- moq-json/js: DEFLATE extracted to moq-flate/@moq/flate, diffing serializer
- js: qmux 0.1.3 (reconnect fix, requireProtocol), watch reload default on

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y

@sourcery-ai sourcery-ai 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.

Sorry, we are unable to review this pull request

The GitHub API does not allow us to fetch diffs exceeding 20000 lines

claude added 9 commits July 2, 2026 14:48
The lockfile committed with the merge was regenerated by an install that
aborted on a postinstall script, so it did not match the merged
package.json set and failed CI's --frozen-lockfile check. Also strip a
stray trailing blank line rustfmt flagged in libmoq's tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y
…ode ignore

The fresh quick-xml advisories have no reachable fix: the sole consumer
chain is plist -> netdev -> netwatch -> iroh and even the latest plist
pins quick-xml 0.39. netdev parses local macOS system configuration, not
attacker-controlled XML. RUSTSEC-2025-0141 no longer matches any crate
(http-cache moved off bincode 1.x), so its ignore is removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y
The platform capture stream is not Send, so Publish::run cannot be
spawned on the JoinSet once the capture feature is enabled. Select it
against the JoinSet on the current task instead, matching the previous
CLI's shape.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y
…isher logs

Three harness fixes surfaced by this PR's smoke run (the first since #1952,
as the workflow only triggers on test/smoke changes or nightly on main):

- The python client never awaited the now-async subscribe_media (#1761 made
  it a coroutine; #1952 fixed subscribe_catalog but missed this one).
- libmoq.a bundles openh264 (C++) and moq-vaapi (libva), so the C client
  link needs -lstdc++ -lva -lva-drm on Linux.
- The rust publisher failed every leg in CI while staying alive, and the
  harness gave no clue why: the rust subscriber's stderr went to /dev/null
  and the publisher log was only dumped if the process died. Keep subscriber
  stderr in the leg log and dump the publisher log when a whole round fails.

rust -> rust passes locally with these changes; the publisher-log dump is
there to diagnose the remaining CI-only failures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y
…:select

Also dump the relay log when the smoke matrix fails: the relay's view is
the only place that records why it closed a session, and the current CI
failure (qmux/WebSocket sessions severed at SETUP with close code 4) is
invisible without it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y
Main added cargo-nextest alongside its justfile switch to nextest (#1947);
the merge kept the justfile but the auto-merge dropped the flake tool.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y
…n on failure

The merge ported main's behavior of tearing down the session when the uni
SETUP stream send fails. On dev's protocol that send is best-effort (a
failure just means the peer treats us as having no capabilities), and on
the qmux/WebSocket transport it can fail benignly. Closing on it turned a
tolerable transient into a fatal 'connection closed: 4', which severed
every WebSocket/TCP session right after version negotiation.

This is the regression behind the failing moq-native broadcast_websocket*
and moq-relay internal_tcp_* nextest cases and the smoke matrix's rust/
python publisher legs. Restores dev's best-effort debug-log behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y
libmoq.a statically bundles moq-video (openh264/vaapi/cuda). Those worker
threads use priority-protected mutexes, and tearing them down at normal
process exit can trip glibc's __pthread_tpp_change_priority assertion and
abort with a core dump, even though the moq data path already delivered a
frame. The client only needs to confirm receipt, so _exit(0) right after,
skipping the dependency's atexit teardown. Fixes the flaky rust -> c leg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y
The merge resolution's PublishDecoder::finish() avc3 arm flushed the
Annex-B split and decoded the trailing access unit but never called
import.finish(), so on stdin EOF the H.264 track was never closed. A
downstream subscriber/exporter would hang waiting on the final group
instead of seeing end-of-broadcast. The other arms (fmp4/ts/flv) all
finalize; origin/main's avc3 TrackStream did split-flush + decode-tail +
import.finish(). Restores the missing finish().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfH4fCnLu9WHGdAjwW8L3Y
@kixelated
kixelated enabled auto-merge (squash) July 2, 2026 20:16
@kixelated
kixelated disabled auto-merge July 2, 2026 20:21
@kixelated
kixelated merged commit f4d7646 into dev Jul 2, 2026
2 checks passed
@kixelated
kixelated deleted the claude/merge-main-into-dev-iykq46 branch July 2, 2026 20:27
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.

5 participants