Code change:
3.2. <del> The first stream opened is a client-initiated bidirectional stream where the peers exchange SETUP messages (message-setup).  The subsequent streams MAY be either unidirectional or bidirectional. For exchanging content, an application would typically send a unidirectional stream containing a single OBJECT message (message- object), as putting more than one object into one stream may create head-of-line blocking delays.  However, if one object has a hard dependency on another object, putting them on the same stream could be a valid choice. </del> <ins> The first stream opened is a client-initiated bidirectional control stream where the peers exchange SETUP messages (message-setup).  All messages defined in this draft are sent on the control stream after the SETUP message.  Control messages MUST NOT be sent on any other stream, and a peer receiving a control message on a different stream closes the session as a 'Protocol Violation'.  Objects MUST NOT be sent on the control stream, and a peer receiving an Object on the control stream closes the session as a 'Protocol Violation'. This draft only specifies a single use of bidirectional streams. Objects are sent on unidirectional streams.  Because there are no other uses of bidirectional streams, a peer MAY currently close the connection if it receives a second bidirectional stream. The control stream MUST NOT be abruptly closed at the QUIC layer. Doing so results in the session being closed as a 'Protocol Violation'. </ins> 3.3.

Related discussion:
text: This would also be nice for the CDN, as each control streams could be routed to a separate backend/origin. A fatal error (RESETSTREAM) on the chat control stream would not impact the media control stream and vice-versa. However, this doesn't quite work right now because the can be collisions. The chat and media system would need to coordinate to avoid collisions, otherwise IDs need to be rewritten. Any incoming data streams need to be forwarded to the correct component based on this rewrite lookup table. One way to fix this is to extend all messages to include a , where 0=media and 1=chat in this example. Each control stream gets its own ID and OBJECTs would include the ID, avoiding collisions and making it very easy to route within the application and CDN. (this is basically WebTransport session pooling) In fact, now each session could even use a different version of MoQ. This would be super useful when the chat and media backends are running different versions of the protocol. It's why I suggested at the end of the call (NAME that each control stream contains it's own SETUP handshake.
Individual comment: Do you mean the "sendOrder" field in OBJECT (section 6.2), or something else? I'm not sure normative language is required here, especially if it's based on what current QUIC implementations supports as a prioritization API. Someday a QUIC implementation could support changing priorities at different offsets for a stream. As for pooling - WebTransport has taught us that pooling is a huge headache. I suggest we defer to WebTransport or open multiple QUIC connections rather than trying to define yet another pooling layer in moqt.
I have a draft in the works to support doing this for HTTP/3, so it's not far off in my world
Well, I kinda think the normative language is justified when priority schemes are written on the wire. You're totally right that an implementation could prioritize at byte offsets... but that doesn't mean a relay can support it. Ugh, I guess we need to discuss if prioritization schemes are negotiated or not. My goal was to require a base scheme (send order) in the transport draft so we could just assume that every MoQ relay will support it, and thus normative language like this is fine.