Original text:
While input_string is not empty: If the first character of input_string is not one of lcalpha, <del> DIGIT, "*", "_", or "-", return output_string. </del>  Let char be the result of removing the first character of input_string.

Reviewer comments:
Allow "." in . Also consistently reorders character lists for key.
I'm getting a high failure rate on parsing (but with a very low number of occurrences; it's not exactly a popular header). The failure seems to occur because of keys like this: Allowing in key would address this, but I'm not sure it's worth the change. Additionally, key currently only allows lowercase alpha; this is mainly to avoid confusion between and , etc. So far this seems to be pretty supportable in cache-control, accept- and elsewhere, with the vast majority of headers seeming to choose the lowercase form. However, it does cause issues in a couple of cases: In , the parameter isn't compatible, leading to a high failure rate for that header In cookies, this makes a number of things incompatible, but it's not clear that we can treat them as a direct mapping anyway.
I have no opinion about dots. As to case, though; I think the options are: say lower-case only – the current option we should probably instruct individual headers' specifications to define how to get into/out of SH, which is harder for extant specs open it up to anycase and be case-sensitive this means that parses to and if someone wants to collapse / they have to do it after the fact open it up to anycase and be case-insensitive still requires instructions for individual headers' specs to define how to get out of SH Incidentally we don't say anything about case for tokens, not that it matters as far as SH is concerned (we never have to compare them.) It might not hurt to say something to the effect that "tokens are case-sensitive so you aren't allowed to change them, but an individual specification that uses sh-token may have special rules for comparing tokens that only differ in case".
WRT lower-case -- I think your analysis is correct; my inclination is to either stay lc only, or to force to LC when parsing textual headers (much like H2 does for field names). WRT instructions for existing headers -- that's out of scope for SH "officially."
Your patch for looks good. Force-lowercasing makes me a bit nervous, because the wire form for h1 will be materially different than what appears in the data model. We'll have to be careful to distinguish between the h1 wire format and the abstract model for keys (which we currently are pretty sloppy about). More seriously, even if we did force-lc, I realise it wouldn't be possible to round-trip things like includeSubDomains, so it probably isn't going to be useful on its own; there will always need to be some application knowledge / mapping. So, I'm inclined to leave casing in keys as-is.
I don't know what you mean by "force-lowercasing". Is that different from leaving it as-is?
i.e., forcing LC when parsing textual headers, as per above.
Oh, do you mean converting "FooBar" to "foobar" as part of some algorithm? Right, yeah, no, I don't like the idea of coercing data into the model if it can't be round-tripped back out. If an individual header field's spec supports a different data model (e.g. strings), then it's up to that header field's spec to define how to convert their string to an sh-key, and back again. I.e. don't do anything in SH, and punt it to RFC6797bis (or draft-mnot-bsh).
Agreed. Could you make the change into a PR?
It is.

Revised text:
While input_string is not empty: If the first character of input_string is not one of lcalpha,  <ins> DIGIT, "_", "-", ".", or "*", return output_string. </ins> Let char be the result of removing the first character of input_string.