Change:
So it turns out that there are two different things called "reserved frame types" in HTTP/3. There are the types reserved for greasing, and there are the types reserved to minimize confusion at code point overlap with HTTP/2. This PR makes three changes, separable if there's controversy: Adds "Reserved" to the frame type table, pointing to the Reserved Types section, and indicates they can be sent on all stream types. Clarifies in the Reserved section that GREASE frames can be sent on any open stream Calls out the reserved-for-H2 types as MUST NOT send, MAY error. Clarifies in the Extensibility section that, while you ignore frame types you don't know, you don't ignore that it wasn't the frame you were expecting if a particular type was required to be in that position.
We've had a long standing requirement that stream (see Section 3.2.1) by each peer By the way I interpret this, I put a check in my implementation that doesn't permit any frame until SETTINGS is received. Am I interpreting things correctly? It would be more consistent to allow reserved frame types to appear at any point on any stream that carries frames. However, I'm fine with this requirement as is but it means there is a little more effort needed to handle reserved frame types across streams.
In our implementation we are interpreting this in the same way: any frame on the control stream received before SETTINGS is a connection error. Even reserved frame types. In general the way we handle this is by discarding frame types that are forbidden rather than checking frame types that are allowed on each stream. Here is a snippet from our code. In this way we avoid the extra effort needed to handle reserved frame types that you mentioned, if I am reading your statement correctly. Basically, some frame types are explicitly disallowed. All other frame types are equal, reserved or non-reserved. Do you foresee an extension possibly benefiting from sending a frame before settings ?
Thanks NAME you made me realise I asked the question wrong. This is about reserved and non-core frames. Section 7 says: extensible protocol elements. Implementations MUST discard frames ... I have no strong use case for delivering frames before SETTINGS. But I worry it falls into a slight grey area that might affect interop. I think the correct answer is that the control stream is special case and we should clarify that in Section 7.
My preference goes to retaining the requirement as-is. This is the way H2 has worked, and I am not sure if there is a practical reason to change. FWIW, we have a similar requirement for PRIORITY frame too, which I'm also fine with: A PRIORITY frame received after other frames on a request stream MUST be treated as a connection error of type HTTPUNEXPECTEDFRAME ().
Ooh yeah, that's a good catch too. Table 1 in section 4 seems to actually highlight this behaviour with the notation. And we sort of have some text that captures this in section 4: We could add tweaks or further guidance to this paragraph ( in a PR that also that makes things explicitly clear .
On receipt, reserved is irrelevant -- it's just an unknown frame type. The reservation is simply to permit senders to generate unknown frame types without accidental collision to a real extension the client might support. So the question is whether "ignoring" unknown frame types means pretending that they weren't even there, and therefore the subsequent frame might still be the first frame on the stream. I'm inclined to say no -- you take no action on a frame you don't recognize, but that doesn't mean that the next frame was the first frame.
I think the overview table in HTTP/3 section 4 should probably also include reserved frame types. This will make it clear what streams these frames can appear on.

Discussion:
server-push for more details. Frames of unknown types (extensions), including reserved frames <del> (frame-grease) MAY be sent on a request or push stream before, after, or interleaved with other frames described in this section. </del> <ins> (frame-reserved) MAY be sent on a request or push stream before, after, or interleaved with other frames described in this section. </ins> The HEADERS and PUSH_PROMISE frames might reference updates to the QPACK dynamic table.  While these updates are not directly part of

Frame types of the format "0x1f * N + 0x21" for integer values of N are reserved to exercise the requirement that unknown types be ignored (extensions).  These frames have no semantics, and can be <del> sent when application-layer padding is desired.  They MAY also be sent on connections where no data is currently being transferred. Endpoints MUST NOT consider these frames to have any meaning upon receipt. </del> <ins> sent on any open stream when application-layer padding is desired. They MAY also be sent on connections where no data is currently being transferred.  Endpoints MUST NOT consider these frames to have any meaning upon receipt. </ins> The payload and length of the frames are selected in any manner the implementation chooses. <ins> Frame types which were used in HTTP/2 where there is no corresponding HTTP/3 frame have also been reserved (iana-frames).  These frame types MUST NOT be sent, and receipt MAY be treated as an error of type HTTP_UNEXPECTED_FRAME. </ins> 8. QUIC allows the application to abruptly terminate (reset) individual

extensible protocol elements.  Implementations MUST discard frames and unidirectional streams that have unknown or unsupported types. This means that any of these extension points can be safely used by <del> extensions without prior arrangement or negotiation. </del> <ins> extensions without prior arrangement or negotiation.  However, where a known frame type is required to be in a specific location, such as the SETTINGS frame as the first frame of the control stream (see control-streams), an unknown frame type does not satisfy that requirement and SHOULD be treated as an error. </ins> Extensions that could change the semantics of existing protocol components MUST be negotiated before being used.  For example, an

Where HTTP/2 employs PADDING frames and Padding fields in other frames to make a connection more resistant to traffic analysis, HTTP/3 can either rely on transport-layer padding or employ the <del> reserved frame and stream types discussed in frame-grease and stream- grease.  These methods of padding produce different results in terms of the granularity of padding, the effect of packet loss and </del> <ins> reserved frame and stream types discussed in frame-reserved and stream-grease.  These methods of padding produce different results in terms of the granularity of padding, the effect of packet loss and </ins> recovery, and how an implementation might control padding. 10.2.