Change:
It is RECOMMENDED that "initial_max_bidi_streams" be no smaller than 100, so as to not unnecessarily limit parallelism. <del> HTTP/3 does not use server-initiated bidirectional streams; clients MUST omit or specify a value of zero for the QUIC transport parameter "initial_max_bidi_streams". </del> <ins> HTTP/3 does not use server-initiated bidirectional streams, though an extension could define a use for these streams.  Clients MUST treat receipt of a server-initiated bidirectional stream as a connection error of type HTTP_GENERAL_PROTOCOL_ERROR unless such an extension has been negotiated. </ins> 6.2.

Discussion:
per London discussion. Removes the mandate that clients send a TP of zero for and replaces it with an error on stream open unless there's an extension permitting it.
There are presently several kinds of very similar error when creating streams: HTTPUNKNOWNSTREAMTYPE MAY be used to tell a peer to STOPSENDING on a stream type that is unknown by the local peer. It is not a connection error. HTTPWRONGSTREAMCOUNT MUST be used if a peer tries to open more than one critical stream (control, QPACK). Connection error. HTTPWRONGSTREAMDIRECTION MUST be used if a client tries to open a push stream. More generally this could be used if a peer attempts to open a stream type that is not allowed to, but push is the only example today. Connection error. The suggestion is to rationalize these into a single error code - HTTPSTREAMCREATIONERROR - that can be used in STOPSENDING or CLOSECONNECTION. The impact of merging COUNT and DIRECTION is minimal because implementations fundamentally have to open streams correctly in order to interop. PS. The eagle eyes will notice I omitted the HTTPDUPLICATE_PUSH creation error. This is on the chopping block in . I class it differently because it is about parsing information after the stream type.
Should a client respond with STREAMCREATIONERROR when it sees the server opening a bidirectional stream? At the moment the designated error code is HTTPGENERALPROTOCOLERROR, but STREAMCREATIONERROR might be a better fit. Or if we are not going to use STREAMCREATIONERROR for server-initiated bidirectional streams, I think we should better rename it to UNIDIRECTIONALSTREAMCREATIONERROR to avoid confusion.
This relates to some earlier discussion on URL and its now-merged PR URL We only recently added text to specify the use of HTTPGENERALPROTOCOLERROR in this case, I think it fits to modify this to STREAMCREATION_ERROR.
Changed in URL
I don't think that we need the MUST here. An extension might want to use those streams. It should be enough to note that these aren't used.
Would the scope of this change include adding text on how core HTTP/3 implementation should treat the reception of data on these streams?
It probably has to, yes. That's something we generally do with most of our MUST statements anyway.

This might be a transport question, but how should a client respond to a server trying to open a server-initiated bidirectional stream? Assuming that the client's initialmaxstreamsuni is zero, a server would send a STREAMSBLOCKED frame. In response, the client would send a MAXSTREAMS frame with the value set to zero. However, IIUC, this MAXSTREAMS frame merely indicates that the resource is temporary unavailable. That means that the server would be blocked. To rephrase, the transport does not provide a way for an endpoint to reject a stream, without letting the peer to actually send a STREAM frame. Are we fine with that? If we think it as a problem, maybe we should change the definition of initialmaxstreams TP. For example, we could specify that the omission of the initialmaxstreams TP indicates rejection of the corresponding type of streams being opened (instead of interpreting the omission as "zero").
I don't think the transport should police what streams are opened beyond managing resource consumption. It may well be, in some other app protocol, that a server is free to open bidi streams, but only if they start with a certain header, or none at all. The app protocol should make both endpoints agree and what is permitted and police accordingly. An application layer could have credits similar to MAX_STREAMS to permit opening certain streams with or without a header. The transport need not deal with this.
Right. The transport only needs to concern itself with policing stream limits. The question here is more about how the use of h3 constrains future extension. As Mikkel says, if there is a use for the server-initiated streams, we shouldn't constrain that.
On the other hand, an extension could modify this requirement, too. Much of what's in the base spec is for the unextended protocol, and I think this is an instance of that. However, this is a MUST which we don't permit the server to enforce, which argues for making it a SHOULD instead. Maybe SHOULD omit/zero, "unless an extension which defines their use is being offered."?
MUST not accept any bidirectional streams that are not explicitly permitted by extensions. I'm not sure about stream header formats here - it would be easy to create conflicts across extensions.

I'd suggest we define those to be the same format as client-initiated ones, and use a column in IANA registry for listing which party can be the initiator. This way, extensions get a uniform way of defining those streams.
Discussed in London; spec shouldn't prohibit or require any particular value, but should say that these streams have no meaning in the protocol and can only be used by negotiation. If you get one without having negotiated their use, it's a connection error.