Change:
ClientHelloInner and ClientHelloOuter will lead to a very large overall size.  One particularly pathological example is "key_share" with post-quantum algorithms.  In order to reduce the impact of <del> duplicated extensions, the client may use the "outer_extension" </del> <ins> duplicated extensions, the client may use the "outer_extensions" </ins> extension. <del> OuterExtensions MUST only be used in ClientHelloInner.  It consists of one or more ExtensionType values, each of which reference an extension in ClientHelloOuter, and a digest of the complete ClientHelloInner. </del> <ins> OuterExtensions consists of one or more ExtensionType values, each of which reference an extension in ClientHelloOuter, and a digest of the complete ClientHelloInner. </ins> When sending ClientHello, the client first computes ClientHelloInner, <del> including any PSK binders, and then MAY substitute extensions which it knows will be duplicated in ClientHelloOuter.  To do so, the client computes the digest of the entire ClientHelloInner message as: </del> <ins> including any PSK binders.  It then computes a new value, the EncodedClientHelloInner, by first making a copy of ClientHelloInner. It then MAY substitute extensions which it knows will be duplicated in ClientHelloOuter.  To do so, the client computes the digest of the entire ClientHelloInner message as: </ins> where "inner" is the ClientHelloInner structure and "Extract", "Expand", and "Nh" are as defined by the KDF API in I-D.irtf-cfrg- hpke.  Then, the client removes and replaces extensions from <del> ClientHelloInner with a single "outer_extension" extension.  The list of outer extensions, OuterExtensions.outer_extensions, includes those which were removed from ClientHelloInner, in the order in which they were removed. This process is reversed by client-facing server.  Specifically, the server replaces the "outer_extension" with the corresponding sequence of extensions in the ClientHelloOuter.  If any referenced extensions are missing, the server MUST abort the connection with an "illegal_parameter" alert.  The server then computes the digest of the reconstructed ClientHelloInner.  If the digest does not equal OuterExtensions.inner_digest, then the server MUST abort the connection with a "decrypt_error" alert. </del> <ins> EncodedClientHelloInner with a single "outer_extensions" extension. Removed extensions MUST be ordered consecutively in ClientHelloInner. The list of outer extensions, OuterExtensions.outer_extensions, includes those which were removed from EncodedClientHelloInner, in the order in which they were removed. Finally, EncodedClientHelloInner is serialized as a ClientHello structure, defined in Section 4.1.2 of RFC8446.  Note this does not include the four-byte header included in the Handshake structure. The client-facing server computes ClientHelloInner by reversing this process.  It scans EncodedClientHelloInner for an "outer_extensions" extension.  If there is none, the ClientHelloInner is the EncodedClientHelloInner.  Otherwise, it replaces the extension with the corresponding sequence of extensions in the ClientHelloOuter.  If any referenced extensions are missing, the server MUST abort the connection with an "illegal_parameter" alert.  The server then computes the digest of the reconstructed ClientHelloInner.  If the digest does not equal OuterExtensions.inner_digest, then the server MUST abort the connection with a "decrypt_error" alert. The "outer_extensions" extension is only used for compressing the ClientHelloInner.  It MUST NOT be sent in either ClientHelloOuter or ClientHelloInner. </ins> 6.

Discussion:
Along the way, I've made two additional tweaks: Renamed outerextension to outerextensions, now that it contains multiple extensions. One of the diagrams even already referred to "outerextensions" because I didn't realize it was called "outerextension".Clarified in compression process and ClientHelloInner construction rules that the to-be-compressed extensions must be consecutive. Hopefully that helps with .
NAME FYI. I'm hoping this will help clarify why the ordering thing isn't actually a big deal.
I've updated the PR to include text to disambiguate the serialization. It's ambiguous whether the encoding includes the 4-byte (12-byte in DTLS) header from the Handshake structure or is just the body, from the ClientHello structure. I've picked the smaller one. This also saves having to answer, in DTLS, what happens when the inner sequence number is wrong.
There are two ClientHelloInners, the actual one used in the handshake, and the encoded one with outerextensions substituted in. Both are described as ClientHelloInner, but this makes it slightly ambiguous which goes into, say, the handshake transcript. (It's late now, so I'll leave this as an issue without a PR. If we don't end up resolving this separately, I'll probably fix this as part of . If we decide to implicitly copy over legacysession_id, the encryption payload becomes less and less defensibly an actual ClientHelloInner.)
In my own implementation, I've been referring to the plaintext payload as CompressedClientHelloInner. Which is terrible, but unambiguous.
Works for me. I was thinking EncodedClientHelloInner because it's shorter and still works even if you choose not to compress anything. (A no-op encoding is still an encoding.)
+1 to EncodedClientHelloInner, given that compression is optional. NAME if you have time, could you whip up a PR?