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 AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This file is split into nested `AGENTS.md` files based on the language/situation
- Fix any outdated docs and comments inline; don't add a separate PR for it.
- Add the AI marker `(Written by <model>)` to any posts on GitHub, excluding commit messages that contain `Co-Authored-By:` trailers.
- Any AI comments may be challenged, and not confused with human maintainers.
- This repo is public: never mention customers, partners, or prospects (names, volumes, terms) or link to private repos. Justify work on its merits.
- Prompt the user to decide when unsure, but always provide recommendations.

# Guidelines
Expand Down
5 changes: 2 additions & 3 deletions quest/m0/broadcast-epoch/stats-split.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ everything since the epoch began.

## Plan

Decided 2026-10-05 (planned from moq-dev/moq.pro#2202):
Decided 2026-10-05:

- **Why.** Every counter is cumulative per entry, and an entry is pruned right
after the frame carrying its closing readout. A broadcast that starts and
Expand Down Expand Up @@ -64,8 +64,7 @@ Decided 2026-10-05 (planned from moq-dev/moq.pro#2202):
just-ended children, not every child the prefix has ever seen. Decide
while implementing whether a map with hundreds of children needs a cap or
paging.
- **Self counters** (decided 2026-10-07, planned from
moq-dev/moq.pro#2165). A prefix track also carries cumulative counters for
- **Self counters** (decided 2026-10-07). A prefix track also carries cumulative counters for
members at exactly the prefix, not its descendants, so a reader can show a
broadcast that also has nested broadcasts. A reader can't derive them as the
rollup less the current children: a pruned child's tail stays in the
Expand Down
1 change: 0 additions & 1 deletion quest/m0/qmux-credit.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,3 @@ Public API: none. Wire: none.
## Related

- [qmux on the QUIC stream state machine](/quest/m2/quic-qmux.md) - replaces these stream maps later
- [moq.pro: edge-to-core qmux](https://github.com/moq-dev/moq.pro/blob/main/quest/m1/edge-core/qmux-credit.md) - the long-lived cluster links that need this
16 changes: 16 additions & 0 deletions quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ regression, and the audio jitter target line here from m0; moved uring,
capture-chain, and first-FETCH pipelining work to m2; and deleted quests that
were done or not worth their cost.

Promoted from m2 on 2026-10-09 by maintainer priority: mobile capture and
completion, the capacity probe, the viewer up-switch, and native enabled,
which simulcast rung disable requires. Added the same day:
simulcast rung disable, OBS multitrack, MoQ in obs-studio, and portrait
ladders.

## Required

- [WebGPU renderer](/quest/m1/webgpu-renderer.md) - a new `@moq/video` renders frames through WebGPU in their own colour space, with Canvas2D where WebGPU is missing, for watch and the publish preview
Expand Down Expand Up @@ -95,13 +101,19 @@ were done or not worth their cost.
- [Retire the libmoq stub](/quest/m1/libmoq-retire.md) - the published `libmoq` crate stops after its final release points users at `moq-c`
- [VideoToolbox presets](/quest/m1/videotoolbox-presets.md) - VideoToolbox honors Balanced and Quality instead of always reporting LowLatency
- [OBS native codecs](/quest/m1/obs-moq-video/README.md) - replace FFmpeg video and audio decoding with moq-video and moq-audio, deliver GPU frames, and use native audio/video encoders
- [OBS multitrack](/quest/m1/obs-multitrack.md) - the obs-moq output publishes OBS's native multitrack video encoders as simulcast renditions, configured like OBS multitrack and over obs-websocket
- [MoQ in obs-studio](/quest/m1/obs-studio/README.md) - a native MoQ output and service merged into obs-studio, once its maintainers agree; the plugin carries it until then
- [AudioToolbox decode](/quest/m1/audio-decode-audiotoolbox.md) - macOS and iOS decode HE-AAC, multichannel AAC, and what else the framework offers
- [AudioToolbox encode](/quest/m1/audio-encode-audiotoolbox.md) - macOS and iOS encode AAC-LC
- [mp4-atom dOps mapping](/quest/m1/mp4-atom-dops-mapping.md) - a released mp4-atom reads and writes any `dOps` channel mapping family and table
- [CMAF surround Opus](/quest/m1/cmaf-opus-surround.md) - fMP4 import and export carry an Opus channel mapping table
- [A self-hosted NVIDIA runner is registered](/quest/m1/gpu-runner.md) - the maintainer registers the host that runs the NVIDIA tests
- [GPU CI](/quest/m1/gpu-ci.md) - NVIDIA tests run nightly on a self-hosted GPU runner, and `just rs nvidia` runs them locally instead of skipping
- [Rendition preference](/quest/m1/rendition-preference.md) - automatic selection by `<moq-watch>`, `Video::ranked`, and WHEP keeps the highest `preference` that decodes, so a compatibility transcode is only picked when nothing preferred decodes
- [Native enabled](/quest/m1/native-enabled.md) - native players and the ffi/C paths never select a disabled rendition, and move off one disabled mid-playback
- [Simulcast rung disable](/quest/m1/simulcast-rung-disable.md) - JS, Rust/FFI, and OBS publishers stop encoding the top renditions their grant cannot fund, advertise `enabled: false`, and re-enable with hysteresis
- [Discover media headroom](/quest/m1/quic-probe.md) - test useful-media pacing before adding redundant probe traffic
- [Viewer up-switch](/quest/m1/viewer-upswitch.md) - a viewer capped by its small rendition finds headroom through PROBE and moves up
- [Own the QUIC stack](/quest/m1/quic/README.md) - quinn hard-forked in-tree as `moq-quic`, carrying BBR, reliable reset, hierarchical scheduling, peer limits, and endpoint sharding
- [QoS](/quest/m1/qos/README.md) - broadcast health: relay starvation and timeliness histograms
- [Session outcomes](/quest/m1/session-outcomes.md) - the relay's session stats count refusals by reason and ends by kind, per root and tier
Expand Down Expand Up @@ -145,6 +157,9 @@ were done or not worth their cost.
- [qmux no-wait opens](/quest/m1/qmux-no-wait.md) - @moq/qmux rejects an over-limit create when waitUntilAvailable is false, like Chrome
- [E2EE](/quest/m1/e2ee/README.md) - TypeScript and Rust peers interoperate over encrypted broadcasts no relay can decrypt
- [#933](/quest/m1/933-video-rotation-metadata-not-propagated-from-mobile-camera.md) - the catalog rotation follows the live camera's orientation
- [Portrait ladder](/quest/m1/portrait-ladder.md) - portrait video plays end to end through transcode, with rungs sized by the source's short side
- [iOS capture](/quest/m1/mobile-capture-ios.md) - Rust captures the camera and screen on iOS, setting the catalog rotation
- [Android capture](/quest/m1/mobile-capture-android.md) - Rust captures through NDK/JNI on Android, reusing the existing codecs and setting the catalog rotation
- [Time stretch](/quest/m1/watch-audio-time-stretch.md) - js/watch: the audio ring converges by time-stretching instead of skipping or going silent
- [Native audio quality](/quest/m1/audio-quality-native.md) - the browser lane's profiles, budgets, and metric schema run against `moq play` on a dummy device
- [Caption import](/quest/m1/captions-import.md) - fMP4 and MKV subtitle tracks import as text renditions instead of erroring or being dropped
Expand All @@ -170,6 +185,7 @@ were done or not worth their cost.
- [Dart on iOS](/quest/m1/dart-ios.md) - prove the shipped iOS native asset actually loads on a device, which no CI can
- [Dart publish](/quest/m1/dart-publish.md) - a `moq-dart-v*` tag publishes `moq` to pub.dev unattended, as `moq_ffi`'s tags already do
- [Dart codec parity](/quest/m1/dart-codecs.md) - Dart is the one binding that cannot originate media
- [Mobile completion](/quest/m1/mobile-completion.md) - verify the Swift and Kotlin bindings over Rust-owned capture before closing #700
- [`moq --listen` drain and stats](/quest/m1/cli-serve.md) - a listening CLI session, already admitted through the relay's auth, is counted and drained like a relay's
- [#709](/quest/m1/709-automatic-letsencrypt-support.md) - the relay provisions and renews its own ACME certificate through rustls-acme over TLS-ALPN-01, persisted on disk
- [Draft 14-16 updates](/quest/m1/ietf-legacy-updates.md) - Rust and JS apply and answer moq-transport 14-16 request updates without ending or leaking the request
Expand Down
5 changes: 2 additions & 3 deletions quest/m1/auth/webtransport-transport.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ sees the new value.

## Plan

Decided 2026-10-07, for moq.pro's per-transport session stats (a customer
measuring how often browsers fall back to WebSocket, whose native QUIC
workers share the `quic` count today):
Decided 2026-10-07, for per-transport session stats (how often browsers fall
back to WebSocket, while native QUIC clients share the `quic` count today):

- **A variant, not a flag.** Rejected: an additive `webtransport: bool` beside
`transport: "quic"`. The variant states the truth. An auth server that
Expand Down
14 changes: 5 additions & 9 deletions quest/m1/bench-buckets.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ at raw-sample precision.

## Plan

Decided 2026-10-05 in moq.pro's quest audit: percentiles neither window nor
merge, and moq.pro's load harness sums several generators against one relay,
so the bench emits mergeable buckets. Approved as recommended.
Decided 2026-10-05 by the maintainer: percentiles neither window nor merge,
and a load harness sums several generators against one relay, so the bench
emits mergeable buckets.

- `Latency` (`rs/moq-bench/src/stats.rs`) counts 1 ms buckets for the whole
run and diffs them each interval for the `latency_interval_*` percentiles
Expand All @@ -38,12 +38,8 @@ so the bench emits mergeable buckets. Approved as recommended.
taken. Update `rs/moq-bench/README.md`.

Lands on main, then is backported to `release` as an additive cherry-pick
PR, like [#4882](https://github.com/moq-dev/moq/pull/4882), since moq.pro's load
harness tracks `release` (decided 2026-10-05). The backport carries #5021's
PR, like [#4882](https://github.com/moq-dev/moq/pull/4882), since downstream load
harnesses track `release` (decided 2026-10-05). The backport carries #5021's
delta along if `release` does not have it yet.

Public API: none (CLI output only). Wire: none.

## Related

- [moq.pro: benchmark output pin](https://github.com/moq-dev/moq.pro/blob/main/quest/m2/kick/bench-pin.md) - the load harness that sums these across generators
8 changes: 4 additions & 4 deletions quest/m1/cluster-routing/routes.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ Decided 2026-10-01 (see the [line's decisions](/quest/m1/cluster-routing/README.
Why not a hold-down: #4644 retracted at once and re-announced a replacement
after 1 s, which ended a downstream front whose only path ran through the
relay, dropping subscribers for about a second while the relay kept serving;
holding without retracting brought hunting back (moq-dev/moq.pro#2116 has the
measurements, and #4642's 300 ms cursor hold is the production mitigation).
holding without retracting brought hunting back in measurements, and
#4642's 300 ms cursor hold is the production mitigation.
Separating "the path changed" (ROUTE) from "the broadcast ended" (ANNOUNCE)
removes that trade, and the failover tests must show no front loses its
route while a working one exists. Decide whether #4642's hold can then go.

Simulator findings so far, from moq-dev/moq.pro#2152 (open, awaiting the
maintainer's decision on a design revision):
Simulator findings so far (awaiting the maintainer's decision on a design
revision):

- Live origin-end costs 134.5 KiB against path vector's 3668.1/1243.0 KiB,
but still emits 2150 client updates against an 840 once-only minimum and
Expand Down
15 changes: 6 additions & 9 deletions quest/m1/cluster-routing/sim.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

## Goal

Waits on moq.pro's routing simulator. The condition clears when moq.pro's
[Simulate the edge and core layout](https://github.com/moq-dev/moq.pro/blob/main/quest/m1/routing-sim-tiers.md)
reports a ROUTE and ANNOUNCE split candidate (per-node distance vector with
Waits on moq.pro's routing simulator. The condition clears when its edge and
core layout simulation reports a ROUTE and ANNOUNCE split candidate (per-node distance vector with
Babel feasibility, path-less announces following the next hop) beside path
vector, on the tiered live layout, the tiered synthetic sweeps, and a
synthetic drone mesh (lossy links, two uplinks, a partition that heals).
Expand All @@ -13,12 +12,10 @@ Per scenario (publish, end, link flap, relay loss and restart, uplink loss):
messages and bytes by kind, convergence time, stale-path seconds, transient
subscribe loops, and whether a two-uplink mesh ever carries CDN traffic.

moq-dev/moq.pro#2136 rewrote that quest for the split (merged 2026-10-02),
and moq-dev/moq.pro#2152 (draft) measures the tiered route and mesh failures.
Its report says the split needs a design revision before its wire ships, so
the condition is now the maintainer's decision on that revision, not only a
merge. To check: #2152 merges, or the maintainer decides the revision. To
advance: ask the maintainer to review #2152's findings. Delete this quest
The simulator now measures the tiered route and mesh failures, and its
report says the split needs a design revision before its wire ships, so the
condition is the maintainer's decision on that revision. To check and
advance: ask the maintainer to review the simulator's findings. Delete this quest
once [Routes and announces](/quest/m1/cluster-routing/routes.md) is
confirmed or revised by them.

Expand Down
5 changes: 2 additions & 3 deletions quest/m1/data-consumer-timestamps.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ wrappers, moq-ffi, and every binding wrapper.

## Plan

Requested by an external consumer (OneTooMany, Discord), who translates
MAVLink into application telemetry and must keep its timestamps to stay in
sync with video.
An application that translates MAVLink into its own telemetry must keep
each value's timestamp to stay in sync with video.

Every `moq_net::Frame` carries an optional timestamp (`None` when untimed,
since #4822), but the consumers decode only `frame.payload` and drop it: `moq_mux::{json,binary}::Consumer::next` and the
Expand Down
4 changes: 1 addition & 3 deletions quest/m1/dogfood-assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ CSP is out of scope: the dashboard adds no policy.
Decided in planning: the maintainer wants hosted mode dogfooded, not just the
pin bump. No CSP. moq.dev's half moved to
[its own quest tree](https://github.com/moq-dev/moq.dev/blob/main/quest/m0/dogfood-assets.md)
on 2026-10-09. The moq.pro side is part of its
[package adoption](https://github.com/moq-dev/moq.pro/blob/main/quest/m1/ship-dev.md).
pronto/web is skipped: it renders video only and never loads a worklet.
on 2026-10-09. The moq.pro side is part of its package adoption.

Guidance:

Expand Down
5 changes: 2 additions & 3 deletions quest/m1/gst-brew-path.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ the formula installs nothing without an error. The published tap formula
The Nix `moq-gst` package (`moq-gst` in `nix/overlay.nix`) also carries the
encoders and decoders a moq-gst pipeline needs. Its plugin path has core,
base, good, and bad today; add gst-plugins-ugly (`x264enc`) and gst-libav
(`avenc_aac`, `avdec_h264`). moq.pro's
[gst-install-upstream](https://github.com/moq-dev/moq.pro/blob/main/quest/m1/gst-install-upstream.md)
waits on this, so its install can drop its own GStreamer setup.
(`avenc_aac`, `avdec_h264`), so a downstream install can drop its own
GStreamer setup.

## Plan

Expand Down
4 changes: 2 additions & 2 deletions quest/m1/js-data-consumer-timestamps.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ video playhead reaches it. Mirrors

## Plan

Requested by OneTooMany, whose web frontend shows KLV and MAVLink telemetry
beside video and today reads raw frames to recover the timestamps.
A web frontend showing KLV or MAVLink telemetry beside video has to read raw
frames today to recover the timestamps.

Decided (2026-10-01): `next()` and the async iterator yield `@moq/net`'s
`Timed<T>` (`{ value, at? }`), the type the producers take.
Expand Down
4 changes: 1 addition & 3 deletions quest/m1/kt-ffi-pom.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ The `dev.moq:moq-jvm` and `dev.moq:moq-android` POMs on Maven Central depend
on a published `moq-ffi` variant, so a Maven build resolves the wrapper.
Today 0.5.0 and 0.5.1 depend on `moq-ffi-jvm` and `moq-ffi-android` version
`0.0.0-dev`, which was never published, so every Maven consumer fails to
resolve. A PR check refuses a generated POM naming that version. moq.pro's
[Kotlin sample](https://github.com/moq-dev/moq.pro/blob/main/quest/m2/kotlin-sample.md)
is a consumer: it builds against the published wrapper.
resolve. A PR check refuses a generated POM naming that version.

## Plan

Expand Down
9 changes: 4 additions & 5 deletions quest/m1/lite07-finalize.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ then roll lite-07 out without a wip wire changing under it.

## Plan

Decided 2026-10-05 in moq.pro's quest audit: finalizing lite-07 is upstream
work with its own quest. Until now nothing upstream owned it, while moq.pro's
mesh and customer rollouts waited on it and the
Decided 2026-10-05 by the maintainer: finalizing lite-07 is upstream work
with its own quest. Until now nothing upstream owned it, while downstream
rollouts waited on it and the
[mesh condition](/quest/m3/lite07-mesh.md) here waited on moq.pro. This quest
waits on nothing outside the repository; the rollouts and the mesh condition
follow it.
Expand All @@ -28,7 +28,7 @@ The route layer of [Cluster routing](/quest/m1/cluster-routing/README.md)
(ROUTE_START/UPDATE/END, path-less ANNOUNCE, the hop list dropped) lands in
lite-07, decided 2026-10-05. That removes lite-07's `Hop Base`/`Hop Keep`
announce compression along with the hop list, and moq.pro's lite-07 rollout
(under Related) has to plan for a lite-07 without hop lists. Only
has to plan for a lite-07 without hop lists. Only
[Routes and announces](/quest/m1/cluster-routing/routes.md) gates the cut,
not the rest of the cluster-routing line (decided 2026-10-08).

Expand Down Expand Up @@ -83,4 +83,3 @@ is published; older versions are unchanged.
## Related

- [The moq.pro mesh runs lite-07](/quest/m3/lite07-mesh.md) - the deployment condition that follows this
- [moq.pro: lite-07 on cluster dials](https://github.com/moq-dev/moq.pro/blob/main/quest/m2/lite07.md) - the mesh rollout that adopts the finalized version, and the customer rollout after it; moq.pro holds it in m2 until the cut is called
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@ reimplement the native layer).
`moq-tokio` already reaches into Android through JNI for `tls::init_android`,
so the mechanism exists.

Capture sets the catalog `rotation` from the sensor and display orientation,
so a phone held in portrait plays upright; the browser half of that is
[#933](/quest/m1/933-video-rotation-metadata-not-propagated-from-mobile-camera.md).

Promoted from m2 on 2026-10-09 by maintainer priority.

## Related

- [iOS capture](/quest/m2/mobile-capture-ios.md) - the other half of mobile, which
- [#933](/quest/m1/933-video-rotation-metadata-not-propagated-from-mobile-camera.md) - the same catalog rotation for browser capture
- [iOS capture](/quest/m1/mobile-capture-ios.md) - the other half of mobile, which
reuses an existing backend rather than adding one
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ Reuse the `capture::Source` shape the other platforms use rather than growing
an iOS-specific entry point, so device enumeration and selection behave the
same everywhere.

Capture sets the catalog `rotation` from the device orientation, so a phone
held in portrait plays upright; the browser half of that is
[#933](/quest/m1/933-video-rotation-metadata-not-propagated-from-mobile-camera.md).

Promoted from m2 on 2026-10-09 by maintainer priority.

## Related

- [Android capture](/quest/m2/mobile-capture-android.md) - the other half of
- [#933](/quest/m1/933-video-rotation-metadata-not-propagated-from-mobile-camera.md) - the same catalog rotation for browser capture
- [Android capture](/quest/m1/mobile-capture-android.md) - the other half of
mobile, and a much larger one
Loading
Loading