Skip to content

Conversation

@ianswett
Copy link
Collaborator

@ianswett ianswett commented Oct 31, 2025

I did not remove Request ID entirely in this PR, because it makes the most sense to do that all at once, but I did create new 'NAMESPACE' and 'NAMESPACE_DONE' messages that are separate from PUBLISH_NAMESPACE/PUBLISH_NAMESPACE_DONE and much simpler.

Saves bytes on the wire by not repeating the 'Track Namespace Prefix' for every Namespace.

Removes UNSUBSCRIBE_NAMESPACE because we can just close the stream.

Fixes #1348
Fixes #1310
Fixes #1305
Fixes part of #1168
Fixes #843

Further possible changes:

  1. Don't send REQUEST_ERROR on errors, QUIC RESET_STREAM with the application error code. Loses Reason Phrase
  2. Don't send REQUEST_OK on success. Loses response parameters.
  3. Allow for subscribing to full Track names and not just Namespaces.
  4. Prohibit sending NAMESPACE_DONE before a NAMESPACE is received for a SUBSCRIBE_NAMESPACE
  5. Add a PUBLISH_BLOCKED sent on the response stream when a new PUBLISH couldn't be sent No way to indicate that PUBLISHes from SUBSCRIBE_NAMESPACE were blocked #1262
  6. Drop the length from NAMESPACE and NAMESPACE_DONE

…ng to Namespaces or PUBLISH

I did not remove Request ID entirely in this PR, because it makes the most sense to do that all at once, but I did create a new 'NAMESPACE' message that's separate from PUBLISH_NAMESPACE and much simpler.

Fixes #1310 
Fixes #1168 
Fixes #843
@ianswett ianswett requested a review from afrind October 31, 2025 00:15
@ianswett ianswett added Design Issues or PRs that change how MoQ works including the wire format. Publish Namespace (formerly Announce) Issues with PUBLISH_NAMESPACE (formerly Announce) labels Oct 31, 2025
Copy link
Collaborator

@afrind afrind left a comment

Choose a reason for hiding this comment

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

What does the subscriber do with the write half of the bidi stream after the SUBSCRIBE_NAMESPACE? FIN, or leave open?

How does this impact UNSUBSCRIBE_NAMESPACE, if at all?

If we introduce REQUEST_UPDATE (#1332), where does that go?

Comment on lines 2896 to 2897
Type (i) = 0x6,
Length (16),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Aren't these 3 bytes completely redundant?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah the response stream can have both NAMESPACE and PUBLISH_NAMESPACE_DONE so you need type (and also REQUEST_OK/ERROR, maybe?). Length feels useless here, but I can live with it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I think I need a type. The Length is a bit more obviously redundant, but that goes back to the TLV vs TV conversation. I think there's a good argument that this isn't on the control stream and one could use TV even if we're using TLV elsewhere.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This stream is currently a mini control stream that supports:

REQUEST_OK
REQUEST_ERROR
NAMESPACE
PUBLISH_NAMESPACE_DONE

There's some nice code reusability there, enough that I can live with the length redundancy. The alternative is quite a bit more spec text, but I can live with that too if folks are concerned.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think it's worth considering, but we can make it separable.

request the current set of matching published namespaces and `Established`
subscriptions, as well as future updates to the set.
The subscriber sends a SUBSCRIBE_NAMESPACE control message on a new
bidirectional stream to a publisher to request the current set of matching
Copy link
Collaborator

Choose a reason for hiding this comment

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

How do you distinguish the control stream from this stream?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's a new bidi stream and it starts with the SUBSCRIBE_NAMESPACE message.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So if the first stream I receive starts with SUBSCRIBE_NAMESPACE, I hold it pending one that starts with CLIENT_SETUP?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Without 0RTT clearly described, which it isn't today, I'm unsure how that could happen?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah @afrind if right.

It depends on if the QUIC library returns streams in stream_id order, but any bidirectional stream should be buffered until the CLIENT_SETUP is processed. In fact, the same is true for any unidirectional streams if pipelining a PUBLISH is valid (debatable with max_request_id), but that's a lot easier to implement.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, I understand the issue now. Yes, I can call out this potential issue.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

PTAL at 2465b19

the Track Namespace Prefix that have not already been sent to this subscriber.
If the set of matching PUBLISH_NAMESPACE messages changes, the publisher sends
the corresponding PUBLISH_NAMESPACE or PUBLISH_NAMESPACE_DONE message.
The publisher will respond with REQUEST_OK or REQUEST_ERROR. If the
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you mean to say these will come on the response half of the bidi stream.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

True, I updated the text above. This text is fairly duplicative I think, but I guess we can move it in another PR?

the corresponding PUBLISH_NAMESPACE or PUBLISH_NAMESPACE_DONE message.
The publisher will respond with REQUEST_OK or REQUEST_ERROR. If the
SUBSCRIBE_NAMESPACE is successful, the publisher will send matching
NAMESPACE messages on the response stream if they are requested.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need or want a mechanism to get only the track names in the same format as namespaces, or we think only PUBLISH is sufficient?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think we do want that, but I was trying to keep this small. Happy to add it into this PR if we're all sure we want it.


* Parameters: The parameters are defined in {{version-specific-params}}.

## NAMESPACE {#message-pub-ns}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
## NAMESPACE {#message-pub-ns}
## NAMESPACE_NOTIFY {#message-pub-ns}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't have a strong opinion, but NAMESPACE is shorter

@ianswett
Copy link
Collaborator Author

ianswett commented Nov 1, 2025

What does the subscriber do with the write half of the bidi stream after the SUBSCRIBE_NAMESPACE? FIN, or leave open?

I'm inclined to leave it open, at least until we decide if want to send REQUEST_UPDATE on it.

How does this impact UNSUBSCRIBE_NAMESPACE, if at all?

I removed it in the more recent update, because it wasn't needed.

If we introduce REQUEST_UPDATE (#1332), where does that go?

On the open bidi stream.

Comment on lines 2896 to 2897
Type (i) = 0x6,
Length (16),
Copy link
Collaborator

Choose a reason for hiding this comment

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

This stream is currently a mini control stream that supports:

REQUEST_OK
REQUEST_ERROR
NAMESPACE
PUBLISH_NAMESPACE_DONE

There's some nice code reusability there, enough that I can live with the length redundancy. The alternative is quite a bit more spec text, but I can live with that too if folks are concerned.

request the current set of matching published namespaces and `Established`
subscriptions, as well as future updates to the set.
The subscriber sends a SUBSCRIBE_NAMESPACE control message on a new
bidirectional stream to a publisher to request the current set of matching
Copy link
Collaborator

Choose a reason for hiding this comment

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

So if the first stream I receive starts with SUBSCRIBE_NAMESPACE, I hold it pending one that starts with CLIENT_SETUP?

request the current set of matching published namespaces and `Established`
subscriptions, as well as future updates to the set.
The subscriber sends a SUBSCRIBE_NAMESPACE control message on a new
bidirectional stream to a publisher to request the current set of matching
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah @afrind if right.

It depends on if the QUIC library returns streams in stream_id order, but any bidirectional stream should be buffered until the CLIENT_SETUP is processed. In fact, the same is true for any unidirectional streams if pipelining a PUBLISH is valid (debatable with max_request_id), but that's a lot easier to implement.

So it can use the Suffix approach and not specify the full Namespace
@ianswett ianswett changed the title Put PUBLISH_NAMESPACE on a stream and unlink Namespaces from PUBLISH Put PUBLISH_NAMESPACE on a stream, make Namespaces and PUBLISH independent Nov 4, 2025
@ianswett ianswett changed the title Put PUBLISH_NAMESPACE on a stream, make Namespaces and PUBLISH independent Put SUBSCRIBE_NAMESPACE on a stream, make Namespaces and PUBLISH independent Nov 4, 2025
@afrind
Copy link
Collaborator

afrind commented Nov 13, 2025

Discussed 11/13 with Authors/Editors -- plan to present to the wg at the interim

@afrind
Copy link
Collaborator

afrind commented Nov 18, 2025

Presented at 11/17 Interim:

Plan is to proceed with this design.

Copy link
Collaborator

@afrind afrind left a comment

Choose a reason for hiding this comment

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

This looks close

Comment on lines 1112 to 1113
part of that namespace. This includes echoing back PUBLISH or PUBLISH_NAMESPACE
messages to the endpoint that sent them. If an endpoint accepts its own
Copy link
Collaborator

Choose a reason for hiding this comment

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

PUBLISH_NAMESPACE is not longer echoed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think it probably should be, to minimize any behavior change, but the PUBLISH_NAMESPACE would turn into a NAMESPACE message on the wire.


The publisher sends the `NAMESPACE_DONE` control message to indicate its
intent to stop serving new subscriptions for tracks within the provided Track
Namespace. All NAMESPACE messages are in response to a SUBSCRIBE_NAMESPACE,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This bit about NAMESPACE messages applies to both NS and NS_DONE, and is in the NS_DONE section.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fair point, any suggestions? Just remove it?

Comment on lines 2920 to 2922
* Track Namespace Suffix: Specifies the final portion of a track's
namespace as defined in {{track-name}}. The namespace begins with the
'Track Namespace Prefix' specified in {message-subscribe-ns}.
Copy link
Collaborator

Choose a reason for hiding this comment

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

"final portion" is a bit under defined. Maybe

Specifies the final portion of a track's namespace as defined in {{track-name}} after removing namespace tuples included in Track Namespace Prefix...

Length (16),
Request ID (i),
Track Namespace Prefix (..),
Subscribe Options (i),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can one send 2 subscribe_namespace with 2 different options

Copy link
Collaborator

Choose a reason for hiding this comment

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

No, this falls under duplicate prefix text elsewhere.

could arrive prior to the control stream, in which case the data SHOULD be buffered
until the control stream arrives and setup is complete.
If an implementation does not want to buffer, it MAY reset other bidirectional
streams before the session and control stream are established.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This PR does not really provide a good way for implementations to figure out what stream is the control stream.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There is a type identifier at the beginning of the control stream, which is the SETUP messages.

|-------|-----------------------------------------------------|
| 0xE | NAMESPACE_DONE ({{message-namespace-done}}) |
|-------|-----------------------------------------------------|
| 0xC | PUBLISH_NAMESPACE_CANCEL ({{message-pub-ns-cancel}})|
Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks like we're repeating the mistake we had in HTTP/3 where we are adding streams without type identifiers and then have some semantic rules about what messages can appear where. Can we have an explicit type for bidi streams instead?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@vasilvv the current PR is adequate, in that it either starts with CLIENT_SETUP or it starts with SUBSCRIBE_NAMESPACE. This is extensible since have varint frame type so have unlimited ways to start streams. It seems like it would be fairly redundant to have:

SETUP_STREAM
CLIENT_SETUP

and

SUB_NS_STREAM
SUB_NS

Right?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess the counter-argument is if in the future you want to start a stream with a non-message. This is what webtransport ran into and it got a little ugly, but ultimately resolved it by reserving a frame type and giving it new semantics.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I definitely don't want to repeat that mistake, but in this case we are adding type/message identifiers.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I can see that this works, but I don't see why we would want to do that. If there are two types of streams, and they have basically disjoint message type list, why do we want them to have the same format?

Comment on lines +1157 to +1158
A SUBSCRIBE_NAMESPACE can be cancelled by closing the stream with
either a FIN or RESET_STREAM. Cancelling does not prohibit original publishers
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
A SUBSCRIBE_NAMESPACE can be cancelled by closing the stream with
either a FIN or RESET_STREAM. Cancelling does not prohibit original publishers
A SUBSCRIBE_NAMESPACE can be cancelled by the creator the stream, by closing the stream with
either a FIN or RESET_STREAM. Cancelling does not prohibit original publishers

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It can be cancelled by either the creator or the peer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Design Issues or PRs that change how MoQ works including the wire format. Publish Namespace (formerly Announce) Issues with PUBLISH_NAMESPACE (formerly Announce)

Projects

None yet

6 participants