Skip to content

feat(cli)!: inspect a relay with moq ls and moq fetch - #4032

Merged
kixelated merged 46 commits into
devfrom
quest/m1/cli-inspect/README
Sep 26, 2026
Merged

kixelated merged 46 commits into
devfrom
quest/m1/cli-inspect/README

Conversation

@kixelated

@kixelated kixelated commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Targets dev: this line carries a published moq-net break (#4059: AnnounceConsumer::next returns announce::Event).

Problem

An operator inspecting a relay had to curl its HTTP /announced and /fetch, outside the session's own auth, and nothing showed how to watch the live set change or read the relay's stats.

Approach

Impact

  • Public API (moq-net, breaking): announce::Update becomes announce::Announce, announce::Kind is removed, and AnnounceConsumer::next, poll_next, try_next, and the Stream item return announce::Event. No moq-ffi, libmoq, or JS API change.
  • CLI: new ls verb; fetch reaches hidden broadcasts.
  • Wire: none.

Alternatives

  • Document only curl for stats and leave moq fetch unable to read them. Rejected: the fix is a scoped origin, the same one ls uses.

Follow-ups

  • JS parity for the Live marker is the js-announce-caught-up quest; an explicit moq-transport boundary is ietf-announce-count.
  • A relay still replaying an upstream session sends ANNOUNCE_OK with only the routes it has so far, so a downstream moq ls can end early. Waiting for the origin's Live deadlocks cluster meshes (relays wait on each other's replay); needs its own quest.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 9 commits September 24, 2026 10:30
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#4059)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Carry main's new announce consumers over to the `announce::Event` shape
(#4059): cluster, auth_lifetime, hidden_cluster, smoke, and announce_to_serve
tests, plus the hidden-broadcast docs. `moq fetch` (#3965) already landed on
main, so its quest leaves this line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ing main

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The subscriber origin asked the relay for every announcement, which hides
dot-prefixed segments, so `moq fetch` never resolved `.stats/...` and timed
out while HTTP `/fetch` served it. Scope the session to the broadcast, as
`moq ls` scopes to its prefix.

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(cli-inspect): CLI inspection feat(cli)!: inspect a relay with moq ls and moq fetch Sep 25, 2026
…EADME

# Conflicts:
#	quest/m1/README.md
#	rs/moq-relay/src/connection.rs
@kixelated
kixelated changed the base branch from main to dev September 25, 2026 17:57
kixelated and others added 7 commits September 25, 2026 16:35
…pts (#4146)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Grok 4.7 <noreply@x.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Grok 4.7 <noreply@x.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Grok 4.7 <noreply@x.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review September 26, 2026 00:10
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-26T15:22:22.863359Z 9796b47 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

kixelated and others added 5 commits September 25, 2026 17:11
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>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Grok 4.7 <noreply@x.ai>
…free port (#4198)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c40a2d8373

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// forward the stored chain as-is (no self push here).
let mut initial: Vec<(crate::PathOwned, Hops, crate::origin::Cost)> = Vec::new();
while let Some(update) = announced.try_next() {
while let Some(event) = announced.try_next() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Wait for Live before sending the initial count

When a downstream announce stream opens while this relay's origin is still replaying an upstream session, try_next() can return None before Event::Live. This then sends ANNOUNCE_OK with a partial or zero active count, causing the downstream cursor to emit Live and a non-following moq ls to exit before the remaining routes arrive. Defer the initial count until the origin actually yields Live, rather than treating a temporarily empty queue as caught up.

Useful? React with 👍 / 👎.

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.

Valid gap, but not fixable this way. I tried holding the burst until the origin yields Live: relays in a mesh replay from each other, so each announce stream waits on the peer's own replay (directly, or around a triangle), and the cluster tests (goaway_cluster, cluster_unknown, lan_cluster_path_carries_broadcasts_both_ways) deadlock or time out. Breaking that cycle needs a design decision (for example, waiting only on sources that are not reachable through the requesting peer, or bounding the wait), so I left the empty-queue count as is and flagged it as a follow-up.

(Written by Claude Opus 5.5)

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.

Maintainer decision: won't fix. A relay must never block its answer on other nodes finishing their replay; waiting across the mesh is worse than this rare race. moq ls reports what is listed at the moment the count arrives.

(Written by Claude Opus 5.5)

Comment on lines +1270 to 1273
// Land before decoding past the boundary, so no live update
// enters the origin ahead of the marker.
Self::poll_landing(&mut self.replaying, &mut run.landing, waiter);
match stream.reader.poll_decode_maybe::<lite::AnnounceBroadcast>(&mut cx) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not infer the replay boundary from a quiet timer

For Lite03/04, a runtime stall or packet gap longer than the 30 ms quiet window makes this call drop the replay guard before attempting to decode the next message, even when that announcement is already buffered. The route then appears after Live, so a non-following listing can silently return a partial snapshot; the IETF namespace path uses the same Quiet heuristic. Silence is not a reliable protocol boundary, so use an explicit boundary or refuse snapshot completeness on versions that cannot provide one.

AGENTS.md reference: AGENTS.md:L16-L16

Useful? React with 👍 / 👎.

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.

Leaving this as is. Lite03/04 carry no initial-set boundary on the wire, so a quiet window is the only signal short of never going live, which would make a non-following moq ls hang on those versions. The timer is the documented fallback; lite-05+ uses the ANNOUNCE_OK count, and an explicit boundary for moq-transport is tracked by the ietf-announce-count quest.

(Written by Claude Opus 5.5)

kixelated and others added 3 commits September 26, 2026 00:21
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 and others added 21 commits September 26, 2026 00:54
…o waiter lists (#4216)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…imit (#4197)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Grok 4.7 <noreply@x.ai>
…de a browser (#4217)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ck (#4215)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: moq-bot[bot] <186640430+moq-bot[bot]@users.noreply.github.com>
…4120)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Jakub Migdał <j.migdal42@gmail.com>
Co-authored-by: Grok 4.7 <noreply@x.ai>
…f quests (#4229)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Patch bumps for unreleased behavior since #3879. Rust stays with release-plz. Go stays at 0.7 because the wrapper additions are compatible and CI owns that patch.

Co-Authored-By: Grok <noreply@x.ai>
Co-authored-by: GPT-6 <noreply@openai.com>
Co-authored-by: Grok 4.7 <noreply@x.ai>
Co-authored-by: GPT-6 <noreply@openai.com>
#4170)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Grok 4.7 <grok-4.7@x.ai>
…kills (#4227)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Grok 4.7 <noreply@x.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: GPT-6 <noreply@openai.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	quest/m1/README.md
# Conflicts:
#	doc/lib/rs/moq-auth.md
#	quest/m1/README.md
#	rs/kio/src/loom.rs
#	rs/kio/src/waiter.rs
#	rs/moq-auth/Cargo.toml
#	rs/moq-auth/src/client.rs
#	rs/moq-cli/src/fetch.rs
#	rs/moq-net/src/lite/subscriber.rs
#	rs/moq-net/tests/support/mock.rs
#	rs/moq-relay/src/auth.rs
#	rs/moq-tokio/tests/broadcast.rs
main's max age test took the first announce event as the publisher's
broadcast; on this line an empty initial set yields `Live` first.

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

Landing pass:

(Written by Claude Opus 5.5)

@kixelated
kixelated enabled auto-merge (squash) September 26, 2026 15:19

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9796b47029

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rs/moq-cli/src/fetch.rs

// Scoped to the broadcast, so the relay announces it by name even when a hidden
// segment such as `.stats` would keep it out of an unscoped listing.
let pattern = moq_net::Pattern::subtree(&broadcast).with_context(|| format!("invalid broadcast `{broadcast}`"))?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle maximum-depth broadcasts without appending **

When --broadcast names a valid 32-segment path (Path::MAX_PARTS), Pattern::subtree appends a globstar as a 33rd segment and returns TooManySegments, so moq fetch now rejects that broadcast before connecting even though it was fetchable before this scoping change and is valid on the wire. Special-case maximum-depth paths with an exact literal pattern, since they cannot have valid descendants.

Useful? React with 👍 / 👎.

@kixelated
kixelated merged commit f61e4d0 into dev Sep 26, 2026
28 checks passed
@kixelated
kixelated deleted the quest/m1/cli-inspect/README branch September 26, 2026 16:08
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