Original text:
structure of the dependency tree changes as PRIORITY frames modify the dependency links between other prioritized elements.  All dependent streams are allocated an integer weight between 1 and 256 (inclusive), derived by adding one to the weight expressed in the PRIORITY frame. dependent on the orphan placeholder; pushes are dependent on the client request on which the PUSH_PROMISE frame was sent. <del> Requests may override the default initial values by including a PRIORITY frame (see frame-priority) at the beginning of the stream. These priorities can be updated by sending a PRIORITY frame on the control stream. </del>  4.3.1. server push using a Push ID (see frame-push-promise), or a placeholder using a Placeholder ID (see placeholders). <del> When a client initiates a request, a PRIORITY frame MAY be sent as the first frame of the stream, creating a dependency on an existing element.  In order to ensure that prioritization is processed in a consistent order, any subsequent PRIORITY frames for that request MUST be sent on the control stream.  A PRIORITY frame received after other frames on a request stream MUST be treated as a connection error of type HTTP_UNEXPECTED_FRAME. If, by the time a new request stream is opened, its priority information has already been received via the control stream, the PRIORITY frame sent on the request stream MUST be ignored. </del>  The PRIORITY frame payload has the following fields: A two-bit field indicating the type of element being prioritized <del> (see prioritized-element-types).  When sent on a request stream, this MUST be set to "11".  When sent on the control stream, this MUST NOT be set to "11". </del>  A two-bit field indicating the type of element being depended on <del> (see element-dependency-types). </del>  <del> A four-bit field which MUST be zero when sent and has no semantic </del>  value on receipt. A variable-length integer that identifies the element being prioritized.  Depending on the value of Prioritized Type, this contains the Stream ID of a request stream, the Push ID of a <del> promised resource, a Placeholder ID of a placeholder, or is absent. </del>  A variable-length integer that identifies the element on which a dependency is being expressed.  Depending on the value of prioritized element (see HTTP2, Section 5.3).  Add one to the value to obtain a weight between 1 and 256. <del> The values for the Prioritized Element Type (prioritized-element- types) and Element Dependency Type (element-dependency-types) imply the interpretation of the associated Element ID fields. </del>  Note that unlike in HTTP2, the root of the tree cannot be referenced using a Stream ID of 0, as in QUIC stream 0 carries a valid HTTP of type HTTP_MALFORMED_FRAME.  The following situations are examples of invalid PRIORITY frames: <del> A PRIORITY frame sent on a request stream with the Prioritized Element Type set to any value other than "11" A PRIORITY frame sent on a request stream which expresses a dependency on a request with a greater Stream ID than the current stream A PRIORITY frame sent on a control stream with the Prioritized Element Type set to "11" </del>  A PRIORITY frame which claims to reference a request, but the associated ID does not identify a client-initiated bidirectional client is not yet permitted to open MUST be treated as a connection error of type HTTP_LIMIT_EXCEEDED. <del> A PRIORITY frame received on any stream other than a request or control stream MUST be treated as a connection error of type HTTP_WRONG_STREAM. </del>  PRIORITY frames received by a client MUST be treated as a connection error of type HTTP_UNEXPECTED_FRAME.

Reviewer comments:
Limits the PRIORITY frame to be only sent on the control stream, and brings back the Exclusive Flag. The exclusive flag was previously removed in
Right now we have a SETTINGS frame that can only be sent once (in each direction), and if it is sent it has to be sent at a very precise point (the start of the stream) or the connection is bust. For these reasons, it strikes me that we could simplify things, in line with today's HTTP/3 design, by unframing settings and placing them as the control stream header. For illustration this would look something like below, where Identifier and Value can be sent multiple times. For Simplifies some parts of error handling. The HTTPMISSINGSETTINGS snowflake becomes redundant Not possible to send multiple SETTINGS on the control stream to trigger HTTPUNEXPECTEDFRAME Not possible to send a SETTINGS frame on the wrong stream to trigger HTTPWRONGSTREAM A peer that is happy with defaults can send 00 (2 bytes) rather than 040 (3 bytes). This is a tinsy tiny benefit Forces endpoints to commit to SETTINGS very early (this is of dubious benefit if SETTINGS only loosen values) Against We already have implementations that handle SETTINGS just fine Keeping the frame allows us change today's design to allow multiple SETTINGS in the future. The arguments for and against seem to net out evenly. Changing control stream seems like a cleaner design to me but shipping is a feature :tm: .
aprops NAME One way to remove [HTTPMISSINGSETTINGS] is to allow not sending the SETTINGS frame at all. By that I meant that if first thing on the control stream isn't SETTINGS, then SETTINGS is not coming, use defaults
While the proposal is interesting, I think my preference goes to retaining the current design. I agree that HTTPMISSINGSETTINGS is unnecessary, it is my view that it should be merged to HTTPUNEXPECTEDFRAME. But once it gets done, it would be my view that the complexity is indifferent; there is no difference in the encoding-side (just sending different series of octets). On the decoding-side, it either having a state that receives series of special octets or a state that receives a particular frame. That said, the reason I prefer using a frame for carrying the settings is because it makes the design consistent. Having a layer that is used for "frame"-ing all the information being exchanged is a good thing. IMO the use of HTTPUNEXPECTEDFRAME or HTTPWRONGSTREAM in relation to SETTINGS frame is fine, because use of these errors are the design pattern we use for other frames too. For example, HTTPUNEXPECTEDFRAME is used to indicate error when the peer sends a DATA frame before a HEADERS frame. Or transmission of a HEADERS frame on the control stream triggers the HTTPWRONGSTREAM error. I prefer using that same design pattern for everything, rather than creating different rules for the way things are being sent in each state.
I remembered that we touched on some of this in URL Thanks for the feedback NAME Push streams break this pattern but c'est la vie. I think I'm happy to kill this issue/proposal.
If we took this proposal, we'd be cementing a new pattern: Unidirectional streams might have a header following the type. Push already does (and in London we rejected a proposal to make Push ID behave the way SETTINGS does instead, ). I like that pattern, and alongside this would remove the concept of frame-that-can-only-be-first. That's decidedly appealing. However, we're close to late-stage and this isn't demonstrably better, just arguably cleaner.
I think that Push Streams is a good argument for pushing this change, although I might argue the Push Streams header is not a length-value structure. I think I'd prefer reusing the type-length-value structure (i.e. frames) for sending SETTINGS rather than defining it's own length-value structure just for one purpose. (not that I care much, but just my two cents)
I believe the group did not want to make this change so I am closing the issue. NAME please reopen if I am mistaken.
The additional complexities of the HTTP/3 prioritization scheme, compared to that of HTTP/2, is that PRIORITY frames might arrive out-of-order between the control stream and the request streams, as well as the complexities that generate from the premise that out-of-order handling is necessary. Our previous perception has been that it's worth the complexity, but I am becoming doubtful if it's necessary. IIUC, the need for sending a PRIORITY frame on the request stream is to handle the rare-case (like 1%) where a packet carrying the control frame is being lost. But if we are to require a server to assign the most deferred priority (i.e. weight=0) to a request for which the PRIORITY frame is yet to be received, there would be a guarantee that the performance would be no worse compared to HTTP/2 over TCP even when packet loss is involved, as NAME points out in URL To rephrase, sending PRIORITY frames on request streams is an "optimization" for a rare case instead of it being a necessity to achieve comparable or better performance to HTTP/2. Therefore, I am suggesting to stop sending PRIORITY frames on the request stream. The benefit of stopping that is that then we can have the guarantee that all the PRIORITY frames would be received by the server in the order they were sent by the client. Then, thanks to the in-order delivery guarantee, I think we can revive the "exclusive" bit , revert the introduction of the "placeholders" concept in place of idle streams.
I just lost a morr elegant reply so this might sound curt. The proposal seems to make tree entry operations more deterministic. However, tree management like pruning and shuffling based on stream closure seems non-determinisitc. H2 has problems in this regard already. Some H3 implementation experience is already bringing to light designs that have two world views of stream state: one for QUIC transport and one for H3.
I'll attempt to summarize the issue: HTTP/3 priorities are different, but not better, and this creates implementation work and technical debt? Previous issue introducing placeholders:
NAME Yeah. I think we share the view that the approach proposed will have the same pros and cons that the prioritization scheme of H2 has. I think that's a good thing, because it helps people use the same approach when using the prioritization scheme.
NAME I disagree with the view. Our task is to port HTTP/2 semantics to HTTP/3. This is how you can do it, with less divergence than we have in the draft now. So it lessens the work to be done, implementation-wise.
This is a possibility, presuming that we take . We needed PRIORITY on the request stream so that streams opening before the PRIORITY frame arrives don't erroneously starve other resources until the PRIORITY frame arrives. plus reverting initial priority would allow bringing back exclusive dependencies; placeholders were separately discussed with HTTPbis as an enhancement to incorporate into HTTP/3, so I think a decision to revert that would be handled separately.
NAME Yes. The simplification is based on . I also agree that we can discuss about placeholders separately.
I have a nagging feeling, the QUIC streams can close in non-deterministic order from the remote peer perspective. This risks a H3 priority scheme that looks similar to H2 on paper but behaves quite differently. In the worst case this requires holding more state on the server in order to increase the chances that the client and server have similar global views.
While I agree that the the streams are being closed in a different manner, it is my view that things would generally work better in HTTP/3, because closure of streams would be notified earlier to the client (due to having less HoLB). Earlier synchronization of states lead to less need for retaining information of closed streams.
NAME sorry for the confusion, I was attempting to say that HTTP/3 priorities were different from HTTP/2 priorities, and that was a negative. I just corrected my comment to say HTTP/3. NAME your concerns are well-founded, but I think that's an existing problem and not a result of a recent change? I previously mentioned(verbally) that tree maintenance should be a longer period of time(ie: 3 MSL URL ?), but I realize even that may not be sufficient for QUIC and instead we should use something like 3*PTO? I also think attaching streams to streams is inherently dangerous and much more dangerous in QUIC than HTTP/2, which is why I want to change HTTP/3 priorities to never have streams depend upon streams.
I also think we might be conflating some issues here... to me, streams-depending-on-streams + do we need placeholders is a separate discussion from the original statement of this issue. I am a bit hesitant to agree with this proposal, as I am worried about potential HOL blocking on the control stream, see also (a potential solution which was discarded in London). As mentioned above, this might be rare, but -any- loss on the control stream would impact priorities. Thinking of long fat networks and the CDN/proxy use case (of which it's still a bit unclear if we want to incorporate that into the HTTP/3 prioritization design), this might have a bigger impact than anticipated (though should only be occasional). I myself was quite happy with just changing default behaviour (with ) in the case of potential re-ordering and don't really see the need for this change. The argument that it allows re-introducing exclusive priorities (uttered elsewhere) is true, but as also uttered elsewhere, I don't really see the need for that feature (was only used by Chrome for H2 afaict) and is better replaced with something like "implicit fifo" e.g., or .
NAME the way I'm currently viewing it is that there are two tracks: The QUIC WG is gamely plugging along on its charter to replicate HTTP/2 functionality in HTTP/3 modulo changes required by the nature of the QUIC transport. In the meantime, the HTTP WG might come up with a way to replace/improve the one in HTTP/2. When they tell us what they want to use, we'll do it. With my editor's hat on, only the first is my business unless and until the second one concludes. As an individual, I can and will go to HTTPbis and advocate for something better. But on this side of the fence, I still have to make progress on the first in case the second one derails. , reverting initial PRIORITY, and bringing back Exclusive dependencies gets us back closer to HTTP/2 equivalence and had general support at the interim. So that's our just-in-case position while we see what HTTPbis decides.
NAME I think those two tracks make sense, though I do think along the way we're making some choices about the best way to change H2 priorities to be more suitable to QUIC and what compromises are and aren't acceptable, which is by its nature a series of compromises. For example, it seems a defaulting request weight of 1 or 0 would be a more HTTP/2 like solution than adding a default placeholder? But possibly it doesn't matter that much? Are there outstanding PRs for the rest of the migration back to more H2-like priorities?
NAME I do not think it matters much. And I think that servers might want to play some game here, for example giving higher default precedence to responses that carry CSS files until a PRIORITY frame is being received. That said, I think I prefer the design principle to be "provide something that is guaranteed to be at worst as good as HTTP/2." Giving least precedence to requests for which the client-specified priority is yet to be known is a natural way to achieve that. Just filed . I think that and are the remaining changes that we need to make, in order to allow browsers use the same prioritization scheme as the ones they've used in HTTP/2 (with the exception being that idle prioritized streams are replaced by placeholders).
Thanks NAME reviewing now
Thanks, this LGTM

Revised text:
structure of the dependency tree changes as PRIORITY frames modify the dependency links between other prioritized elements. <ins> An exclusive flag allows for the insertion of a new level of dependencies.  The exclusive flag causes the prioritized element to become the sole dependency of its parent, causing other dependencies to become dependent on the exclusive element. </ins> All dependent streams are allocated an integer weight between 1 and 256 (inclusive), derived by adding one to the weight expressed in the PRIORITY frame. dependent on the orphan placeholder; pushes are dependent on the client request on which the PUSH_PROMISE frame was sent.  <ins> Priorities can be updated by sending a PRIORITY frame (see frame- priority) on the control stream. </ins> 4.3.1. server push using a Push ID (see frame-push-promise), or a placeholder using a Placeholder ID (see placeholders).  <ins> In order to ensure that prioritization is processed in a consistent order, PRIORITY frames MUST be sent on the control stream. </ins> The PRIORITY frame payload has the following fields: A two-bit field indicating the type of element being prioritized  <ins> (see priority-element-types).  This MUST NOT be set to "11". </ins> A two-bit field indicating the type of element being depended on  <ins> (see priority-element-types). A single-bit flag indicating that the dependency is exclusive (see priority). </ins>  <ins> A three-bit field which MUST be zero when sent and has no semantic </ins> value on receipt. A variable-length integer that identifies the element being prioritized.  Depending on the value of Prioritized Type, this contains the Stream ID of a request stream, the Push ID of a  <ins> promised resource, or a Placeholder ID of a placeholder. </ins> A variable-length integer that identifies the element on which a dependency is being expressed.  Depending on the value of prioritized element (see HTTP2, Section 5.3).  Add one to the value to obtain a weight between 1 and 256.  <ins> The values for the Prioritized Element Type and Element Dependency Type (priority-element-types) imply the interpretation of the associated Element ID fields. </ins> Note that unlike in HTTP2, the root of the tree cannot be referenced using a Stream ID of 0, as in QUIC stream 0 carries a valid HTTP of type HTTP_MALFORMED_FRAME.  The following situations are examples of invalid PRIORITY frames:  <ins> A PRIORITY frame with the Prioritized Element Type set to "11". </ins> A PRIORITY frame which claims to reference a request, but the associated ID does not identify a client-initiated bidirectional client is not yet permitted to open MUST be treated as a connection error of type HTTP_LIMIT_EXCEEDED.  <ins> A PRIORITY frame received on any stream other than the control stream MUST be treated as a connection error of type HTTP_WRONG_STREAM. </ins> PRIORITY frames received by a client MUST be treated as a connection error of type HTTP_UNEXPECTED_FRAME.