Skip to content

feat(cli): report import stats and export feedback - #5783

Closed
t0ms wants to merge 1 commit into
moq-dev:quest/m2/stats/schemafrom
t0ms:quest/m2/stats/rust
Closed

t0ms wants to merge 1 commit into
moq-dev:quest/m2/stats/schemafrom
t0ms:quest/m2/stats/rust

Conversation

@t0ms

@t0ms t0ms commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #5643 (base quest/m2/stats/schema), as the maintainer asked there, and rebased onto its head 8cadf9f4, which takes main.

Problem

#5643 defines the publisher's stats snapshot and the viewer's .echo feedback, but nothing in Rust
writes either. The Rust reporters
quest asks moq-mux to count what each rendition carries and the CLI to publish it.

Approach

This is the import and export half. The quest file now holds the rest: the capture encoders, moq play --echo, and gateway --stats.

  • moq-mux counts at the container edges. catalog::Producer::media / media_raw attach a
    counter to each track a container importer writes: frames, payload bytes, and keyframes for video.
    Source counts what an exporter reads: frames, bytes, and the newest arrival (timestamp and
    wall). catalog::Producer::stats() and Source::stats() return them keyed by rendition ID. Every
    container import and export shares them. Counts are cumulative for the process: a rendition that
    ends keeps its final counts, and one that returns under the same ID continues them. An fMP4 import
    counts samples as frames.
  • moq import --stats names stats.json (and its .z) in the catalog's stats section while
    the importer still holds its reservation, so the section rides the first catalog. It writes about
    once a second while subscribed, with the connection's RTT, estimated send rate, and loss. At EOF it
    writes the final counts whether or not anyone subscribes, and the import holds the track through
    --linger, so a late subscriber still reads them. It covers the stdin imports. import capture,
    the gateways, archive, and ts --program all refuse it: the capture encoders create their tracks
    directly and do not count yet, and --program all builds a catalog per program.
  • moq export --echo <name> follows the catalog's echo section and publishes
    <prefix>/<name>.echo with feedback.json (and its .z). Each catalog update reconciles it, and
    the broadcast is retracted when the export ends. The catalog finishing does not end it, since the
    export still drains its delayed tail. --echo covers the stdout container exports, and refuses
    --catalog-format msf, which carries no echo section.
  • moq export stats / moq export echo print reports as JSON lines. stats follows a
    broadcast's stats track until the broadcast ends. echo prints {"broadcast", "feedback"} for
    every .echo broadcast under --broadcast.
  • Docs: doc/bin/cli.md § Stats and feedback, doc/concept/stats.md, and the quest rewritten for
    the remaining half.

Decisions a reviewer may want to revisit:

  • The CLI refuses --stats where it would publish an empty or partial track, rather than publishing
    one.
  • --echo names one path segment.
  • Reports have the lowest priority, below every media track.

Impact

  • New flags and sinks only; nothing changes without them.
  • moq-mux gains catalog::Producer::stats and Source::stats.
  • moq-json moves from moq-cli's dev-dependencies to its dependencies.

Results

just fix and just check pass with the TS health commit on top: 3,243 and 436 tests. This commit
alone passes moq-mux's and moq-cli's 1,598 tests and lint. On macOS, play's link step trips
build.warnings on the __eh_frame linker note; with warnings allowed it passes 206 of 206, that
note being its only warning. The tests are new:

Test What it shows Result
stats_count_what_the_import_writes_and_the_export_reads (moq-mux) an in-process bbb_cbr.ts import counts exactly the frames and bytes written, and an export's Source the same after draining, with an arrival pass
a_returning_track_continues_its_counts, an_ended_track_keeps_its_final_counts, arrival_pairs_the_latest_timestamp_with_its_wall_time the counter registry pass
import_stats_count_what_each_rendition_wrote (CLI over a test relay) half the clip, a report, then the rest: the first report counts less, the last equals an in-process import's counts, RTT present pass
a_late_sink_reads_the_final_stats a sink joining after EOF, during the linger, reads the final counts pass; fails without the final write and the hold (first "not found", then an empty track)
export_echo_reports_what_the_export_reads feedback at viewers/alice.echo from a catalog soliciting viewers; frames read never exceed those written; the arrival advances; RTT present pass
stats_needs_a_catalog_the_cli_builds, echo_needs_a_container_export_and_a_hang_catalog the refusals pass

(Written by Claude Opus 5.5)

`moq import --stats` names a stats track in the catalog the import builds and
fills it with what each rendition has written: frames, payload bytes, and video
keyframes, with the connection's transport. `moq export --echo <name>`
publishes the feedback a catalog solicits, counting what the export reads and
its newest arrival. `moq export stats` and `moq export echo` print either as
JSON lines.

moq-mux counts at the container producer and the source, so every container
import and export shares the counters. Capture encoders, gateways, `archive`,
and `ts --program all` refuse `--stats`; MSF catalogs refuse `--echo`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@t0ms
t0ms force-pushed the quest/m2/stats/rust branch from eedd70a to c5b2b84 Compare October 17, 2026 04:00
@kixelated
kixelated deleted the branch moq-dev:quest/m2/stats/schema October 17, 2026 04:00
@kixelated kixelated closed this Oct 17, 2026
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.

2 participants