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
2 changes: 1 addition & 1 deletion dart/moq_ffi/lib/src/moq.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18795,7 +18795,7 @@ void _checkApiChecksums() {
throw UniffiInternalError.panicked("UniFFI API checksum mismatch");
}
if (uniffi_moq_ffi_checksum_method_moqmediatrackstreamproducer_finish() !=
57446) {
6627) {
throw UniffiInternalError.panicked("UniFFI API checksum mismatch");
}
if (uniffi_moq_ffi_checksum_method_moqmediatrackstreamproducer_write() !=
Expand Down
29 changes: 29 additions & 0 deletions js/net/src/zod.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { expect, test } from "bun:test";
import * as z from "@zod/mini";
import { Producer } from "./group.ts";
import { textFrame } from "./mock.ts";
import * as Zod from "./zod.ts";

test("read validates each frame and ends only at the end of the group", async () => {
const producer = new Producer(0);
const consumer = producer.consume();
// Falsy values are frames like any other, not the end of the stream.
for (const json of ["0", "false", "null", '"ok"']) producer.writeFrame(textFrame(json));
producer.close();

const schema = z.union([z.number(), z.boolean(), z.null(), z.string()]);
expect(await Zod.read(consumer, schema)).toBe(0);
expect(await Zod.read(consumer, schema)).toBe(false);
expect(await Zod.read(consumer, schema)).toBe(null);
expect(await Zod.read(consumer, schema)).toBe("ok");
expect(await Zod.read(consumer, schema)).toBeUndefined();
});

test("read rejects a frame the schema refuses", async () => {
const producer = new Producer(0);
const consumer = producer.consume();
producer.writeFrame(textFrame('{"count":"three"}'));
producer.close();

await expect(Zod.read(consumer, z.object({ count: z.number() }))).rejects.toThrow();
});
1 change: 0 additions & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ lands before the cut.

- [Dead code and API surface audit](/quest/m1/audit-dead-code.md) - repeat the removal audit before the next major release
- [Dependency and alternatives audit](/quest/m1/audit-deps.md) - dependencies are current, deduplicated, needed, and the best maintained option
- [Test coverage audit](/quest/m1/audit-test-coverage.md) - repeat the coverage audit against the m0 baselines before the next major release
- [Test cost audit](/quest/m1/audit-test-cost.md) - the slowest, flakiest, and least valuable tests are fixed, deleted, or planned
- [Interop report](/quest/m1/interop-report.md) - nightly Interop results publish as a color-coded matrix on the Pages site instead of only in logs
- [CI workflow audit](/quest/m1/audit-ci.md) - every workflow and job gives a signal someone sees, at a cost that signal justifies, or is fixed, moved, or deleted
Expand Down
117 changes: 0 additions & 117 deletions quest/m1/audit-test-coverage.md

This file was deleted.

3 changes: 3 additions & 0 deletions quest/m2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ ranked just below deterministic TS legs, which it requires.
- [AudioToolbox encode](/quest/m2/audio-encode-audiotoolbox.md) - macOS and iOS encode AAC-LC
- [CMAF surround Opus](/quest/m2/cmaf-opus-surround.md) - a released mp4-atom carries the `dOps` channel mapping table, and fMP4 import and export carry it through the OpusHead
- [GPU CI](/quest/m2/gpu-ci.md) - NVIDIA tests run nightly on real hardware, and `just rs nvidia` runs them locally instead of skipping
- [VA-API renderer tests](/quest/m2/vaapi-render-tests.md) - the ignored VA-API renderer import tests run in `just rs gpu` on AMD and Intel and fail instead of skipping
- [Vendor-free CARLA bridge](/quest/m2/carla-bridge.md) - the CARLA demo's GPU bridge lets moq-video pick the encoder, and its stand-in test runs on AMD as well as NVIDIA
- [V4L2 virtual camera](/quest/m2/v4l2-virtual-camera.md) - V4L2 capture runs nightly against the `vivid` virtual driver instead of only on a developer's camera
- [Probe](/quest/m2/probe/README.md) - a session probes up to the bitrate it wants to send or receive, so a stopped simulcast rendition resumes and a viewer up-switches
Expand All @@ -75,6 +76,7 @@ ranked just below deterministic TS legs, which it requires.
- [Android capture](/quest/m2/mobile-capture-android.md) - Rust captures through NDK/JNI on Android, reusing the existing codecs and setting the catalog rotation
- [Time stretch](/quest/m2/watch-audio-time-stretch.md) - js/watch: the audio ring converges by time-stretching instead of skipping or going silent
- [Audio join budget](/quest/m2/audio-join-budget.md) - `moq-audio` joining at the latest group loses no group a publisher bursts before its budget widens
- [PulseAudio capture periods](/quest/m2/pulseaudio-capture-period.md) - capture on cpal's PulseAudio host arrives in short periods, not the server's 2 s default fragment, proven on the null sink's monitor
- [Bindings size profile](/quest/m2/ffi-size-profile.md) - a benchmark decides whether the moq-ffi builds ship at opt-level "s", which halves the dylib
- [The catalog publish path compiles once](/quest/m2/catalog-publish-once.md) - the catalog producer and its JSON diff codegen in `moq-mux` instead of once per importer crate, about 1 MiB of the CLI
- [Zero-copy byte returns](/quest/m2/ffi-bytes-return.md) - returned payloads reach the host without a copy, if the payload numbers justify it
Expand Down Expand Up @@ -176,3 +178,4 @@ ranked just below deterministic TS legs, which it requires.
- [Relay metrics through prometheus-client](/quest/m2/relay-prometheus-client.md) - `/metrics` renders through the maintained client with the same series
- [Dead routes on IETF name their cause](/quest/m2/js-ietf-dead-route-error.md) - a JS subscription on a dead moq-transport session ends with the session error, not `unauthorized`
- [Error cleanups](/quest/m2/error-cleanups.md) - delete the unused `Error::SessionClosed`; raw transport failures already map to `Unroutable`
- [Test coverage audit](/quest/m2/audit-test-coverage.md) - repeat the coverage audit against the m1 baselines after the next release ships
143 changes: 143 additions & 0 deletions quest/m2/audit-test-coverage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# [M] Test coverage audit

## Goal

Behavior that matters but no test exercises is covered or planned, and every
test runs in CI.

## Plan

Recurs once per major release (decided 2026-10-19). The PR that finishes
this run also adds the next one with the same file name at the end of the next
milestone's `Required` (m0 to m1, m1 to m2). The successor keeps the Goal
and this paragraph; the rest of its Plan is rewritten with what this run
learned: baselines, results, and what to check first. A successor placed in m2
also lists the [release cut](/quest/m2/release/cut.md) under `Required`, so it
waits for the release in flight to ship. Only `/quest-delete` ends the
recurrence. Fixes land in the run's PR, one commit each, rather than as follow-ups.
Only a change that needs a maintainer decision (public API, scope) or is
independently landable and too large to review alongside the rest becomes a
follow-up through `/quest-plan`.

### Tools

Nightly keeps both reports as artifacts: `just rs coverage` (cargo-llvm-cov
over nextest, the native workspace at default features, both fuzz packages
and the native moq-wasm stub excluded) and `just js coverage` (Bun's own
coverage, one process per package, line hits unioned across processes).
Start from those artifacts (`gh run download <nightly run> -n rust-coverage`
and `-n js-coverage`) rather than re-running the instrumented workspace,
which is expensive on a shared machine.

- `just rs coverage <crate>` is not comparable to the workspace table:
without other packages' feature unification it compiles less of the
crate.
- Default features hide feature-gated tests that run nightly in the
`rs features` leg (`--all-features`). Check that leg passed before calling
a low file untested: on 2026-10-20 it stopped at a moq-auth example's lint,
so nothing after it ran.
- Bun 1.4.2 undercounts a module loaded again with a query suffix. Verify an
apparent JS gap before acting on it, and never merge packages into one
`bun test` process.
- The most productive scan in m1 was public functions whose signature line
the lcov report never hit: walk `DA:` records for lines matching
`pub fn`/`pub(crate) fn` outside test, bench, and fuzz files. It found the
binding facades below in minutes. Per-file uncovered line counts mostly
point at GPU code and generated bindings instead.
- When sampling `fix` commits for regression tests, count
`#[moq_clock::test]` as well as `#[test]` and `#[tokio::test]`.

### m1 baselines

From nightly run 39421743227 at `f13283b302` (2026-10-20): 9,050 native
tests passed with 33 ignored, and 18 JS package processes ran 3,924 tests.
Lines covered / measured:

| Rust crate | Lines | Rust crate | Lines |
| --- | --- | --- | --- |
| hang | 2848 / 2924 | moq-loc | 141 / 153 |
| kio | 2045 / 2137 | moq-msf | 674 / 684 |
| moq-archive | 4353 / 4484 | moq-mux | 64372 / 66631 |
| moq-audio | 5455 / 5716 | moq-net | 83698 / 87593 |
| moq-auth | 5187 / 5313 | moq-nvenc | 3445 / 7771 |
| moq-bench | 1614 / 2068 | moq-pattern | 931 / 960 |
| moq-boy | 169 / 707 | moq-quic | 21696 / 22815 |
| moq-c | 8946 / 9516 | moq-relay | 10952 / 11607 |
| moq-cli | 6431 / 7566 | moq-room | 432 / 460 |
| moq-clock | 1858 / 1921 | moq-rtc | 2506 / 2882 |
| moq-e2ee | 679 / 759 | moq-rtmp | 6826 / 7638 |
| moq-ffi | 10819 / 11749 | moq-rtsp | 1033 / 1057 |
| moq-flate | 839 / 892 | moq-shaper | 2149 / 2219 |
| moq-gst | 6362 / 6740 | moq-sock | 1328 / 1486 |
| moq-hls | 8473 / 8857 | moq-srt | 1286 / 1481 |
| moq-ice | 319 / 361 | moq-stats | 4414 / 4601 |
| moq-json | 4897 / 5231 | moq-tokio | 15962 / 18005 |
| moq-uring | 4802 / 5558 | moq-transcode | 2997 / 3239 |
| moq-v4l | 9 / 1457 | moq-video | 6462 / 9988 |
| carla bridge (demo) | 923 / 1676 | | |

| JS package | Lines | Unloaded files | JS package | Lines | Unloaded files |
| --- | --- | --- | --- | --- | --- |
| common | 200 / 250 | 5 | loc | 127 / 145 | 0 |
| net | 19248 / 25149 | 4 | msf | 103 / 130 | 0 |
| p2p | 293 / 303 | 1 | video | 277 / 336 | 0 |
| clock | 310 / 333 | 1 | watch | 3123 / 4596 | 29 |
| pattern | 435 / 523 | 0 | publish | 2773 / 3308 | 22 |
| auth | 725 / 788 | 2 | room | 493 / 530 | 1 |
| e2ee | 568 / 569 | 2 | signals | 580 / 763 | 2 |
| flate | 233 / 333 | 0 | wasm | 0 / 0 | 0 |
| json | 804 / 1093 | 0 | moq-boy | 155 / 194 | 8 |
| hang | 2076 / 2899 | 1 | | | |

These are not acceptance thresholds. Compare the next run's report against
them and explain what moved. Against m0, every crate held its ratio: the
growth (moq-net +3.4k measured lines, moq-auth's in-band auth, moq-clock)
arrived tested, and moq-cli and @moq/json shrank. The m1 run's new tests
land after this baseline, so the next report should show moq-mux's
`import/track.rs` and moq-ffi's `video.rs` and `media.rs` rise.

### What m1 found

- `just rs audio-devices`, added by the m0 run, failed all five tests on its
first nightly. Two causes: cpal's PulseAudio host opened playback with the
server's default 2 s buffer (3.96 s end to end), and the tests assumed a
device starts within 100 ms while PulseAudio's idle null sink renders up to
two seconds ahead. Playback now asks PulseAudio for 20 ms periods, and the
tests wait until the device's clock moves. Watch that the first nightly
after this run is green, and keep any new device test behind the same wait.
Capture likely shares the buffer default: [PulseAudio capture periods](/quest/m2/pulseaudio-capture-period.md).
- The binding facades were the largest untested public surface:
`moq_mux::import::Track` had decoded only Avc3, Hvc1, VP8, and the audio
codecs other than MP3; `TrackStream` (the FFI raw-stream producer) had
never decoded a byte; and `MoqVideoEncoder` (`moq.video.Encoder` in every
wrapper) had no test in any language. Its doc and the Swift copy also
claimed `finish` drops the trailing access unit, which it does not.
- `just rs gpu` could not load a Vulkan loader inside the Nix shell on a
non-NixOS host. AMD and Intel now run through the flake's Mesa; NVIDIA
stays with [GPU CI](/quest/m2/gpu-ci.md).
- The VA-API renderer import tests have no caller: the m0 run mapped them to
GPU CI, which covers only NVIDIA. [VA-API renderer tests](/quest/m2/vaapi-render-tests.md)
owns them now.
- Every `#[ignore]` has a reason, and each one's caller is a recipe or a
quest. Several reasons name neither (the WGC, MediaCodec, and NVIDIA
Vulkan/CUDA tests), but their quests name the tests. Re-run the check by
test name, not by reason text.
- All 33 `fix` commits from the m0 PR to `7d2a91fe66` that changed code
carried a regression test; the rest were dependency, CI, Nix, or bench
compile fixes.

### What to check first

- The nightly legs that run tests outside `just check`: `rs audio-devices`,
`rs multicast`, `rs render-sw`, `rs quic-stress`, `rs features`, and the
`rust-test` benchmark group. A red leg hides everything after it.
- Public functions never executed, by the scan above, starting with moq-c,
moq-ffi, and moq-mux's import facades.
- Whether [Bindings in the interop matrix](/quest/m2/interop-bindings.md),
[GPU CI](/quest/m2/gpu-ci.md), [V4L2 virtual camera](/quest/m2/v4l2-virtual-camera.md),
and [MediaCodec on an emulator](/quest/m2/android-mediacodec-ci.md) landed,
before re-auditing the tests they own.

## Required

- [Release cut](/quest/m2/release/cut.md) - the release in flight ships before this run starts
Loading
Loading