-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Editorial: Reduce Annex B's monkey-patching #2952
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Note that, in the rendered spec's CSS, the I was thinking of dropping the Anyhow, I stress that the build preview is not the final rendering; that will require some changes to ecmarkup. |
We discussed this at editor call and decided this should be run by committee first so we can hear any objections. We still maintain that these changes are within editorial discretion, though. Also, we will need to change the wording of the "feature tests" to make sure we aren't changing or obfuscating the web browser requirement. |
I gather that the problem is that the wording "If the host supports [feature]" might be misread to give the host the freedom to support [feature] or not, whereas only non-browsers have that option (browsers must support it). And even though the start of Annex B makes that clear, and "[feature]" is a link to the feature description within Annex B, that might not be enough. So one possibility would be to change the wording to something like "If the host is a web browser or the host supports [feature]". Another might be to make the phrase "the host supports" be a link to the start of Annex B, and possibly make that a better landing site for that link. |
@jmdyck Correct, and yes those are some reasonable alternative strategies. Would you like the editors to discuss it more and give you a specific recommendation for the wording, or do you want to come up with something first? |
Hm, not much left for me to come up with, other than elaborating on a "better landing site". Could be something like:
|
I now realize that the 'normative-optional' attribute isn't right for these cases, so it should probably be something new, e.g. 'annex-b'. Let me know what you'd like. |
For the inline note, how about:
with a manual link to the "landing site" in annex B. And then the "landing site" wording you suggest as above is fine, except I'd tweak the last couple sentences as in
We're also fine with calling these normative-optional even though the "optional" part is not technically true for browsers. |
I've done this, but I'm somewhat dissatisfied with the results. In particular, in some cases (in FunctionDeclarationInstantiation,
and
I'm not saying it's an
Instead of a manual link, I added
Although now we never use that phrase. But people can (in the rendered spec) hover the term and get all the references, so not a problem, I guess.
I'm not fine with it, though. Calling them normative-optional would imply a change in normative status, and I want to be clear that this PR doesn't do that. |
(force-pushed to get the updated |
Now that I can see the rendered version, this bothers me less. |
Let's just tweak the definition of "normative optional" to add "unless otherwise indicated", then, as in
|
We discussed this in plenary today, and while one delegate was not comfortable with it (specifically the function-in-block part) everyone else who expressed an opinion was strongly in favor, so we're going to go forward with it. Editors will still need to review for wording and so on, of course. |
(force-pushed to resolve merge-conflicts from PR #2877) |
Reminder: This PR is 'based' on PR #2951, so that PR should be resolved first. (2951 moves one of the insertion-points for Annex B stuff, so that's easier to do before inlining than after.) |
What do you think about this rendering, but with the "ANNEX B" title linking to https://tc39.es/ecma262/#sec-additional-ecmascript-features-for-web-browsers? |
I'm not a fan of "unless otherwise indicated", but I'm not finding alternative wording that fits the context, so will add this. And if the inlined bits of Annex B are going to be labelled normative-optional, I imagine that should apply to the whole of Annex B too. (I.e., change its |
It won’t necessarily apply to everything, some things may end up being required. |
spec.html
Outdated
1. Let _lexEnv_ be _varEnv_. | ||
1. Else, | ||
1. [id="step-functiondeclarationinstantiation-web-compat-insertion-point", normative-optional] If the host is a web browser or otherwise supports <emu-xref href="#sec-block-level-function-declarations-web-legacy-compatibility-semantics" title></emu-xref>, then | ||
1. For each |FunctionDeclaration| _f_ that is directly contained in the |StatementList| of a |Block|, |CaseClause|, or |DefaultClause|, do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this somehow restrict scope? Otherwise it's unclear what is meant by "a |Block|, |CaseClause|, or |DefaultClause|".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Without any qualification, it seems like "a |Block|, |CaseClause|, or |DefaultClause|" could refer to any such Parse Node that the implementation is aware of, which seems too broad.
Originally (in ES6), it was scoped via "For each |FunctionDeclaration| f in varDeclarations ...", but then that was removed in commit efbfc88, which doesn't appear to be connected to a PR, but claims to fix old bug 4427. However, if you look at that bug report's suggested fix, in addition to removing "in varDeclarations", it also says to append "Contained within code", and that part didn't happen in the commit.
For discussion that prompted the bug report, see esdiscuss.
Anyhow, that's a preexisting problem, so not the main point of this PR, but I could tack on a commit if the editors want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On second thought, I figured it deserved its own PR: #3361.
spec.html
Outdated
<li> | ||
It is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries. | ||
It is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries<span normative-optional>, unless IsStrict(this production) is *false*, the duplicate entries are only bound by FunctionDeclarations, and the host is a web browser or otherwise supports <emu-xref href="#sec-block-level-function-declarations-web-legacy-compatibility-semantics" title></emu-xref></span>. | ||
</li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This renders poorly, and in particular misses the "normative optional" text: https://ci.tc39.es/preview/tc39/ecma262/sha/06e2af4a47bd749e5cbb0fb0c737221e86685a85/multipage/ecmascript-language-statements-and-declarations.html#sec-block-static-semantics-early-errors
I wonder if moving the attribute up a level would improve things.
<li> | |
It is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries. | |
It is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries<span normative-optional>, unless IsStrict(this production) is *false*, the duplicate entries are only bound by FunctionDeclarations, and the host is a web browser or otherwise supports <emu-xref href="#sec-block-level-function-declarations-web-legacy-compatibility-semantics" title></emu-xref></span>. | |
</li> | |
<li> | |
<div>It is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries.</div> | |
<div normative-optional>If the host is a web browser or otherwise supports <emu-xref href="#sec-block-level-function-declarations-web-legacy-compatibility-semantics" title></emu-xref>, the above Syntax Error does not apply when IsStrict(this production) is *false* and the duplicate entries are only bound by FunctionDeclarations.</div> | |
</li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This renders poorly, and in particular misses the "normative optional" text:
I agree that it renders poorly, but I'm not sure what you mean by "misses". The normative optional text is there, but the bottom of each line is slightly obscured/clipped by the padding of the line below.
ecmarkup.css probably needs a new rule for when normative-optional
occurs on inline content. (Currently, that attribute is only attached to block content, specifically emu-clause
elements.) E.g., if you reduce the padding from 0.5em to 0.2em, the clipping goes away. (Also, the border-left line maybe doesn't make sense for inline content.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it renders poorly, but I'm not sure what you mean by "misses". The normative optional text is there, but the bottom of each line is slightly obscured/clipped by the padding of the line below.
I mean that the literal text "NORMATIVE OPTIONAL" is absent, but Conformance indicates that it should be present:
A Normative Optional clause is denoted in this specification with the words "Normative Optional" in a coloured box, as shown below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean that the literal text "NORMATIVE OPTIONAL" is absent
Ahh, gotcha.
spec.html
Outdated
<li> | ||
It is a Syntax Error if the LexicallyDeclaredNames of |CaseBlock| contains any duplicate entries. | ||
It is a Syntax Error if the LexicallyDeclaredNames of |CaseBlock| contains any duplicate entries<span normative-optional>, unless IsStrict(this production) is *false*, the duplicate entries are only bound by FunctionDeclarations, and the host is a web browser or otherwise supports <emu-xref href="#sec-block-level-function-declarations-web-legacy-compatibility-semantics" title></emu-xref></span>. | ||
</li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise here (<li><p>It is a Syntax Error if…</p><p normative-optional>If the host is a web browser or otherwise supports…</p></li>
).
spec.html
Outdated
@@ -22723,12 +22739,9 @@ <h1>Static Semantics: Early Errors</h1> | |||
<emu-grammar>LabelledItem : FunctionDeclaration</emu-grammar> | |||
<ul> | |||
<li> | |||
It is a Syntax Error if any source text is matched by this production. | |||
It is a Syntax Error if any source text is matched by this production<span normative-optional>, unless that source text is non-strict code and the host is a web browser or otherwise supports <emu-xref href="#sec-labelled-function-declarations" title></emu-xref></span>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here (etc.).
…tantiation This PR completes a small bugfix from 9 years ago. Fixes tc39#2663. ---- History: 2015-07-17: @bakkot identifies a problem in Annex B's "Changes to FunctionDeclarationInstantiation": https://esdiscuss.org/topic/block-level-function-declarations-web-legacy-compatibility-bug To remedy this, @allenwb submits bug 4427: https://tc39.es/archives/bugzilla/4427/ in which he recommends changing > For each FunctionDeclaration _f_ **in _varDeclarations_** that is directly contained in the |StatementList| of a |Block|, |CaseClause|, or |DefaultClause|, to > For each FunctionDeclaration _f_ that is directly contained in the |StatementList| of a |Block|, |CaseClause|, or |DefaultClause| **Contained within _code_**, (emphasis mine). 2015-10-29: @anba submits PR tc39#141, claiming to fix bug 4427. It deletes "in _varDeclarations_", but doesn't add "Contained within _code_". My guess is, this was just an oversight. 2015-11-02: PR tc39#141 is merged to master as commit efbfc88. 2022-02-13: @nicolo-ribaudo raises issue tc39#2663 about this, and says he'd open a PR to fix it, but I don't think that happened. 2024-06-26: @gibson042 raises the problem again, in a commment on PR tc39#2952: tc39#2952 (comment)
…tantiation This PR completes a small bugfix from 9 years ago. Fixes tc39#2663. ---- History: 2015-07-17: @bakkot identifies a problem in Annex B's "Changes to FunctionDeclarationInstantiation": https://esdiscuss.org/topic/block-level-function-declarations-web-legacy-compatibility-bug To remedy this, @allenwb submits bug 4427: https://tc39.es/archives/bugzilla/4427/ in which he recommends changing > For each FunctionDeclaration _f_ **in _varDeclarations_** that is directly contained in the |StatementList| of a |Block|, |CaseClause|, or |DefaultClause|, to > For each FunctionDeclaration _f_ that is directly contained in the |StatementList| of a |Block|, |CaseClause|, or |DefaultClause| **Contained within _code_**, (emphasis mine). 2015-10-29: @anba submits PR tc39#141, claiming to fix bug 4427. It deletes "in _varDeclarations_", but doesn't add "Contained within _code_". My guess is, this was just an oversight. 2015-11-02: PR tc39#141 is merged to master as commit efbfc88. 2022-02-13: @nicolo-ribaudo raises issue tc39#2663 about this, and says he'd open a PR to fix it, but I don't think that happened. 2024-06-26: @gibson042 raises the problem again, in a commment on PR tc39#2952: tc39#2952 (comment)
…tantiation (tc39#3361) This PR completes a small bugfix from 9 years ago. Fixes tc39#2663. ---- History: 2015-07-17: @bakkot identifies a problem in Annex B's "Changes to FunctionDeclarationInstantiation": https://esdiscuss.org/topic/block-level-function-declarations-web-legacy-compatibility-bug To remedy this, @allenwb submits bug 4427: https://tc39.es/archives/bugzilla/4427/ in which he recommends changing > For each FunctionDeclaration _f_ **in _varDeclarations_** that is directly contained in the |StatementList| of a |Block|, |CaseClause|, or |DefaultClause|, to > For each FunctionDeclaration _f_ that is directly contained in the |StatementList| of a |Block|, |CaseClause|, or |DefaultClause| **Contained within _code_**, (emphasis mine). 2015-10-29: @anba submits PR tc39#141, claiming to fix bug 4427. It deletes "in _varDeclarations_", but doesn't add "Contained within _code_". My guess is, this was just an oversight. 2015-11-02: PR tc39#141 is merged to master as commit efbfc88. 2022-02-13: @nicolo-ribaudo raises issue tc39#2663 about this, and says he'd open a PR to fix it, but I don't think that happened. 2024-06-26: @gibson042 raises the problem again, in a commment on PR tc39#2952: tc39#2952 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally lgtm, some questions about wording.
spec.html
Outdated
<h1>Static Semantics: Early Errors</h1> | ||
<emu-grammar>Block : `{` StatementList `}`</emu-grammar> | ||
<ul> | ||
<li> | ||
It is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries. | ||
It is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries<span normative-optional>, unless IsStrict(this production) is *false*, the duplicate entries are only bound by FunctionDeclarations, and the host is a web browser or otherwise supports <emu-xref href="#sec-block-level-function-declarations-web-legacy-compatibility-semantics" title></emu-xref></span>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the "unless" too long now and hard to parse. WDYT splitting this, and all Syntax Error sentences, into:
If the host is not a web browser and does not otherwise supports <blah>, it is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries.
If the host is a web browser or otherwise supports <blah>, it is a SyntaxError if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries, unless IsStrict(this production) is *false*, the duplicate entries are only bound by FunctionDeclarations.
Thoughts @bakkot @michaelficarra?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the second constraint you have there is mis-worded? Not sure what it's meant to say, but I think I get the idea and that would be fine by me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I think I see your confusion. The structure I intended was:
- If the host does support this particular normative optional feature, (it is a Syntax Error if reasons, unless these other reasons).
Is your confusion that it can also be parsed as the following?
- (If the host does support this particular normative optional feature, it is a Syntax Error if reasons), unless these other reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I dunno then, I don't see a good way to split it up otherwise. It's hard to actually move the entire unless to the front as an if because the unless has an anaphora ("the duplicate entries").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then leave it as-is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re the "unless" being too long and hard to parse, we could introduce a <ul>
. Something like:
It is a Syntax Error if (duplicates), unless:
- IsStrict(this production) is *false*,
- the duplicate entries are only bound by FunctionDeclarations, and
- the host is a web browser or otherwise supports (link).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A ul
wfm.
Please have it say either "unless all the following are true", or have a trailing ", and" on every non-final bullet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I've added a fixup commit to introduce a <ul>
into this rule and also a similar one further down.
There are some others that only have a 2-term conjunction; I'm assuming they're okay.
Please have it say either "unless all the following are true", or have a trailing ", and" on every non-final bullet.
The spec doesn't have a lot of precedent for lists of conditions, but it seems to prefer (something like) the former, so that's what I did.
I put the normative-optional
attribute only on the <ul>
, even though technically, the normative-optional part starts before the "unless". Does anyone care?
Also, it occurred to me that ecmarkdown has its own way to signal a bulleted list (using *
), but I don't think there's a way to mark such a list as normative-optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
The Evaluation semantics for FunctionDeclaration is accompanied by a Note that says "An alternative semantics is provided in B.3.2." However, B.3.2 is a fairly large section, and the alternative Evaluation semantics might be difficult to spot. So this commit expands that Note by adding links to the specific steps that give the alternative Evaluation semantics for FunctionDeclaration.
Specifically, tack on "unless otherwise indicated". (This will allow Annex B features to be labelled normative-optional.)
…ions" Also add a defn for "the host supports".
<h1>Static Semantics: Early Errors</h1> | ||
<emu-grammar>Block : `{` StatementList `}`</emu-grammar> | ||
<ul> | ||
<li> | ||
It is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries. | ||
<p>It is a Syntax Error if the LexicallyDeclaredNames of |StatementList| contains any duplicate entries, unless all of the following conditions are true:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not totally clear how you're supposed to interpret "[...] unless all of the following conditions are true" followed by a list marked normative-optional. The naive reading is that if you are choosing not to implement the normative optional behavior then the entire list is considered to be elided, in which case "all of the conditions" is vacuously true, which is not what we want.
Possibly something like "[...] unless the host is a web browser or otherwise supports #block-level-function-declarations-web-legacy-compatibility-semantics, and both of the following conditions are true:"? That's also more consistent with the pattern elsewhere, where the "is a browser" condition is the first guard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly something like "[...] unless the host is a web browser or otherwise supports #blah, and both of the following conditions are true:"?
Added a fixup to make this change.
Everywhere else, the phrase "the host is a web browser or otherwise supports blah is within the scope of a normative-optional
, so I put the "unless ... are true:" part in a <span normative-optional>
in addition to the <ul>
being tagged as normative-optional
. But I have no idea how that looks when rendered.
That's also more consistent with the pattern elsewhere, where the "is a browser" condition is the first guard.
There are 3 other places where I didn't make it the first guard:
- line 23091 under
LabelledItem : FunctionDeclaration
- line 23241 under
Catch : `catch` `(` CatchParameter `)` Block
- line 30038 in
EvalDeclarationInstantiation
So you might want to confirm that you're okay with those.
<h1>Static Semantics: Early Errors</h1> | ||
<emu-grammar>SwitchStatement : `switch` `(` Expression `)` CaseBlock</emu-grammar> | ||
<ul> | ||
<li> | ||
It is a Syntax Error if the LexicallyDeclaredNames of |CaseBlock| contains any duplicate entries. | ||
<p>It is a Syntax Error if the LexicallyDeclaredNames of |CaseBlock| contains any duplicate entries, unless all of the following conditions are true:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto above.
@@ -23791,7 +23811,7 @@ <h1>Runtime Semantics: Evaluation</h1> | |||
1. Return ~empty~. | |||
</emu-alg> | |||
<emu-note> | |||
<p>An alternative semantics is provided in <emu-xref href="#sec-block-level-function-declarations-web-legacy-compatibility-semantics"></emu-xref>.</p> | |||
<p>An alternative semantics is provided by <emu-xref href="#sec-block-level-function-declarations-web-legacy-compatibility-semantics" title></emu-xref> at step <emu-xref href="#step-functiondeclarationinstantiation-alt-funcdecl-eval"></emu-xref> of FunctionDeclarationInstantiation, step <emu-xref href="#step-globaldeclarationinstantiation-alt-funcdecl-eval"></emu-xref> of GlobalDeclarationInstantiation, and step <emu-xref href="#step-evaldeclarationinstantiation-alt-funcdecl-eval"></emu-xref> of EvalDeclarationInstantiation.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine for now but I'd like to find some way to inline these as well in a followup. Having a runtime algorithm step say "and then when you perform this other step, do this other thing" is crazy.
spec.html
Outdated
@@ -51929,6 +51994,8 @@ <h1>Regular Expressions</h1> | |||
<emu-annex id="sec-additional-ecmascript-features-for-web-browsers" namespace="annexB" normative> | |||
<h1>Additional ECMAScript Features for Web Browsers</h1> | |||
<p>The ECMAScript language syntax and semantics defined in this annex are required when the ECMAScript host is a web browser. The content of this annex is normative but optional if the ECMAScript host is not a web browser.</p> | |||
<p>Some features defined in this annex are specified in this annex, and some are specified in the main body of this document.</p> | |||
<p>When a feature is specified in the main body, each point where it affects the document is marked with the words "Normative Optional" in a coloured box. Moreover, where the feature involves particular wording in an algorithm or early error rule, this is guarded by the condition that “<dfn variants="otherwise supports">the host supports</dfn>” the relevant feature. Web browsers are required to support all such features.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it the case that web browsers are required to support all normative optional features? (I think yes?) If so, we should say so in the definition of "normative optional", not here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That may be true today, but I don't know if we want it to always be true. If it's ever not true, we run the risk of forgetting to update that text. I think the mention here is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to optimize for clarity of the existing document over guarding against future editorial mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is conceptually more appropriate here as well. I don't want anyone learning "normative optional" means "available in web browsers" when that may not be true in the future, even if it is editorially corrected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concern is that I don't want people to have to find this sentence in the annex in order to know that these features are in fact required. The fact that it's currently easy to miss that Annex B imposes additional requirements on web browsers (and therefore any engine which wants to run code written for web browsers) is the whole reason we're doing this in the first place.
I really don't think we should be worrying about being defensive against a future world where we have additional normative optional features which are optional for browsers.
See Issue #1595 for some background. However, that talks about making many Annex B things normative, which this PR doesn't do. This PR takes pseudocode-replacements from Annex B and splices them into the corresponding points in the main body, while maintaining their normative-optional status.
This PR doesn't eliminate all Annex B monkey-patching, because I'm avoiding Annex B features that modify the grammar (due to controversy), i.e.:
(It's unclear why the latter two aren't included in B.1, since they define additional syntax.)
That leaves:
This PR has one commit for each of those sections, plus an extra one at the start to make B.3.2 easier (which might be useful to cherry-pick, even if this PR goes nowhere). This PR is also 'based' on PR #2951, so that'll show up as a commit here until it's merged.
Here's roughly the scheme I followed when eliminating a monkey-patch of an abstract operation. (There are also early error rules that get patched, but the edits are analogous, and simpler.)
Where the status quo has:
this PR changes that to:
(In some cases, "Do the mainline thing" is empty, which simplifies things.)
Note that the above format of the "host supports" step is a compromise to get the current ecmarkup to accept and render it. What I had in mind instead was something more like:
ecmarkup could then recognize the "normative-optional" step-attribute and apply appropriate styling for that step and all its substeps.