diff --git a/source/2026-07-july/d4133-proposal-requirements.md b/source/2026-07-july/d4133-proposal-requirements.md
index 9f3c003..e68ead9 100644
--- a/source/2026-07-july/d4133-proposal-requirements.md
+++ b/source/2026-07-july/d4133-proposal-requirements.md
@@ -10,7 +10,7 @@ reply-to:
## Abstract
-The committee has never established a criteria for what belongs in the standard library; this paper supplies one.
+The committee has never established a criterion for what belongs in the standard library. This paper supplies one.
Each pre-meeting mailing now carries more than one hundred proposals, a volume the committee's own direction papers describe as unmanageable for any individual reader. Review capacity has not grown to match, and the release schedule is fixed, so the quantity that absorbs the growth is the review each paper receives. This paper describes a gate: a threshold evaluation, held before a proposal consumes review time, that asks whether the component belongs in the standard at all. For library components the paper supplies the gate's instruments - eight measurable quantities calibrated against the published record of past admissions. For language features the paper states the gate question and marks the space for delegates with compiler and teaching expertise to supply the instruments.
@@ -32,11 +32,11 @@ The author developed and maintains [Corosio](https://github.com/cppalliance/coro
This paper places an admission model and its supporting evidence in the record. It is input to the criteria discussion that [P2000R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2000r4.pdf)[3] encouraged.
-The author's stake extends to the model itself: the library instruments in Section 5 treat networking favorably, and the author maintains networking libraries. Section 5.7 prices the model's costs against networking with the same instruments it applies everywhere else. The model's arithmetic is the author's; the record it is calibrated against is the committee's own.
+The author's stake extends to the model itself: the library instruments in Section 5 treat networking favorably, and the author maintains networking libraries. Section 5.7 prices the model's costs against networking with the same instruments it applies everywhere else. The model's arithmetic is the author's. The record it is calibrated against is the committee's own.
-One limitation is structural. The value model in Section 5 was written by a party to disputes it would judge. A reader who rejects the model loses none of the underlying findings: the criteria vacuum in Section 5.4, the budget pricing in Section 5.5, and the penalty record in Section 5.6 are documented from published committee papers, vendor records, and public minutes, and they stand without the model.
+One limitation is structural. In Section 5, the value model was written by a party to disputes it would judge. A reader who rejects the model loses none of the underlying findings: the criteria vacuum in Section 5.4, the budget pricing in Section 5.5, and the penalty record in Section 5.6 are documented from published committee papers, vendor records, and public minutes, and they stand without the model.
-The method is documentary: every claim is sourced to published papers, public minutes, vendor documentation, or public mailing lists, and every quotation was verified against its source. Generative AI assisted with research and drafting; the author verified the quotations and takes responsibility for every claim.
+The method is documentary: every claim is sourced to published papers, public minutes, vendor documentation, or public mailing lists, and every quotation was verified against its source. Generative AI assisted with research and drafting. The author verified the quotations and takes responsibility for every claim.
This paper asks for nothing.
@@ -53,61 +53,61 @@ This paper contributes four things:
3. The library instruments for the gate (Section 5), each grounded in the published admission record, with the evidence bar a passing paper must then meet (Section 7).
4. A stated gap where the language instruments belong, marked for delegates with compiler and teaching expertise (Section 6).
-The paper assumes the reader accepts the committee's own throughput accounting as accurate; every figure in Section 3 is drawn from numbered committee documents.
+The paper assumes the reader accepts the committee's own throughput accounting as accurate. Every figure in Section 3 is drawn from numbered committee documents.
---
## 3. The Mailing Outgrew the Review
-This section establishes the problem the gate addresses, in four steps: proposal volume rose, review capacity did not, the release schedule is fixed, and therefore the review each paper receives is the quantity that gives way. Sections 3.1 through 3.4 document each step from the committee's own records.
+In four steps, this section establishes the problem the gate addresses: proposal volume rose, review capacity did not, the release schedule is fixed, and therefore the review each paper receives is the quantity that gives way. Sections 3.1 through 3.4 document each step from the committee's own records.
### 3.1 Volume Rose
-The Direction Group described the inflow in 2020: "One effect of this enthusiasm for C++ is to inundate us with a flood of proposals. The sheer volume of proposals leads to fewer proposals getting through the processes to get accepted. Some proposals drift from the author's original design from the need to gain support in an environment where time to think and present ideas is limited" ([P2000R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2000r2.pdf)[10]). The same group had already quantified the load in [P0939R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0939r3.pdf)[11], Section 7.2: "WG21 does not lack for proposals. The interest is high and the number of proposals of each mailing has grown to more than 100. That's unmanageable for an individual with a day job." [P2000R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2000r3.pdf)[12] adds the traffic figure: "The WG21 mailing lists alone produce in total between 1,000 and 3,000 messages a month, which is a large volume of traffic to keep on top of."
+In 2020, the Direction Group described the inflow: "One effect of this enthusiasm for C++ is to inundate us with a flood of proposals. The sheer volume of proposals leads to fewer proposals getting through the processes to get accepted. Some proposals drift from the author's original design from the need to gain support in an environment where time to think and present ideas is limited" ([P2000R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2000r2.pdf)[10]). The same group had already quantified the load in [P0939R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0939r3.pdf)[11], Section 7.2: "WG21 does not lack for proposals. The interest is high and the number of proposals of each mailing has grown to more than 100. That's unmanageable for an individual with a day job." [P2000R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2000r3.pdf)[12] adds the traffic figure: "The WG21 mailing lists alone produce in total between 1,000 and 3,000 messages a month, which is a large volume of traffic to keep on top of."
-The volume has not receded since those papers were written. The admin group reported in [N5005](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/n5005.pdf)[13] (January 2025): "The post-Wrocław mailing had 167 papers, 107 of which were P-papers not counting multiple revisions, withdrawn papers, or papers adopted in Wrocław."
+Since those papers were written, the volume has not receded. In [N5005](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/n5005.pdf)[13] (January 2025), the admin group reported: "The post-Wrocław mailing had 167 papers, 107 of which were P-papers not counting multiple revisions, withdrawn papers, or papers adopted in Wrocław."
-The historical scale of the inflow is on record. Herb Sutter's [pre-meeting trip report for San Diego 2018](https://herbsutter.com/2018/11/05/pre-trip-report-fall-iso-c-standards-meeting-san-diego/)[14] counted 274 papers in one mailing, against a corpus of 1,148 papers for the entire eight-year C++98 cycle, and his [post-meeting trip report](https://herbsutter.com/2018/11/13/trip-report-fall-iso-c-standards-meeting-san-diego/)[15] observed that the mailing "started to approach the total number of technical papers to produce the first C++ standard (total of pre-meeting mailings from 1990-1997)". Counted from the public open-std.org paper indexes for [2019](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/)[16] and [2024](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/)[17], the years 2019 and 2024 each produced more than 900 paper documents (617 and 560 unique papers respectively): each of those single years approaches the paper output of the entire eight-year C++98 cycle.
+For scale, Herb Sutter's [pre-meeting trip report for San Diego 2018](https://herbsutter.com/2018/11/05/pre-trip-report-fall-iso-c-standards-meeting-san-diego/)[14] counted 274 papers in one mailing, against a corpus of 1,148 papers for the entire eight-year C++98 cycle, and his [post-meeting trip report](https://herbsutter.com/2018/11/13/trip-report-fall-iso-c-standards-meeting-san-diego/)[15] observed that the mailing "started to approach the total number of technical papers to produce the first C++ standard (total of pre-meeting mailings from 1990-1997)". Counted from the public open-std.org paper indexes for [2019](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/)[16] and [2024](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/)[17], the years 2019 and 2024 each produced more than 900 paper documents (617 and 560 unique papers respectively): each of those single years approaches the paper output of the entire eight-year C++98 cycle.
### 3.2 Capacity Did Not
-The convener described the bottleneck to the San Diego 2018 plenary, as recorded in [P1338R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1338r1.pdf)[18]: "There are 181 people at this meeting. We have grown a lot and the number of papers has grown a lot too. We used to have less papers than people, but that is no longer the case. We still want to look at all of the papers ... To be able to see all the papers, we have scaled the groups and added incubation groups at the meeting. We are still bottlenecked at LWG and CWG which need to do the final review of the papers."
+As recorded in [P1338R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1338r1.pdf)[18], the convener described the bottleneck to the San Diego 2018 plenary: "There are 181 people at this meeting. We have grown a lot and the number of papers has grown a lot too. We used to have less papers than people, but that is no longer the case. We still want to look at all of the papers ... To be able to see all the papers, we have scaled the groups and added incubation groups at the meeting. We are still bottlenecked at LWG and CWG which need to do the final review of the papers."
Two years later, the chairs of both library groups gave the same answer to the same question. The pre-autumn 2020 telecon minutes, [N4871](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4871.pdf)[19], record the exchange. Asked whether to look into expanding the throughput or managing expectations, the Library Working Group (LWG) chair answered: "I'm not sure what we can do to expand the throughput. We should probably start managing expectations." The Library Evolution Working Group (LEWG) chair answered in the same discussion: "It's hard to improve throughput, we should start managing expectations."
-The throughput numbers behind those answers are published. LEWG's own accounting in [P2400R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2400r2.html)[20] records, in its cumulative tally running from April 2020, 74 telecons and 107 papers reviewed in roughly seventeen months, against a standing backlog of 41 active papers, at a cadence of one or two papers per ninety-minute telecon. The people doing that review were polled during the same period: the November 2020 plenary record, [P2260R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2260r0.pdf)[21], reports that over 60 percent of participants said they often feel exhausted by meetings and demands from all sources, and 46 percent said the pace was not sustainable. The N4871 exchange and these poll figures are pandemic-era records and are read here as corroboration, not as steady state. The steady-state capacity evidence brackets them: the convener's bottleneck statement is from 2018, and the 2022 removal of `submdspan` for LWG scheduling reasons (Section 3.4) shows the same constraint operating after meetings resumed.
+The throughput numbers behind those answers are published. LEWG's own accounting in [P2400R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2400r2.html)[20] records, in its cumulative tally running from April 2020, 74 telecons and 107 papers reviewed in roughly seventeen months, against a standing backlog of 41 active papers, at a cadence of one or two papers per ninety-minute telecon. During the same period, the people doing that review were polled: the November 2020 plenary record, [P2260R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2260r0.pdf)[21], reports that over 60 percent of participants said they often feel exhausted by meetings and demands from all sources, and 46 percent said the pace was not sustainable. The N4871 exchange and these poll figures are pandemic-era records and are read here only as corroboration. The steady-state capacity evidence brackets them: the convener's bottleneck statement is from 2018, and the 2022 removal of `submdspan` for LWG scheduling reasons (Section 3.4) shows the same constraint operating after meetings resumed.
### 3.3 The Ship Date Does Not Move
-The release schedule absorbs none of the growth. [P1000R6](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p1000r6.pdf)[22] fixes the three-year cadence, and the cadence has held through C++26. The train model's stated protection - features are pulled when not ready - operates asymmetrically in practice: [P4131R0](https://isocpp.org/files/papers/D4131R0.pdf)[9] documents, release by release from C++14 through C++26, that features are pushed when almost ready rather than pulled when not ready.
+The release schedule absorbs none of the growth. [P1000R6](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p1000r6.pdf)[22] fixes the three-year cadence, and the cadence has held through C++26. In practice, the train model's stated protection - features are pulled when not ready - operates asymmetrically: [P4131R0](https://isocpp.org/files/papers/D4131R0.pdf)[9] documents, release by release from C++14 through C++26, that features are pushed when almost ready rather than pulled when not ready.
### 3.4 Review per Paper Is the Quantity That Collapses
When volume rises, capacity holds, and the deadline is fixed, the quantity that gives way is the review each paper receives. The record shows this directly.
-[P3443R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3443r0.pdf)[23] measured one study group's 2024 docket: 63 papers discussed in 10 months, and of the 41 papers that received binding polls, 56.10 percent were published less than one week before they were discussed and polled. The paper states the experience from inside the room: "During the last year the authors of this paper felt that the process of making P2900 is too fast. Papers are sneaking in at a high rate and are processed immediately as they arrive." (The quoted paper number is Contracts for C++; the study group is SG21, and its Contracts-deadline year was an intense one, which is why the figure is read here as one measured instance of the mechanism rather than a committee-wide average.)
+[P3443R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3443r0.pdf)[23] measured one study group's 2024 docket: 63 papers discussed in 10 months, and of the 41 papers that received binding polls, 56.10 percent were published less than one week before they were discussed and polled. From inside the room, the paper states the experience: "During the last year the authors of this paper felt that the process of making P2900 is too fast. Papers are sneaking in at a high rate and are processed immediately as they arrive." (The quoted paper number is Contracts for C++. The study group is SG21, and its Contracts-deadline year was an intense one, which is why the figure is read here as one measured instance of the mechanism rather than a committee-wide average.)
[P3023R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3023r1.html)[24] describes the attention side of the same collapse: "In committee, we frequently spend time on things that only a small number of people care about. It's difficult to say 'no' when someone, somewhere would benefit. There's also a tendency to mentally check-out during these discussions which results in proposals not getting an appropriate rigor."
Even proposals with the strongest provenance lose review time. [P2630R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2630r1.html)[25] records that `submdspan`, a function "considered critical for the overall functionality of mdspan", was removed from the mdspan proposal "due to review time constraints ... in order for mdspan to be included in C++23". The separation poll itself is recorded in the [LEWG telecon summary on the mdspan tracker](https://github.com/cplusplus/papers/issues/96)[26] as "made purely out of scheduling concerns to make sure that LWG is not overloaded."
-Together the four steps yield this section's finding. The standard does not ship late; it ships less-reviewed.
+Together the four steps yield this section's finding. The standard does not ship late. It ships less-reviewed.
---
## 4. The Gate Question
-When review per paper is the collapsing quantity, the highest-leverage intervention is the one that happens before review is spent. That intervention is a threshold question: does this component belong in the standard at all? This section describes a two-step model for asking it. Section 4.1 describes the calibration step, Section 4.2 the comparison step, and Section 4.3 the three verdicts the comparison renders.
+When review per paper is the collapsing quantity, the most effective intervention is the one that happens before review is spent. That intervention is a threshold question: does this component belong in the standard at all? This section describes a two-step model for asking it. Section 4.1 covers the calibration step, Section 4.2 the comparison step, and Section 4.3 the three verdicts the comparison renders.
-Library and language proposals face different forms of the question, because the ecosystem alternative exists for one and not the other. A library component can be downloaded; a language feature cannot. Section 5 develops the library gate in full. Section 6 states the language gate and leaves its instruments open.
+Library and language proposals face different forms of the question, because the ecosystem alternative exists for one and not the other. A library component can be downloaded. A language feature cannot. Section 5 develops the library gate in full. Section 6 states the language gate and leaves its instruments open.
### 4.1 The Pre-Flight Calibration
-Before a proposal's advocacy frames the discussion, the evaluating group confers and pools what the room knows about the domain. The output is not a verdict. It is a calibrated expectation: a rough, order-of-magnitude estimate of what standardizing the component ought to be worth, together with an inventory of who in the room can competently judge the claims. The estimate draws on observable ecosystem facts - whether multiple incompatible implementations of the same concept exist, whether the component crosses interface boundaries between independently authored libraries, and how fast the domain moves. Section 5.3 makes these three quantities precise. No proposal is rejected at this step.
+Before a proposal's advocacy frames the discussion, the evaluating group confers and pools what the room knows about the domain. The output is a calibrated expectation, never a verdict: a rough, order-of-magnitude estimate of what standardizing the component ought to be worth, together with an inventory of who in the room can competently judge the claims. The estimate draws on observable ecosystem facts - whether multiple incompatible implementations of the same concept exist, whether the component crosses interface boundaries between independently authored libraries, and how fast the domain moves. Section 5.3 makes these three quantities precise. No proposal is rejected at this step.
-The calibration serves two purposes. The first is anchoring control, and it is a design premise of the model rather than a sourced finding: a well-written proposal sets the frame for everything discussed after it, so when the room forms its expectation first, the paper must shift a formed estimate instead of supplying the first one. Whether a conferring room sharpens its estimates or entrenches them is an empirical question; the calibration records the model needs in order to be evaluated are the same records that would answer it.
+The calibration serves two purposes. Anchoring control is the first, and it is a design premise of the model rather than a sourced finding: a well-written proposal sets the frame for everything discussed after it, so when the room forms its expectation first, the paper must shift a formed estimate instead of supplying the first one. Whether a conferring room sharpens its estimates or entrenches them is an empirical question. And the records the calibration produces for evaluating the model are the same records that would answer it.
-The second purpose is the expertise inventory, and the published record shows why it must happen before discussion rather than during the poll. The October 2021 electronic poll on asynchronous models, published in [P2453R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2453r0.html)[27], asked whether the sender/receiver model is a good basis for most asynchronous use cases "including networking"; the poll achieved consensus while the published comments include "can't judge its suitability for networking" from a voter who voted Weakly Favor. [P4097R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4097r0.pdf)[7] documents the episode. A statement of non-expertise that surfaces inside the poll comments arrives too late to inform the poll. The calibration step collects it first, and "none of us knows this domain" is itself a recorded finding.
+The second purpose is the expertise inventory, and the published record shows why it must happen before discussion instead of during the poll. Published in [P2453R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2453r0.html)[27], the October 2021 electronic poll on asynchronous models asked whether the sender/receiver model is a good basis for most asynchronous use cases "including networking". The poll achieved consensus while the published comments include "can't judge its suitability for networking" from a voter who voted Weakly Favor. [P4097R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4097r0.pdf)[7] documents the episode. A statement of non-expertise that surfaces inside the poll comments arrives too late to inform the poll. The calibration step collects it first, and "none of us knows this domain" is itself a recorded finding.
### 4.2 The Comparison
@@ -127,23 +127,23 @@ flowchart TD
compare -->|"meets or exceeds the expectation"| admitNode["Admit to full review"]
```
-*Figure 1: The two-step gate. The pre-flight produces an expectation, never a verdict; the verdict comes from comparing the paper against the expectation.*
+*Figure 1: The two-step gate. The pre-flight produces an expectation, never a verdict. The verdict comes from comparing the paper against the expectation.*
-Reject means the component does not belong: even a generous reading of the evidence cannot meet the expectation the room formed, and no volume of paper can change that. The distinction matters because volume has substituted for evidence before. Counted from the public [wg21.link index](https://wg21.link/index.json)[28] by title match on executor, sender, receiver, scheduler, and `std::execution` (a floor, since papers without a matching title word are excluded), the executor lineage produced 115 distinct papers and 219 revision documents between its first paper in 2012 and mid-2026, including the fourteen revisions of [P0443R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0443r0.html)[29] - retired unadopted - and the replacement design that followed. A gate that renders a recorded verdict settles the belongs-question at paper one, on evidence; the verdict attaches to the component rather than to the persistence of its authors.
+Reject means the component does not belong: even a generous reading of the evidence cannot meet the expectation the room formed, and no volume of paper can change that. The distinction matters because volume has substituted for evidence before. Counted from the public [wg21.link index](https://wg21.link/index.json)[28] by title match on executor, sender, receiver, scheduler, and `std::execution` (a floor, since papers without a matching title word are excluded), the executor lineage produced 115 distinct papers and 219 revision documents between its first paper in 2012 and mid-2026. That count includes the fourteen revisions of [P0443R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0443r0.html)[29] - retired unadopted - and the replacement design that followed. A gate that renders a recorded verdict settles the belongs-question at paper one, on evidence, and attaches the verdict to the component rather than to the persistence of its authors.
Not ready means the expectation stands but this paper has not measured up to it: the component may merit standardization, and the paper is returned for the evidence the gate requires. The distinction between reject and not ready protects good components from weak papers, and denies weak components rescue by strong papers.
-Under the model, the room does openly what it already does implicitly. Every scheduling decision the committee makes today embeds an unrecorded judgment about whether the component belongs; the gate records the judgment, its inputs, and the expertise of the people who made it.
+Under the model, the room does openly what it already does implicitly. Every scheduling decision the committee makes today embeds an unrecorded judgment about whether the component belongs. The gate records the judgment, its inputs, and the expertise of the people who made it.
---
## 5. The Library Gate
-This section supplies the instruments the pre-flight calibration uses for library components, and the evidence that no such instruments have ever policed the door. Section 5.1 states the default. Section 5.2 defines the vocabulary. Section 5.3 states the value model. Sections 5.4 through 5.6 calibrate the model against the committee's own record: the criteria vacuum, the priced budget, and the penalty ledger. Section 5.7 identifies what clears the gate.
+This section supplies the instruments the pre-flight calibration uses for library components, and the evidence that no such instruments have ever policed the door. Section 5.1 states the default, and Section 5.2 defines the vocabulary. Section 5.3 states the value model. Sections 5.4 through 5.6 calibrate the model against the committee's own record: the criteria vacuum, the priced budget, and the penalty ledger. Section 5.7 identifies what clears the gate.
### 5.1 The Default Is No
-Standardization has costs that ecosystem delivery does not bear. An ecosystem library fixes bugs in its next release, changes its API when users report friction, drops features that turn out to be mistakes, and competes for its users. A standard library component is specified once, implemented by every conforming vendor, taught to every student, maintained in perpetuity, and - per the record in Section 5.6 - frozen at the point of adoption. A component that is useful but needs nothing from standardization is simply a useful library, and the burden of demonstrating otherwise sits on the proposer.
+Standardization has costs that ecosystem delivery does not bear. An ecosystem library fixes bugs in its next release, changes its API when users report friction, drops features that turn out to be mistakes, and competes for its users. Per the record in Section 5.6, a standard library component is specified once, implemented by every conforming vendor, taught to every student, maintained in perpetuity, and frozen at the point of adoption. A component that is useful but needs nothing from standardization is a useful library, and the burden of demonstrating otherwise sits on the proposer.
### 5.2 The Vocabulary
@@ -152,7 +152,7 @@ The gate's instruments are eight named quantities. Each term receives one senten
| Term | Meaning |
|---|---|
| Coordination Problem | The class of problem that justifies standardization: a concept everybody needs but every library implements differently |
-| Complexity Budget | The finite resource of specification the standard can carry; every addition spends it |
+| Complexity Budget | The finite resource of specification the standard can carry. Every addition spends it |
| The GitHub Test | The threshold question: what does standardization deliver that downloading the library does not |
| Reach Test | The audience question: how large is the constituency that collects the benefit |
| Return on Complexity (ROC) | Value delivered per unit of Complexity Budget spent |
@@ -164,47 +164,47 @@ The gate's instruments are eight named quantities. Each term receives one senten
### 5.3 The Value Model
-The model turns the vocabulary into arithmetic; the disclosure in Section 1 applies to this model in particular. Five quantities parameterize it: `B`, the gross benefit per beneficiary per year beyond availability alone; `N`, the number of beneficiaries; `delta`, the fraction of value forfeited to ossification, between 0 and 1; `k`, the complexity spent in wording, names, and interactions; and `C0`, the fixed cost of admission in committee hours and displaced floor time. Two rates complete it: `tau`, the annual Interaction Tax per unit of complexity, and `r`, a time discount rate.
+The model turns the vocabulary into arithmetic. In Section 1, the disclosure applies to this model in particular. Five quantities parameterize it: `B`, the gross benefit per beneficiary per year beyond availability alone; `N`, the number of beneficiaries; `delta`, the fraction of value forfeited to ossification, between 0 and 1; `k`, the complexity spent in wording, names, and interactions; and `C0`, the fixed cost of admission in committee hours and displaced floor time. Two rates complete it: `tau`, the annual Interaction Tax per unit of complexity, and `r`, a time discount rate.
The GitHub Test is the threshold condition: `B` is the difference between the standardized benefit and the downloadable benefit, and if everything the component offers is captured by downloading it, `B` is zero and no other number matters. This is the default no of Section 5.1, stated as arithmetic.
-The Standardization Penalty relates in-standard value to ecosystem value: the standardized component delivers `(1 - delta)` of what its ecosystem form delivers, and `delta` grows with the domain's evolution velocity multiplied by the freeze horizon - release cycle plus implementation lag plus the effectively permanent freeze of the application binary interface (ABI). The Penalty is not a constant; it is a property of the domain, measurable from ecosystem release cadence. Hash maps and regular expressions live in high-velocity domains, so their `delta` approaches 1; Section 5.6 prices both. Strings live in a low-velocity domain, so their `delta` is small.
+The Standardization Penalty relates in-standard value to ecosystem value: the standardized component delivers `(1 - delta)` of what its ecosystem form delivers, and `delta` grows with the domain's evolution velocity multiplied by the freeze horizon - release cycle plus implementation lag plus the effectively permanent freeze of the application binary interface (ABI). The Penalty varies by domain and is measurable from ecosystem release cadence. Hash maps and regular expressions live in high-velocity domains, so their `delta` approaches 1. Section 5.6 prices both. Strings live in a low-velocity domain, so their `delta` is small.
-The remaining definitions compose. The annual dividend flow of an admitted component is `d = (1 - delta) * B * N - tau * k`: benefit net of Penalty, minus the Interaction Tax the component levies on the rest of the standard every year. The Standardization Dividend `D` is the discounted sum of that flow minus `C0`. Return on Complexity is `ROC = D / k`.
+The remaining definitions compose. The annual dividend flow of an admitted component is `d = (1 - delta) * B * N - tau * k`: benefit net of Penalty, minus the Interaction Tax the component levies on the rest of the standard every year. Discounting that flow and subtracting `C0` gives the Standardization Dividend `D`. Return on Complexity is `ROC = D / k`.
-The admission rule is comparative, because the Complexity Budget is finite: admit if and only if `ROC` meets or beats `lambda`, where `lambda` is the return of the best proposal the admission displaces. Positive is not the bar; better than every competitor for the same budget is the bar.
+Because the Complexity Budget is finite, the admission rule is comparative: admit if and only if `ROC` meets or beats `lambda`, where `lambda` is the return of the best proposal the admission displaces. A positive return is not enough. The component must beat every competitor for the same budget.
-One scaling law separates most components that clear this rule from most that do not. For a convenience component, value scales linearly with adoption: each user collects the benefit once. For a vocabulary component, value lives in the links: independently authored libraries that can now interoperate collect the benefit pairwise, so value grows with the square of adoption - to the extent the links are realized in practice, which is why Section 5.7 counts realized boundary traffic rather than potential pairs. Linear algebra computation happens inside a codebase - linear scaling. Strings cross every interface boundary - quadratic scaling. Among components the ecosystem can deliver, only those whose value scales with the square of adoption reliably outrun `delta`, `tau * k`, and `C0`; the exception is the component the ecosystem cannot deliver at all, such as a facility requiring compiler support, whose `B` is large enough that linear scaling clears.
+One scaling law separates most components that clear this rule from most that do not. For a convenience component, value scales linearly with adoption: each user collects the benefit once. For a vocabulary component, value lives in the links: independently authored libraries that can now interoperate collect the benefit pairwise, so value grows with the square of adoption - to the extent the links are realized in practice, which is why Section 5.7 counts realized boundary traffic rather than potential pairs. Linear algebra computation happens inside a codebase - linear scaling. Strings cross every interface boundary - quadratic scaling. Among components the ecosystem can deliver, only those whose value scales with the square of adoption reliably outrun `delta`, `tau * k`, and `C0`. The exception is the component the ecosystem cannot deliver at all, such as a facility requiring compiler support, whose `B` is large enough that linear scaling clears.
-The model never requires absolute precision, because the admission rule is a ranking. `lambda` is the return of the displaced proposal, so order-of-magnitude estimates suffice to rank whenever the gaps are large, and the gaps are large: a component serving everyone who connects to the internet and a component serving one specialty container's users differ by a margin no estimation error can flip. This is the ordinal sufficiency principle, and it is what licenses the pre-flight calibration of Section 4.1 to be rough. The objection that these quantities cannot be measured precisely is an argument against false precision, not against measurement.
+Because the admission rule is a ranking, the model never requires absolute precision. `lambda` is the return of the displaced proposal, so order-of-magnitude estimates suffice to rank whenever the gaps are large, and the gaps are large: a component serving everyone who connects to the internet and a component serving one specialty container's users differ by a margin no estimation error can flip. This is the ordinal sufficiency principle, and it is what licenses the pre-flight calibration of Section 4.1 to be rough. The objection that these quantities cannot be measured precisely is an argument against false precision, not against measurement.
-One retrodiction shows the instruments operating at the precision the model claims for them, using only facts knowable at the decision. Run the gate on the regular expression component as of 2003, the year the hash table and regex admissions were before the committee. The GitHub Test: `B` was modest - Boost.Regex was freely downloadable, so standardization offered availability on closed toolchains and little else. The scaling class: regular expressions are consumed inside a codebase and rarely cross interface boundaries as a vocabulary type, so value scales linearly. The domain velocity: regex engines were under active development in 2003 and had been for years, so `delta` was foreseeably large - the freeze would forfeit the improvements the domain kept producing. Verdict at order-of-magnitude precision: linear scaling, small `B`, large `delta` - reject, or at most not-ready pending evidence that availability-on-every-toolchain outweighed a foreseeably large Penalty. The committee admitted it unanimously (Section 5.4), and Section 5.6 records what the Penalty then collected. The retrodiction uses hindsight to select the example, not to run the instruments; every input was on the table in 2003.
+One retrodiction shows the instruments operating at the precision the model claims for them, using only facts knowable at the decision. Run the gate on the regular expression component as of 2003, the year the hash table and regex admissions were before the committee. The GitHub Test: `B` was modest - Boost.Regex was freely downloadable, so standardization offered availability on closed toolchains and little else. On the scaling class, regular expressions are consumed inside a codebase and rarely cross interface boundaries as a vocabulary type, so value scales linearly. The domain velocity: regex engines were under active development in 2003 and had been for years, so `delta` was foreseeably large - the freeze would forfeit the improvements the domain kept producing. Verdict at order-of-magnitude precision: linear scaling, small `B`, large `delta` - reject, or at most not-ready pending evidence that availability-on-every-toolchain outweighed a foreseeably large Penalty. The committee admitted it unanimously (Section 5.4), and Section 5.6 records what the Penalty then collected. Hindsight enters only in selecting the example. Every input to the instruments was on the table in 2003.
### 5.4 No Admission Rule Has Ever Policed the Door
-The committee has asked the gate question of itself for twenty-five years without answering it. This section traces the record from the TR1 charter to the present standing documents.
+For twenty-five years the committee has asked the gate question of itself without answering it. The record traced here runs from the TR1 charter to the present standing documents.
-The criteria question is as old as the library extension effort that produced the first Library Technical Report (TR1). [N1314](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2001/n1314.htm)[30] (Matt Austern, 2001) recorded the library working group's position at the start: "At this early stage, the library working group was reluctant to identify any possible directions that would definitely be ruled out." What it did require measured proposal quality, not need: "A proposal should be a well thought out design, and should include specific text that would be suitable for a standard. ... Ideally it should include a reference implementation ..." On criteria themselves, N1314 stated: "We will need to develop criteria for evaluating proposals." No later document in the record surveyed here - the calls for proposals, the direction papers, and the standing documents traced through the rest of this section - supplied them.
+The criteria question is as old as the library extension effort that produced the first Library Technical Report (TR1). [N1314](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2001/n1314.htm)[30] (Matt Austern, 2001) recorded the library working group's position at the start: "At this early stage, the library working group was reluctant to identify any possible directions that would definitely be ruled out." What it did require measured the quality of a proposal rather than the need for it: "A proposal should be a well thought out design, and should include specific text that would be suitable for a standard. ... Ideally it should include a reference implementation ..." On criteria themselves, N1314 stated: "We will need to develop criteria for evaluating proposals." No later document in the record surveyed here - the calls for proposals, the direction papers, and the standing documents traced through the rest of this section - supplied them.
-The criterion that emerged instead was existing practice. The TR2 call for proposals, [N1810](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1810.html)[31] (2005), stated it with its rationale: "The committee prefers proposals that are based on existing practice. ... First, a proposal must be implementable, and the best evidence that something is implementable is that it has been implemented. Second, if a proposal is based on existing practice, the committee can have more confidence that the proposal solves a real problem and that its interface serves the needs of real users." The 2012 standing call, [N3370](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3370.html)[32], restated the preference and added a delivery rule: "the clear preference is for new library components to go into TRs, while modifications go into the standard." Existing practice is a quality filter, not an admission rule: it asks whether the component works, not whether the standard needs it.
+What emerged instead was existing practice. The TR2 call for proposals, [N1810](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1810.html)[31] (2005), stated it with its rationale: "The committee prefers proposals that are based on existing practice. ... First, a proposal must be implementable, and the best evidence that something is implementable is that it has been implemented. Second, if a proposal is based on existing practice, the committee can have more confidence that the proposal solves a real problem and that its interface serves the needs of real users." In 2012, the standing call [N3370](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3370.html)[32] restated the preference and added a delivery rule: "the clear preference is for new library components to go into TRs, while modifications go into the standard." Existing practice is a quality filter, not an admission rule: it asks whether the component works, and leaves unasked whether the standard needs it.
-The Direction Group assessed the founding criteria in [P0939R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0939r0.pdf)[33] (2018), Section 4.2: "During the early stages of the development of the first standard, we articulated some principle for what to include in the standard library, including Language support; Facilities that everybody needs; Facilities needed for communicating among separately developed libraries. We think these are reasonable criteria, but in practice they didn't have much effect." The same paper names the cost side: "No feature is cost free, there is always the implementation cost, the cost of producing teaching material, the time needed to learn, the opportunities for confusion, and the inevitable distraction from overselling." The same year, [P0977R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0977r0.pdf)[34] reproduced its author's own 1992 warning to the committee: "If every extension that is reasonably well-defined, clean and general, and would make life easier for a couple of hundred or couple of thousand C++ programmers were accepted, the language would more than double in size."
+In [P0939R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0939r0.pdf)[33] (2018), Section 4.2, the Direction Group assessed the founding criteria: "During the early stages of the development of the first standard, we articulated some principle for what to include in the standard library, including Language support; Facilities that everybody needs; Facilities needed for communicating among separately developed libraries. We think these are reasonable criteria, but in practice they didn't have much effect." The same paper names the cost side: "No feature is cost free, there is always the implementation cost, the cost of producing teaching material, the time needed to learn, the opportunities for confusion, and the inevitable distraction from overselling." The same year, [P0977R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0977r0.pdf)[34] reproduced its author's own 1992 warning to the committee: "If every extension that is reasonably well-defined, clean and general, and would make life easier for a couple of hundred or couple of thousand C++ programmers were accepted, the language would more than double in size."
Twenty-one years after N1314, the Direction Group was still asking for the discussion to start. [P2000R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2000r4.pdf)[3] (2022), Section 5.3: "We encourage a discussion of criteria of what should be in the standard library and what should not. The aim is to be able to discuss proposed new standard-library components in the context of articulated criteria."
-The standing documents contain no criteria. As of its 2024-05-14 revision, the entire policy list in [SD-9](https://isocpp.org/std/standing-documents/sd-9-library-evolution-policies)[35], "Library Evolution Policies", reads: "1. Policy: Library wording should not use [[nodiscard]]". The Tokyo 2024 minutes, [N4980](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4980.pdf)[36], record that "LEWG had its first policies discussion during the Tokyo meeting" - twenty-three years after N1314 - and frame the purpose as saving process time, not defining admission.
+The standing documents contain no criteria. As of its 2024-05-14 revision, the entire policy list in [SD-9](https://isocpp.org/std/standing-documents/sd-9-library-evolution-policies)[35], "Library Evolution Policies", reads: "1. Policy: Library wording should not use [[nodiscard]]". The Tokyo 2024 minutes, [N4980](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4980.pdf)[36], record that "LEWG had its first policies discussion during the Tokyo meeting" - twenty-three years after N1314 - and frame the purpose as saving process time rather than defining admission.
-The nearest modern criteria statement appears in a paper written to argue against one admission. [P3001R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3001r0.html)[37] (2023) lists the categories: "Elements of the standard library ideally fall into one of the following categories: 3.1 Types and functions requiring compiler intrinsics ... 3.2 Core vocabulary types ... 3.3 Cross-platform OS abstractions ... 3.4 Fundamental algorithms and data structures", and states the cost frame: "Standardizing a feature takes a lot of work, and the committee has limited time. Everything we discuss takes time away from a different feature and means delaying something else." The room continued with the container the paper argued against at a 2:1 ratio, as the committee [paper tracker](https://github.com/cplusplus/papers/issues/1685)[38] records; the categories bound nothing.
+The nearest modern criteria statement appears in a paper written to argue against one admission. [P3001R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3001r0.html)[37] (2023) lists the categories: "Elements of the standard library ideally fall into one of the following categories: 3.1 Types and functions requiring compiler intrinsics ... 3.2 Core vocabulary types ... 3.3 Cross-platform OS abstractions ... 3.4 Fundamental algorithms and data structures", and states the cost frame: "Standardizing a feature takes a lot of work, and the committee has limited time. Everything we discuss takes time away from a different feature and means delaying something else." The room continued with the container the paper argued against at a 2:1 ratio, as the committee [paper tracker](https://github.com/cplusplus/papers/issues/1685)[38] records, and the categories bound nothing.
-The vote record shows what an unpoliced door produces. At Oxford 2003, the TR1 hash-table admission passed with zero recorded opposition - the minutes ([N1459](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1459.html)[39]) tally the motion at 19-0-0 in J16 and 9-0-0 in WG21, favor-oppose-abstain; Section 5.6 records what that component's 2003 interface forecloses today. At Kona 2007, the committee's only formal scope-exclusion vote in this record resolved to "Exclude thread pools, task launching, and reader-writer locks" ([N2452](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2452.html)[40]); task launching entered anyway as `std::async` in C++11, and reader-writer locks entered in C++14 and C++17. The Berlin 2006 minutes ([N1993](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1993.html)[41]) tally the special math straw poll at 3-5-2 in WG21 - a failure to carry - and the functions were published as a separate ISO standard and merged into C++17 regardless; Section 5.5 prices their twenty-one-year implementation arc.
+The vote record shows what an unpoliced door produces. At Oxford 2003, the TR1 hash-table admission passed with zero recorded opposition - the minutes ([N1459](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1459.html)[39]) tally the motion at 19-0-0 in J16 and 9-0-0 in WG21, favor-oppose-abstain. Section 5.6 records what that component's 2003 interface forecloses today. At Kona 2007, the committee's only formal scope-exclusion vote in this record resolved to "Exclude thread pools, task launching, and reader-writer locks" ([N2452](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2452.html)[40]). Task launching entered anyway as `std::async` in C++11, and reader-writer locks entered in C++14 and C++17. The Berlin 2006 minutes ([N1993](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1993.html)[41]) tally the special math straw poll at 3-5-2 in WG21 - a failure to carry - and the functions were published as a separate ISO standard and merged into C++17 regardless. Section 5.5 prices their twenty-one-year implementation arc.
-The record supports one finding: the stated criteria were quality filters, the stated exclusions did not hold, the founding principles "didn't have much effect" by their authors' own assessment, and no standing document defines what belongs. The committee checks whether a proposal is well-made; nothing on record checks whether the standard needs it.
+One finding covers the whole record: the stated criteria were quality filters, the stated exclusions did not hold, the founding principles "didn't have much effect" by their authors' own assessment, and no standing document defines what belongs. The committee checks whether a proposal is well-made. Nothing on record checks whether the standard needs it.
### 5.5 The Complexity Budget, Priced
-The Complexity Budget is measurable in pages, names, and years of vendor latency. This section prices it.
+The Complexity Budget is measurable in pages, names, and years of vendor latency, and this section prices it.
-The standard has more than tripled since C++98, and the library is where the growth is. The following table sets published ISO page counts beside page counts measured directly from the working-draft PDFs.
+Since C++98 the standard has more than tripled, and the library is where the growth is. The following table sets published ISO page counts beside page counts measured directly from the working-draft PDFs.
| Version | Published ISO pages | Working draft | Draft pages | Library share of clause text |
|---|---|---|---|---|
@@ -215,15 +215,15 @@ The standard has more than tripled since C++98, and the library is where the gro
| C++23 | - | [N4950](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4950.pdf)[45] | 2134 | 75% |
| C++26 WD | - | [N5046](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/n5046.pdf)[46] | 2679 | 77% |
-*Table 2: Standard size and library share by revision. Draft pages and library shares were measured from the cited PDFs on 2026-07-08; the share compares language-clause pages to library-clause pages as delimited by each draft's own bookmark tree, with front matter, annexes, and the indexes outside both counts. The C++26 working draft is 545 pages (26 percent) larger than the C++23 final draft, the largest single-cycle jump in absolute pages in the language's history.*
+*Table 2: Standard size and library share by revision. Draft pages and library shares were measured from the cited PDFs on 2026-07-08. The share compares language-clause pages to library-clause pages as delimited by each draft's own bookmark tree, with front matter, annexes, and the indexes outside both counts. The C++26 working draft is 545 pages (26 percent) larger than the C++23 final draft, the largest single-cycle jump in absolute pages in the language's history.*
Bjarne Stroustrup corroborates the proportion in [HOPL-IV](https://dl.acm.org/doi/10.1145/3386320)[47] (2020): "The standard library is about 3/4 of the C++20 standard."
-The name count grew faster than the pages. The library name index holds [3,543 entries in C++11](https://timsong-cpp.github.io/cppwp/std11/libraryindex)[48] and [14,278 in the C++26 working draft](https://eel.is/c++draft/libraryindex)[49] - a quadrupling in fifteen years. The index alone occupies 122 pages of the C++26 draft, up from 36 pages in C++11. Proposal authors state their name spend on the record: [P1673R13](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p1673r13.html)[50] reports "Our proposal would add 61 new unique names to the C++ Standard Library."
+The name count grew faster than the pages. The library name index holds [3,543 entries in C++11](https://timsong-cpp.github.io/cppwp/std11/libraryindex)[48] and [14,278 in the C++26 working draft](https://eel.is/c++draft/libraryindex)[49] - a quadrupling in fifteen years. In the C++26 draft the index alone occupies 122 pages, up from 36 pages in C++11. Proposal authors state their name spend on the record: [P1673R13](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p1673r13.html)[50] reports "Our proposal would add 61 new unique names to the C++ Standard Library."
-Individual components price their own wording. Measured from the same drafts: the Ranges clause grew from 64 pages in C++20 to 170 in the C++26 working draft; the File systems clause is 54 pages; Regular expressions is 45; and the new Execution control clause enters at 91 pages - larger than filesystem or regex - with zero shipping mainstream implementations. A single merge paper can approach the scale of the original library: [P0896R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0896r4.pdf)[51] is a 226-page wording document, where the entire C++98 library specification was on the order of 350 pages.
+Individual components price their own wording. Measured from the same drafts: the Ranges clause grew from 64 pages in C++20 to 170 in the C++26 working draft, the File systems clause is 54 pages, Regular expressions is 45, and the new Execution control clause enters at 91 pages - larger than filesystem or regex - with zero shipping mainstream implementations. A single merge paper can approach the scale of the original library: [P0896R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0896r4.pdf)[51] is a 226-page wording document, where the entire C++98 library specification was on the order of 350 pages.
-A page of specification is not a shipped feature; vendors pay the budget again in implementation, and the latency is measured in years. The following table records when each of the three mainstream standard libraries shipped selected standardized features, compiled from the [cppreference compiler support table](https://en.cppreference.com/cpp/compiler_support)[52] and the vendors' own status pages on 2026-07-08.
+A page of specification is not a shipped feature. Vendors pay the budget again in implementation, and the latency is measured in years. The following table records when each of the three mainstream standard libraries shipped selected standardized features, compiled from the [cppreference compiler support table](https://en.cppreference.com/cpp/compiler_support)[52] and the vendors' own status pages on 2026-07-08.
| Feature | Standardized | libstdc++ | libc++ | MSVC STL |
|---|---|---|---|---|
@@ -236,9 +236,9 @@ A page of specification is not a shipped feature; vendors pay the budget again i
*Table 3: Vendor availability lag for selected features, compiled from the cppreference support table and the vendors' own status pages on 2026-07-08. Standardized does not mean available: for the published standards, the lag runs from one year to nine-plus years, and sometimes to never. The std::execution row predates C++26 publication and is shown for scale.*
-The special math functions entered TR1 in 2005, failed the Berlin vote, were published separately as ISO/IEC 29124:2010, merged into C++17 anyway, and remain 20-of-21 "Not Started" in libc++ - a mandated C++17 feature unavailable on the default Apple and Android toolchain nine years after standardization. The garbage collection interface was standardized in C++11, implemented by no vendor, and removed in C++23; the removal paper, [P2186R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2186r2.html)[54], states: "This status-quo hasn't changed in 12 years. ... the current specification simply missed the mark, and will not be missed."
+The special math functions entered TR1 in 2005, failed the Berlin vote, were published separately as ISO/IEC 29124:2010, merged into C++17 anyway, and remain 20-of-21 "Not Started" in libc++ - a mandated C++17 feature unavailable on the default Apple and Android toolchain nine years after standardization. Standardized in C++11, the garbage collection interface was implemented by no vendor and removed in C++23. The removal paper, [P2186R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2186r2.html)[54], states: "This status-quo hasn't changed in 12 years. ... the current specification simply missed the mark, and will not be missed."
-The delivery pipeline confirms the same price. Of the fifteen published library-relevant Technical Specifications, four delivered nothing to the standard - the Networking TS never merged, the Reflection TS contributed zero words before its design was abandoned for a different approach, Library Fundamentals v3 merged nothing, and the Transactional Memory line ended as a white paper after fourteen years of study group work - and four more delivered fragments: Concurrency v1 without `future::then`, Library Fundamentals v2 without `observer_ptr`, the Concepts TS stripped of terse syntax and function concepts, and Parallelism v2 reduced to `simd` six years later. The ledger is the [cppreference TS registry](https://en.cppreference.com/cpp/experimental)[55] cross-checked against the final drafts.
+The delivery pipeline confirms the same price. Of the fifteen published library-relevant Technical Specifications, four delivered nothing to the standard: the Networking TS never merged, the Reflection TS contributed zero words before its design was abandoned for a different approach, Library Fundamentals v3 merged nothing, and the Transactional Memory line ended as a white paper after fourteen years of study group work. Four more delivered fragments: Concurrency v1 without `future::then`, Library Fundamentals v2 without `observer_ptr`, the Concepts TS stripped of terse syntax and function concepts, and Parallelism v2 reduced to `simd` six years later. The ledger is the [cppreference TS registry](https://en.cppreference.com/cpp/experimental)[55] cross-checked against the final drafts.
The budget is finite in pages, in names, in vendor implementation capacity, and in the committee's own review hours (Section 3). Every admission spends all four.
@@ -248,7 +248,7 @@ The Standardization Penalty is the committee's own finding. [P3001R0](https://ww
#### The freeze mechanism: Prague 2020
-At the Prague meeting in February 2020, the committee polled the room on breaking ABI. The tallies were published on the [public list of the tooling study group, SG15](https://lists.isocpp.org/sg15/att-0979/attachment)[56], and the official minutes, [N4855](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4855.pdf)[57], record the outcome: "We decided not to promise ABI stability. ... We did not have a consensus for a big ABI break for C++23 ..." No ABI break has occurred through C++26 development. The vote did not choose stability; it declined to choose, and the default - freeze - won.
+At the Prague meeting in February 2020, the committee polled the room on breaking ABI. The tallies were published on the [public list of the tooling study group, SG15](https://lists.isocpp.org/sg15/att-0979/attachment)[56], and the official minutes, [N4855](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4855.pdf)[57], record the outcome: "We decided not to promise ABI stability. ... We did not have a consensus for a big ABI break for C++23 ..." Through C++26 development, no ABI break has occurred. The vote did not choose stability. It declined to choose, and the default - freeze - won.
What the freeze forecloses was quantified in the papers before the room. [P1863R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1863r1.pdf)[58]: "It's been the case for years that implementers effectively have a veto on ABI breaking changes - we have already been prioritizing ABI above design or performance concerns. ... we believe we could provide an API-compatible unordered_map/std::hash implementation that improves existing performance by 200-300% on average. This is disallowed by ABI constraints. ... We say 'performance' but vote 'ABI'. This dissonance is harmful for the ecosystem." [P2028R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2028r0.pdf)[59] draws the permanent conclusion: "there are things in the standard library that are meaningfully inefficient (regex, unordered_map) and will be so forever." Botond Ballo's [Prague trip report](https://botondballo.wordpress.com/2020/03/12/trip-report-c-standards-meeting-in-prague-february-2020/)[60] records the operational form: "the Library Evolution group has had to reject multiple proposals for improvements to existing library facilities over the past several years, because they would be ABI-breaking."
@@ -269,15 +269,15 @@ The one implementation that did break string ABI shows the cost side. Jonathan W
*Table 4: The P1433R0 grep-task benchmark (1.3 GB CSV, pattern `([0-9]{4,16})?[aA]`, macOS with clang). The standardized component is seventy-five times slower than the system baseline and one hundred sixty times slower than the fastest downloadable alternative.*
-All three vendors have said on the record that the fix requires an ABI break they will not take. The libc++ maintainers in [llvm/llvm-project #60991](https://github.com/llvm/llvm-project/issues/60991)[65]: "it's been pretty much untouched since it's been implemented more than ten years ago. ... don't expect huge improvements." Microsoft in [microsoft/STL #405](https://github.com/microsoft/STL/issues/405)[66]: "Resolving this issue will require breaking binary compatibility. We won't be able to accept pull requests for this issue until the vNext branch is available." libstdc++ in [GCC bug 118408](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118408)[67]: "It may be too late to fix this though ..." A poll of the text-processing study group, SG16, recorded consensus to recommend deprecation without guaranteed replacement in February 2020, per the [tracker record](https://github.com/cplusplus/papers/issues/597)[68]; no deprecation paper has followed, and SG16's own [tracking issue for one](https://github.com/sg16-unicode/sg16/issues/57)[69] remains open six years later, labeled "paper needed".
+All three vendors have said on the record that the fix requires an ABI break they will not take. The libc++ maintainers in [llvm/llvm-project #60991](https://github.com/llvm/llvm-project/issues/60991)[65]: "it's been pretty much untouched since it's been implemented more than ten years ago. ... don't expect huge improvements." Microsoft in [microsoft/STL #405](https://github.com/microsoft/STL/issues/405)[66]: "Resolving this issue will require breaking binary compatibility. We won't be able to accept pull requests for this issue until the vNext branch is available." libstdc++ in [GCC bug 118408](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118408)[67]: "It may be too late to fix this though ..." A poll of the text-processing study group, SG16, recorded consensus to recommend deprecation without guaranteed replacement in February 2020, per the [tracker record](https://github.com/cplusplus/papers/issues/597)[68]. No deprecation paper has followed, and SG16's own [tracking issue for one](https://github.com/sg16-unicode/sg16/issues/57)[69] remains open six years later, labeled "paper needed".
#### unordered_map: the 2003 interface forecloses the 2017 state of the art
-The hash container admitted unanimously in 2003 specified reference stability and a bucket API, and those guarantees foreclose the open-addressing designs that now dominate. Meta's engineers state the mechanism in the [F14 announcement](https://engineering.fb.com/2019/04/25/developer-tools/f14/)[70]: "The standard guarantees reference stability: References and pointers to the keys and values in the hash table must remain valid until the corresponding key is removed. In practice, this means the entries must be indirect and individually allocated, which adds a substantial CPU overhead." Google's response was measured at [CppCon 2017](https://www.youtube.com/watch?v=ncHmEUmJZf4)[71]: "Our implementation of this new design gets 2-3x better performance with significant memory reductions (compared to unordered_map) and is being broadly deployed across Google. ... You might be asking, did we just break standards compatibility? Yes. Multiple times." Even a fully conformant rewrite pays: the [Boost.Unordered benchmarks](https://www.boost.org/doc/libs/latest/libs/unordered/doc/html/unordered/benchmarks.html)[72] show a standard-compliant rewrite making lookups almost twice as fast as `std::unordered_map`, with the non-conformant flat map faster still. Joaquín M López Muñoz's analysis in [ACCU Overload 170](https://accu.org/journals/overload/30/170/munoz)[73] traces the foreclosure to four interface features that leak the 2003 chaining assumption. In the years since the Prague vote, no paper in the [wg21.link index](https://wg21.link/index.json)[28] proposes a standard open-addressing hash table (searched by title on hash, map, and container terms, 2026-07-08); that work happens entirely outside the standard.
+Admitted unanimously in 2003, the hash container specified reference stability and a bucket API, and those guarantees foreclose the open-addressing designs that now dominate. Meta's engineers state the mechanism in the [F14 announcement](https://engineering.fb.com/2019/04/25/developer-tools/f14/)[70]: "The standard guarantees reference stability: References and pointers to the keys and values in the hash table must remain valid until the corresponding key is removed. In practice, this means the entries must be indirect and individually allocated, which adds a substantial CPU overhead." Google's response was measured at [CppCon 2017](https://www.youtube.com/watch?v=ncHmEUmJZf4)[71]: "Our implementation of this new design gets 2-3x better performance with significant memory reductions (compared to unordered_map) and is being broadly deployed across Google. ... You might be asking, did we just break standards compatibility? Yes. Multiple times." Even a fully conformant rewrite pays: the [Boost.Unordered benchmarks](https://www.boost.org/doc/libs/latest/libs/unordered/doc/html/unordered/benchmarks.html)[72] show a standard-compliant rewrite making lookups almost twice as fast as `std::unordered_map`, with the non-conformant flat map faster still. Joaquín M López Muñoz's analysis in [ACCU Overload 170](https://accu.org/journals/overload/30/170/munoz)[73] traces the foreclosure to four interface features that leak the 2003 chaining assumption. In the years since the Prague vote, no paper in the [wg21.link index](https://wg21.link/index.json)[28] proposes a standard open-addressing hash table (searched by title on hash, map, and container terms, 2026-07-08). That work happens entirely outside the standard.
#### filesystem: deprecations began immediately
-`std::filesystem` entered C++17 from Boost.Filesystem with fourteen years of field history, and its `u8path` function completed a full add-deprecate-remove cycle inside three revisions: added in C++17, deprecated in C++20 by the char8_t changes of [P0482R6](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0482r6.html)[74], removal proposed in [P3364R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3364r0.pdf)[75] - a language change colliding with a shipped library API, which is the Interaction Tax of Table 1 operating, not ossification. The Penalty proper drives the second deprecation wave against the same class: [P2319R5](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2319r5.html)[76] states that "some common path accessors still exhibit broken behavior, which results in mojibake and data loss." Security repair also arrived from outside: both libc++ and libstdc++ shipped the time-of-check/time-of-use (TOCTOU) symlink race that Rust patched as [CVE-2022-21658](https://blog.rust-lang.org/2022/01/20/cve-2022-21658/)[77], and libc++ [fixed remove_all six days after the Rust advisory](https://github.com/llvm/llvm-project/commit/4f67a909902d8ab9e24e171201db189b661700bf)[78] with a test taken from the Rust patch. Boost.Filesystem, meanwhile, kept evolving after the standard froze: its v4 semantics fix the dotfile behaviors the standard cannot, per the [release history](https://www.boost.org/doc/libs/master/libs/filesystem/doc/release_history.html)[79].
+`std::filesystem` entered C++17 from Boost.Filesystem with fourteen years of field history, and its `u8path` function completed a full add-deprecate-remove cycle inside three revisions: added in C++17, deprecated in C++20 by the char8_t changes of [P0482R6](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0482r6.html)[74], removal proposed in [P3364R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3364r0.pdf)[75] - a language change colliding with a shipped library API, which is the Interaction Tax of Table 1 operating rather than ossification. The Penalty proper drives the second deprecation wave against the same class: [P2319R5](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2319r5.html)[76] states that "some common path accessors still exhibit broken behavior, which results in mojibake and data loss." Security repair also arrived from outside: both libc++ and libstdc++ shipped the time-of-check/time-of-use (TOCTOU) symlink race that Rust patched as [CVE-2022-21658](https://blog.rust-lang.org/2022/01/20/cve-2022-21658/)[77], and libc++ [fixed remove_all six days after the Rust advisory](https://github.com/llvm/llvm-project/commit/4f67a909902d8ab9e24e171201db189b661700bf)[78] with a test taken from the Rust patch. Boost.Filesystem, meanwhile, kept evolving after the standard froze: its v4 semantics fix the dotfile behaviors the standard cannot, per the [release history](https://www.boost.org/doc/libs/master/libs/filesystem/doc/release_history.html)[79].
#### format: the best case still pays
@@ -292,13 +292,13 @@ The hash container admitted unanimously in 2003 specified reference stability an
*Table 5: Feature lag between {fmt} and the standard, from the [{fmt} documentation](https://fmt.dev/12.0/api/)[80] and [Barry Revzin's enumeration](https://stackoverflow.com/questions/63586747/what-are-the-differences-between-libfmt-and-stdformat)[81]. Victor Zverovich's own accounting: "the print function in almost its current form has been available in the {fmt} library ... since version 0.10.0 released 9.5 years ago" ([vitaut.net](https://vitaut.net/posts/2023/print-in-cpp23/)[82]).*
-The shipped design also needed retroactive repair, and the repair was possible only because the freeze had not yet engaged. [P2216R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2216r3.html)[83] made invalid format strings a compile-time error as a defect report against published C++20; the LEWG record on the [tracking issue](https://github.com/cplusplus/papers/issues/919)[84] is explicit: "We voted in two breaking changes (wrt C++20) in the design of format. We did this with the understanding that std::format is not yet shipping in any implementation ..." Five further defect reports followed against the published standard. And the shipped implementations still trail the library they copied: Microsoft's own tracking issue [microsoft/STL #1802](https://github.com/microsoft/STL/issues/1802)[85] documented `std::format` at launch as "more than 3 times slower than its fmt counterpart", and Matt Godbolt's [2026 measurement](https://github.com/mattgodbolt/performance-tuning/commit/29bfb1c421076e8339d7d9751d0b1c639ebd0d1c)[86] still has fmt::format_to at roughly 80 nanoseconds against libstdc++'s 130.
+The shipped design also needed retroactive repair, and the repair was possible only because the freeze had not yet engaged. [P2216R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2216r3.html)[83] made invalid format strings a compile-time error as a defect report against published C++20. The LEWG record on the [tracking issue](https://github.com/cplusplus/papers/issues/919)[84] is explicit: "We voted in two breaking changes (wrt C++20) in the design of format. We did this with the understanding that std::format is not yet shipping in any implementation ..." Five further defect reports followed against the published standard. And the shipped implementations still trail the library they copied: Microsoft's own tracking issue [microsoft/STL #1802](https://github.com/microsoft/STL/issues/1802)[85] documented `std::format` at launch as "more than 3 times slower than its fmt counterpart", and Matt Godbolt's [2026 measurement](https://github.com/mattgodbolt/performance-tuning/commit/29bfb1c421076e8339d7d9751d0b1c639ebd0d1c)[86] still has fmt::format_to at roughly 80 nanoseconds against libstdc++'s 130.
-The best case in the modern record - field-proven, author-driven, fully implemented - ships behind its ecosystem original on features, performance, and availability. That is the floor of the Penalty, not the ceiling.
+The best case in the modern record - field-proven, author-driven, fully implemented - ships behind its ecosystem original on features, performance, and availability. That shortfall is the floor of the Penalty rather than its ceiling.
#### execution: the Penalty arriving before the standard ships
-`std::execution` provides a composable asynchronous model with structured cancellation, compile-time work-graph construction, and deployed GPU-domain prototypes; the paper trail examined here concerns not those properties but what adoption-before-deployment cost. It shows the Penalty operating on a component with no field deployment as adopted. Adopted at St. Louis in June 2024 with, per [Jonathan Müller's trip report](https://www.think-cell.com/en/career/devblog/trip-report-summer-iso-cpp-meeting-in-st-louis-usa)[87], "a very narrow vote with 1/3 voting against adoption", the design accumulated a published correction ledger before any vendor shipped it: [P4041R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4041r0.pdf)[88] tabulates 2 removals, 1 rewrite, 2 architectural fixes, 7 post-adoption additions, 5 LWG defects, and 4 national-body comment groups against the June 2024 adoption. [P3187R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3187r1.pdf)[89] removed three operations - `ensure_started`, `start_detached`, and `execute` - from the approved design as unsafe before the working-draft merge itself. In January 2026 the design's architect wrote in [P3826R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3826r3.html)[90]: "early customization is irreparably broken and must be removed. ... It is a design change happening uncomfortably close to the release of C++26", and observed that "the major Standard Library vendors seem to be in no rush to implement std::execution." [P2583R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p2583r4.pdf)[91] documents a structural gap - the completion protocol cannot perform C++20 symmetric transfer - that shipping C++26 forecloses. The component pays `delta` on entry without ever having collected ecosystem value to discount.
+`std::execution` provides a composable asynchronous model with structured cancellation, compile-time work-graph construction, and deployed GPU-domain prototypes. The paper trail examined here sets those properties aside and concerns what adoption-before-deployment cost: the Penalty operating on a component with no field deployment as adopted. Adopted at St. Louis in June 2024 with, per [Jonathan Müller's trip report](https://www.think-cell.com/en/career/devblog/trip-report-summer-iso-cpp-meeting-in-st-louis-usa)[87], "a very narrow vote with 1/3 voting against adoption", the design accumulated a published correction ledger before any vendor shipped it: [P4041R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4041r0.pdf)[88] tabulates 2 removals, 1 rewrite, 2 architectural fixes, 7 post-adoption additions, 5 LWG defects, and 4 national-body comment groups against the June 2024 adoption. [P3187R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3187r1.pdf)[89] removed three operations - `ensure_started`, `start_detached`, and `execute` - from the approved design as unsafe before the working-draft merge itself. In January 2026 the design's architect wrote in [P3826R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3826r3.html)[90]: "early customization is irreparably broken and must be removed. ... It is a design change happening uncomfortably close to the release of C++26", and observed that "the major Standard Library vendors seem to be in no rush to implement std::execution." [P2583R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p2583r4.pdf)[91] documents a structural gap - the completion protocol cannot perform C++20 symmetric transfer - that shipping C++26 forecloses. The component pays `delta` on entry without ever having collected ecosystem value to discount.
#### linalg: fix papers before any implementation exists
@@ -306,18 +306,18 @@ The best case in the modern record - field-proven, author-driven, fully implemen
#### The long tail
-The pattern is not new; it is the standard's whole history. The following components were recognized as defective within years of shipping and never repaired, or repaired only decades later.
+The pattern is the standard's whole history. Within years of shipping, the following components were recognized as defective and never repaired, or repaired only decades later.
| Component | Defect recognized | Outcome |
|---|---|---|
| vector<bool> | [LWG issue 96](https://timsong-cpp.github.io/lwg-issues/96)[96] opened 1998 | Closed not-a-defect: "Attempts to fix this directly have not been tractable, and removing it has not been tractable" |
-| valarray | Its designers ended involvement before C++98 shipped, per the record collected [in this discussion](https://stackoverflow.com/questions/46465011/where-is-it-a-good-idea-to-use-stdvalarray)[97] | A proposed redesign arrived as standardization was closing and was not taken up; the component is unchanged since |
+| valarray | Its designers ended involvement before C++98 shipped, per the record collected [in this discussion](https://stackoverflow.com/questions/46465011/where-is-it-a-good-idea-to-use-stdvalarray)[97] | A proposed redesign arrived as standardization was closing and was not taken up. The component is unchanged since |
| initializer_list | Fix proposals in 2008 and 2015 | 2024 answer on the [public std-proposals list](https://lists.isocpp.org/std-proposals/2024/11/11583.php)[98]: "nope, no plans, nothing can be done" |
| optional<T&> | Cut from C++17 over an assignment-semantics deadlock | Landed in C++26, roughly 15 years after the same debate in Boost ([P1683R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1683r0.html)[99]) |
| strstream | Deprecated at birth in C++98 | Removed in C++26, almost 30 years later ([P2867R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2867r1.html)[100]) |
| iostreams | [N4412](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4412.html)[101] catalogs the shortcomings (2015) | Coexists with printf and std::format: three parallel formatting systems specified simultaneously |
-*Table 6: Components recognized as defective and never repaired. Admission is effectively irreversible; the Penalty runs until removal, and removal takes decades when it happens at all.*
+*Table 6: Components recognized as defective and never repaired. Admission is effectively irreversible. The Penalty runs until removal, and removal takes decades when it happens at all.*
The ledger supports one reading: `delta` is real, large in fast-moving domains, and permanent. A component's proposal must price it, and Section 7 states the evidence that pricing requires.
@@ -325,29 +325,29 @@ The ledger supports one reading: `delta` is real, large in fast-moving domains,
Three classes of component clear the instruments with any regularity, and writers from the committee's library leadership have converged on the same three from different directions. [P3001R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3001r0.html)[37]'s categories - compiler intrinsics, core vocabulary types, cross-platform OS abstractions, fundamental algorithms - match the scope formula Titus Winters published on the [Abseil blog](https://abseil.io/blog/20180227-what-should-go-stdlib)[102] in 2018 ("Fundamentals. Things that can only be done with compiler support ... Vocabulary. Time, vector, string.") and the answer the sitting LEWG chair gave at the [CppCon 2020 fireside chat](https://www.youtube.com/watch?v=lil4xfpmnF4&t=1036s)[103]: "the things that I think belong in the Standard Library are the things that cannot go anywhere else. ... Vocabulary types. ... Abstractions around the platform. ... Things that require language support." Jonathan Müller [derived the same three](https://www.foonathan.net/2017/11/standard-library/)[104] independently in 2017. In the model's terms these are the components for which the GitHub Test yields a nonzero `B`: compiler-support facilities cannot be downloaded at all, and vocabulary types collect their value from interoperation, which downloading one library cannot deliver.
-Vocabulary types are the quadratic-scaling class, and the mechanism is on record in both directions. [P2125R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2125r0.pdf)[105] defines it: "The types that are most commonly passed through interfaces in a given codebase are what we call 'vocabulary types' ... having multiple common forms also leads to an ambient performance cost as chains of function calls convert back and forth between different forms." The cost of a missing vocabulary type is countable: a GitHub code search finds the QString-to-std::string conversion shim in [202,752 public C++ files](https://github.com/search?q=%22QString%3A%3AfromStdString%22+language%3Ac%2B%2B&type=code)[106] (file-level counts include vendored and duplicated trees; the order of magnitude is the datum). And the mechanism working is countable too: `string_view` arrived consolidated from three independently implemented production string-reference types ([N3762](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3762.html)[107]), and after standardization, ICU - a decades-old library with its own UTF-16 string class - [added std::u16string_view acceptance at its boundary](https://unicode-org.github.io/icu/userguide/strings/)[108], and Abseil designed its pre-adopted types to [collapse into aliases of the std types](https://abseil.io/about/design/dropin-types)[109]: "there is only one type in play."
+Vocabulary types are the quadratic-scaling class, and the mechanism is on record in both directions. [P2125R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2125r0.pdf)[105] defines it: "The types that are most commonly passed through interfaces in a given codebase are what we call 'vocabulary types' ... having multiple common forms also leads to an ambient performance cost as chains of function calls convert back and forth between different forms." The cost of a missing vocabulary type is countable: a GitHub code search finds the QString-to-std::string conversion shim in [202,752 public C++ files](https://github.com/search?q=%22QString%3A%3AfromStdString%22+language%3Ac%2B%2B&type=code)[106] (file-level counts include vendored and duplicated trees, so the order of magnitude is the datum). And the mechanism working is countable too: `string_view` arrived consolidated from three independently implemented production string-reference types ([N3762](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3762.html)[107]). After standardization, ICU - a decades-old library with its own UTF-16 string class - [added std::u16string_view acceptance at its boundary](https://unicode-org.github.io/icu/userguide/strings/)[108], and Abseil designed its pre-adopted types to [collapse into aliases of the std types](https://abseil.io/about/design/dropin-types)[109]: "there is only one type in play."
-The unsolved Coordination Problems show the gate passing components the docket lacks. JSON: [684,032 public files use nlohmann::json](https://github.com/search?q=%22nlohmann%3A%3Ajson%22+language%3Ac%2B%2B&type=code)[110] and 72,288 use rapidjson::Document (the same vendored-tree caveat applies, and the counts sweep in copies of the libraries themselves), with mutually incompatible value types and conversion protocols; the JSON proposal brought to WG21, [P0760R0](https://github.com/nlohmann/std_json/blob/master/proposal.md)[111], was never adopted. Error handling: the committee's own 2021 poll record, [P2384R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2384r1.html)[112], contains the sentence "We are in dire need of standardized error-or-value type, but there is still a lot of competing types in the area ..." These are concepts everybody needs and every library implements differently - the Coordination Problem definition - and their value lives at interface boundaries, which is quadratic scaling.
+The unsolved Coordination Problems show the gate passing components the docket lacks. JSON: [684,032 public files use nlohmann::json](https://github.com/search?q=%22nlohmann%3A%3Ajson%22+language%3Ac%2B%2B&type=code)[110] and 72,288 use rapidjson::Document (the same vendored-tree caveat applies, and the counts sweep in copies of the libraries themselves), with mutually incompatible value types and conversion protocols. The JSON proposal brought to WG21, [P0760R0](https://github.com/nlohmann/std_json/blob/master/proposal.md)[111], was never adopted. Error handling: the committee's own 2021 poll record, [P2384R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2384r1.html)[112], contains the sentence "We are in dire need of standardized error-or-value type, but there is still a lot of competing types in the area ..." These are concepts everybody needs and every library implements differently - the Coordination Problem definition - and their value lives at interface boundaries, which is quadratic scaling.
-Networking belongs to the same class; Section 1 discloses the author's stake in it. The reach is surveyed, not asserted: the ISO C++ Developer Survey series records between 19.37 percent ([2024 summary](https://isocpp.org/files/papers/CppDevSurvey-2024-summary.pdf)[113]) and 25.38 percent ([2022 summary](https://isocpp.org/files/papers/CppDevSurvey-2022-summary.pdf)[114]) of C++ developers working on communications projects across 2021-2024, against a baseline population of roughly [10.3 million C++ developers](https://developernation.net/resources/reports/state-of-the-developer-nation-25th-edition-q3-20231/)[115], and the indirect reach ceiling is the [twenty billion installations of curl](https://daniel.haxx.se/blog/2024/03/20/curl-turns-26-today/)[116]. Sockets appear at interface boundaries between independently authored libraries, which is the quadratic axis. The instruments also price what the class pays, and the pricing is not small: protocol churn - TLS versions, QUIC, platform I/O interfaces - gives the domain a real velocity, so a standardized networking component carries a `delta` well above the vocabulary-type floor, and the Microsoft STL maintainer's objection quoted in Section 8 - specialist components decay under generalist maintenance and ABI restriction - is precisely a Penalty argument the gate takes at face value. A networking proposal therefore enters the comparison of Section 4.2 with a high expectation on both sides of the ledger: quadratic reach to claim, and a large, foreseeable Penalty to price and survive. Whether any particular proposal does so is the sufficiency question of Section 7, kept apart from the class question by the two-step model of Section 4.
+Networking belongs to the same class. Section 1 discloses the author's stake in it. The reach is surveyed: the ISO C++ Developer Survey series records between 19.37 percent ([2024 summary](https://isocpp.org/files/papers/CppDevSurvey-2024-summary.pdf)[113]) and 25.38 percent ([2022 summary](https://isocpp.org/files/papers/CppDevSurvey-2022-summary.pdf)[114]) of C++ developers working on communications projects across 2021-2024, against a baseline population of roughly [10.3 million C++ developers](https://developernation.net/resources/reports/state-of-the-developer-nation-25th-edition-q3-20231/)[115], and the indirect reach ceiling is the [twenty billion installations of curl](https://daniel.haxx.se/blog/2024/03/20/curl-turns-26-today/)[116]. Sockets appear at interface boundaries between independently authored libraries, which is the quadratic axis. The instruments also price what the class pays, and the pricing is not small: protocol churn - TLS versions, QUIC, platform I/O interfaces - gives the domain a real velocity, so a standardized networking component carries a `delta` well above the vocabulary-type floor. Quoted in Section 8, the Microsoft STL maintainer's objection - specialist components decay under generalist maintenance and ABI restriction - is precisely a Penalty argument the gate takes at face value. A networking proposal therefore enters the comparison of Section 4.2 with a high expectation on both sides of the ledger: quadratic reach to claim, and a large, foreseeable Penalty to price and survive. Whether any particular proposal does so is the sufficiency question of Section 7, kept apart from the class question by the two-step model of Section 4.
-Clearing the gate is necessary, not sufficient, and even vocabulary types misfire at the boundary. `char8_t`, a standardized vocabulary type, generated compiler opt-out flags rather than adoption - [P2513R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2513r2.html)[117] records that "-fno-char8_t and /Zc:char8_t- needed to be rolled out the moment conforming C++20-aspiring implementations rolled out ..." The gate is the beginning of scrutiny, not the end of it.
+Clearing the gate is necessary, not sufficient, and even vocabulary types misfire at the boundary. `char8_t`, a standardized vocabulary type, generated compiler opt-out flags rather than adoption - [P2513R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2513r2.html)[117] records that "-fno-char8_t and /Zc:char8_t- needed to be rolled out the moment conforming C++20-aspiring implementations rolled out ..." The gate is only the beginning of scrutiny.
---
## 6. The Language Gate
-Language features face the gate question in a different form, because the ecosystem alternative does not exist. A library can be downloaded, compared against rivals, and dropped; a language feature is implemented by every compiler, carried in every curriculum, and read by every maintainer of every codebase that ever uses it - or that ever reads code written by someone who did. The GitHub Test has no direct analog: nothing about a language feature can be downloaded, so the threshold question becomes whether the benefit justifies permanent complexity in every implementation and every reader, rather than whether standardization adds value over availability.
+Language features face the gate question in a different form, because the ecosystem alternative does not exist. A library can be downloaded, compared against rivals, and dropped. A language feature is implemented by every compiler, carried in every curriculum, and read by every maintainer of every codebase that ever uses it - or that ever reads code written by someone who did. Nothing about a language feature can be downloaded, so the GitHub Test has no direct analog, and the threshold question becomes whether the benefit justifies permanent complexity in every implementation and every reader, rather than whether standardization adds value over availability.
-The costs on the language side are named in the committee's record - implementation cost in every front end, teaching cost in every curriculum, interaction cost against every existing feature, and the same review scarcity documented in Section 3 - but this paper does not supply the instruments to price them. The author's expertise is in libraries, and a gate calibrated by someone without compiler-implementation experience would be exactly the kind of unpriced assertion this paper argues against.
+On the language side, the costs are named in the committee's record - implementation cost in every front end, teaching cost in every curriculum, interaction cost against every existing feature, and the same review scarcity documented in Section 3 - but this paper does not supply the instruments to price them. The author's expertise is in libraries, and a gate calibrated by someone without compiler-implementation experience would be exactly the kind of unpriced assertion this paper argues against.
-The author invites delegates who hold that expertise - compiler implementers, EWG veterans, and educators - to supply the language instruments: the analog of the vocabulary table in Section 5.2, the observable facts a pre-flight calibration would draw on, and the record of past language admissions against which to calibrate them. The two-step model of Section 4 is designed to accept such instruments unchanged; only the calibration inputs differ between the two gates.
+The author invites delegates who hold that expertise - compiler implementers, EWG veterans, and educators - to supply the language instruments: the analog of the vocabulary table in Section 5.2, the observable facts a pre-flight calibration would draw on, and the record of past language admissions against which to calibrate them. By design, the two-step model of Section 4 accepts such instruments unchanged. Only the calibration inputs differ between the two gates.
---
## 7. What a Paper That Passes the Gate Must Prove
-A component that passes the gate has cleared the room's expectation of worth; the paper must still measure what the room estimated. This section states the evidence obligations: the four-item checklist (7.1), the implementation requirement (7.2), the two steel-man sections (7.3 and 7.4), and the accountability artifacts that survive adoption (7.5). Each obligation in Section 7.1 corresponds to a quantity in the value model, so the sufficiency comparison of Section 4.2 is a comparison of measurements against estimates rather than a contest of impressions.
+Passing the gate, a component has cleared the room's expectation of worth. The paper must still measure what the room estimated. This section states the evidence obligations: the four-item checklist (7.1), the implementation requirement (7.2), the two steel-man sections (7.3 and 7.4), and the accountability artifacts that survive adoption (7.5). In Section 7.1, each obligation corresponds to a quantity in the value model, so the sufficiency comparison of Section 4.2 is a comparison of measurements against estimates rather than a contest of impressions.
### 7.1 The Evidentiary Checklist
@@ -366,7 +366,7 @@ A paper that consists only of design supplies none of these. Design is not evide
### 7.2 Complete Implementation
-The gate requires a complete library with benchmarks, unit tests, and documentation - not a sketch, not a header of stubs, not an API description without a build. The committee historically accepted proposals without implementations because producing them was expensive; that calibration is stale. In the author's experience building and maintaining the two AI-assisted library codebases disclosed in Section 1, generative AI has collapsed the cost of a demonstration library from months of skilled labor to days, and the evidence bar rises to match the fallen cost. A proposal without an implementation is no longer a proposal that could not afford one; it is a proposal that chose not to produce one. The same shift applies to language proposals: a proof-of-concept compiler fork is feasible for any feature whose complexity is appropriate for standardization, and a feature for which no proof-of-concept fork proves feasible even with AI assistance has documented its own implementation cost. [P4023R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4023r0.pdf)[118] addresses AI in the committee process broadly; the observation here is narrower - the cost of producing evidence dropped, so the excuse of cost is gone.
+The gate requires a complete library with benchmarks, unit tests, and documentation, rather than a sketch, a header of stubs, or an API description without a build. Historically the committee accepted proposals without implementations because producing them was expensive, and that calibration is stale. In the author's experience building and maintaining the two AI-assisted library codebases disclosed in Section 1, generative AI has collapsed the cost of a demonstration library from months of skilled labor to days, and the evidence bar rises to match the fallen cost. A proposal without an implementation is no longer a proposal that could not afford one. It is a proposal that chose not to produce one. The same shift applies to language proposals: a proof-of-concept compiler fork is feasible for any feature whose complexity is appropriate for standardization, and a feature for which no proof-of-concept fork proves feasible even with AI assistance has documented its own implementation cost. [P4023R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4023r0.pdf)[118] addresses AI in the committee process broadly. The observation here is narrower - the cost of producing evidence dropped, so the excuse of cost is gone.
### 7.3 Steel Man Against Standardization
@@ -378,11 +378,11 @@ A proposal that does not contain this section has not considered the alternative
The proposal must contain the strongest case for the alternative designs that solve the same problem differently: what they provide that this design does not, what their advantages are, and why this design was chosen over them.
-The cost of omitting this section is documented. [P4094R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4094r0.pdf)[6] records that three deployed executor models were unified into P0443R0 with no analysis of what each domain lost, and [P4098R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4098r0.pdf)[8] records six unification claims supported by one hypothetical code snippet. A proposal that does not steel man the competition has not demonstrated that it examined the design space; the room then examines it live, at the review prices established in Section 3.
+The cost of omitting this section is documented. [P4094R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4094r0.pdf)[6] records that three deployed executor models were unified into P0443R0 with no analysis of what each domain lost, and [P4098R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4098r0.pdf)[8] records six unification claims supported by one hypothetical code snippet. A paper that omits this section has not demonstrated that it examined the design space, so the room examines it live, at the review prices established in Section 3.
### 7.5 Accountability Artifacts
-Five artifacts close the loop after adoption, and they are stated here compactly because the companion papers carry their full arguments. Post-adoption metrics: the paper defines, before adoption, how the committee will know whether the component worked - deployment rate across implementations, adoption surveys, defect rates, teaching reports. Forced retrospective: a look-back at two releases or six years, whichever comes first; [P4046R0](https://isocpp.org/files/papers/P4046R0.pdf)[5] records the current state - "The committee has no retrospectives, no formal onboarding, no written institutional memory." Decision record: rationale, alternatives, dissent, and revisit conditions; [P4050R0](https://isocpp.org/files/papers/D4050R0.pdf)[4] Section 2 records that today none of the four is recorded. Domain coverage attestation: which domains were present for the poll, as metadata on the record; the P2453R0 episode in Section 4.1 is the motivating case. Prediction registry: claims made during adoption - "this will enable X", "this covers networking" - recorded with falsifiable criteria and a revisit date; [P4098R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4098r0.pdf)[8] surveys a decade of such claims and finds most received no published follow-up.
+Five artifacts close the loop after adoption, and they are stated here compactly because the companion papers carry their full arguments. Post-adoption metrics: the paper defines, before adoption, how the committee will know whether the component worked - deployment rate across implementations, adoption surveys, defect rates, teaching reports. Forced retrospective: a look-back at two releases or six years, whichever comes first. [P4046R0](https://isocpp.org/files/papers/P4046R0.pdf)[5] records the current state - "The committee has no retrospectives, no formal onboarding, no written institutional memory." Decision record: rationale, alternatives, dissent, and revisit conditions. [P4050R0](https://isocpp.org/files/papers/D4050R0.pdf)[4] Section 2 records that today none of the four is recorded. Domain coverage attestation: which domains were present for the poll, as metadata on the record. The P2453R0 episode in Section 4.1 is the motivating case. Prediction registry: claims made during adoption - "this will enable X", "this covers networking" - recorded with falsifiable criteria and a revisit date. [P4098R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4098r0.pdf)[8] surveys a decade of such claims and finds most received no published follow-up.
---
@@ -398,37 +398,37 @@ The sympathetic answer came from inside the batteries camp. Titus Winters, [resp
### "C++ has no package manager, so the standard library must carry more"
-The strongest public form of the argument appeared on [r/cpp in 2022](https://www.reddit.com/r/cpp/comments/scri8u/why_do_you_like_c/hucxyvm/)[122]: "C++ is almost unique in having a shitty standard library that you cannot build networked software with, and no standard package manager ..."
+On [r/cpp in 2022](https://www.reddit.com/r/cpp/comments/scri8u/why_do_you_like_c/hucxyvm/)[122], the strongest public form of the argument appeared: "C++ is almost unique in having a shitty standard library that you cannot build networked software with, and no standard package manager ..."
-The Rust record answers the premise directly, from the [Rust internals forum](https://internals.rust-lang.org/t/expansion-of-standard-library/10475)[123]: "When all 3rd party code is just as easy to depend on as the standard library, there's no longer any special availability advantage to being in the standard library. ... once it's on crates.io, then 'everyone has it' in practice already." The implementer's answer is on record from the maintainer of Microsoft's STL, [writing on r/cpp in 2024](https://www.reddit.com/r/cpp/comments/19b1brk/why_does_c_get_so_much_hate_is_it_really_that_bad/kiox6z0/)[124]: "The Standard Library is the worst package manager, and Standard Library maintainers aren't domain experts. What you should want is a good networking library available through a good package manager (e.g. vcpkg) - you shouldn't want it to be in the Standard, where it'll be maintained by generalists (like me!) instead of proper specialists, updated on a toolset update cadence ... and subject to the usual ABI restrictions." His example is networking, the domain of the author's disclosed stake, and the gate model does not argue with him: Section 5.7 prices his objection as the Penalty a networking component must survive at sufficiency. The availability premise also fails empirically: Section 5.5 measured standardized-but-unavailable at one to nine-plus years per vendor, and sometimes never. Bjarne Stroustrup drew the conclusion at the [CppCon 2020 fireside chat](https://www.youtube.com/watch?v=lil4xfpmnF4&t=1643s)[125]: "If we could get a decent package manager and distribution system, I predict [the C++ Standard Library] would have a logger within a year. Because there are several good ones."
+From the [Rust internals forum](https://internals.rust-lang.org/t/expansion-of-standard-library/10475)[123], the Rust record answers the premise directly: "When all 3rd party code is just as easy to depend on as the standard library, there's no longer any special availability advantage to being in the standard library. ... once it's on crates.io, then 'everyone has it' in practice already." The implementer's answer is on record from the maintainer of Microsoft's STL, [writing on r/cpp in 2024](https://www.reddit.com/r/cpp/comments/19b1brk/why_does_c_get_so_much_hate_is_it_really_that_bad/kiox6z0/)[124]: "The Standard Library is the worst package manager, and Standard Library maintainers aren't domain experts. What you should want is a good networking library available through a good package manager (e.g. vcpkg) - you shouldn't want it to be in the Standard, where it'll be maintained by generalists (like me!) instead of proper specialists, updated on a toolset update cadence ... and subject to the usual ABI restrictions." His example is networking, the domain of the author's disclosed stake, and the gate model does not argue with him: Section 5.7 prices his objection as the Penalty a networking component must survive at sufficiency. The availability premise also fails empirically: Section 5.5 measured standardized-but-unavailable at one to nine-plus years per vendor, and sometimes never. Bjarne Stroustrup drew the conclusion at the [CppCon 2020 fireside chat](https://www.youtube.com/watch?v=lil4xfpmnF4&t=1643s)[125]: "If we could get a decent package manager and distribution system, I predict [the C++ Standard Library] would have a logger within a year. Because there are several good ones."
### "Standard blessing drives adoption and awareness beyond what downloads achieve"
-The linalg proposal states the strong form in [P1673R13](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p1673r13.html)[50]: "The set of linear algebra operations in this proposal are derived from a well-established, standard set of algorithms that has changed very little in decades. It is one of the strongest possible examples of standardizing existing practice that anyone could bring to C++."
+In [P1673R13](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p1673r13.html)[50], the linalg proposal states the strong form: "The set of linear algebra operations in this proposal are derived from a well-established, standard set of algorithms that has changed very little in decades. It is one of the strongest possible examples of standardizing existing practice that anyone could bring to C++."
-The proposal's own text carries the answer: the same paper states that "The BLAS is a standard that codifies decades of existing practice. ... Optimized third-party BLAS implementations with liberal software licenses exist" - the Coordination Problem was solved outside the language standard, decades ago. The post-adoption record completes it: two and a half years on, no vendor ships `std::linalg` (Section 5.6), while the unblessed alternatives hold the field - [Eigen's own user list](https://libeigen.gitlab.io/)[126] names TensorFlow, Ceres, ROS, and Stan, reach earned without any standard's blessing, and curl reached twenty billion installations by adoption, not admission. Blessing without vendor implementation is a promise, and Section 5.5 measured the wait between promise and delivery in years.
+The proposal's own text supplies the rebuttal: the same paper states that "The BLAS is a standard that codifies decades of existing practice. ... Optimized third-party BLAS implementations with liberal software licenses exist" - the Coordination Problem was solved outside the language standard, decades ago. The post-adoption record completes it: two and a half years on, no vendor ships `std::linalg` (Section 5.6), while the unblessed alternatives hold the field - [Eigen's own user list](https://libeigen.gitlab.io/)[126] names TensorFlow, Ceres, ROS, and Stan, reach earned without any standard's blessing, and curl reached twenty billion installations through adoption alone. Blessing without vendor implementation is a promise, and Section 5.5 measured the wait between promise and delivery in years.
### "Standardization worked fine for format"
Victor Zverovich, the author, [wrote in 2019](https://vitaut.net/posts/2019/std-format-cpp20/)[127]: "Contrary to the usual 'design-by-committee' narrative, the standardization process was tremendously beneficial both for the proposal and the {fmt} library, resulting in numerous improvements."
-The claim is true and the paper's Section 5.6 already accepts it: format is the best-executed library standardization of the modern era. The objection fails as a generalization, not as a fact. The best case required six and a half years of prior field deployment, an author who carried the work through, and a retroactive defect-report window that existed only because no vendor had shipped yet - and it still trails its ecosystem original on features (Table 5), performance, and availability. Jason Turner's practitioner comparison in [C++ Weekly episode 341](https://www.youtube.com/watch?v=zc6B-j0S9Iw)[128] lands the same way: "if you're in an environment where you do have some sort of package manager or some way to take advantage of lib {fmt}, then I think it wins in this comparison here." When the best case pays the Penalty, the median case pays more.
+The claim is true and the paper's Section 5.6 already accepts it: format is the best-executed library standardization of the modern era. Only as a generalization does the objection fail. The best case required six and a half years of prior field deployment, an author who carried the work through, and a retroactive defect-report window that existed only because no vendor had shipped yet - and it still trails its ecosystem original on features (Table 5), performance, and availability. Jason Turner's practitioner comparison in [C++ Weekly episode 341](https://www.youtube.com/watch?v=zc6B-j0S9Iw)[128] lands the same way: "if you're in an environment where you do have some sort of package manager or some way to take advantage of lib {fmt}, then I think it wins in this comparison here." When the best case pays the Penalty, the median case pays more.
### "The gate adds bureaucracy to an already slow process"
-The gate's cost is one calibration discussion per new component - not per revision - and the arithmetic runs at mailing volume. The post-Wrocław mailing carried 107 P-papers (Section 3.1), most of them revisions of components already calibrated; at ten minutes for each genuinely new component, a mailing's calibration load is measured in a few hours of assembled-room time. The break-even against Section 3's prices is short: LEWG's published cadence is one or two papers per ninety-minute telecon, with proposals returning across meetings, so a single gated-out component that would otherwise consume two telecons repays dozens of calibrations. The larger return is not the review hours of any one proposal but the end of re-litigation: the executor lineage of Section 4.3 asked the belongs-question across 115 papers and fourteen years because no verdict ever attached to the component; the gate attaches one at paper one - in that class's case, plausibly admit, on the evidence the calibration would have required up front. The model also does not add a judgment the committee does not already make - every scheduling decision embeds an unrecorded belongs-or-not judgment today. The gate records it.
+The gate's cost is one calibration discussion per new component - not per revision - and the arithmetic runs at mailing volume. The post-Wrocław mailing carried 107 P-papers (Section 3.1), most of them revisions of components already calibrated. At ten minutes for each new component, a mailing's calibration load is measured in a few hours of assembled-room time. Against Section 3's prices the break-even is short: LEWG's published cadence is one or two papers per ninety-minute telecon, with proposals returning across meetings, so a single gated-out component that would otherwise consume two telecons repays dozens of calibrations. The larger return is the end of re-litigation rather than the review hours of any one proposal: the executor lineage of Section 4.3 asked the belongs-question across 115 papers and fourteen years because no verdict ever attached to the component. At paper one the gate attaches one - in that class's case, plausibly admit, on the evidence the calibration would have required up front. The model also adds no judgment the committee does not already make - every scheduling decision embeds an unrecorded belongs-or-not judgment today. The gate records it.
### "The estimates are subjective"
-They are rough by design, and the ordinal sufficiency principle of Section 5.3 is the answer: the admission rule is a ranking, rankings survive order-of-magnitude error when the gaps are large, and the gaps are large. Soft numbers force stated estimates that can be argued about; the current alternative is no numbers, which forces nothing. The objection describes the status quo, not the model.
+They are rough by design, and the ordinal sufficiency principle of Section 5.3 is the answer: the admission rule is a ranking, rankings survive order-of-magnitude error when the gaps are large, and the gaps are large. Soft numbers force stated estimates that can be argued about. The current alternative is no numbers, which forces nothing. The objection describes the status quo, not the model.
---
## 9. Conclusion
-The criteria question is the committee's own, asked in 2001 and open since. N1314 recorded that criteria "will need to be developed"; P0939R0 recorded that the founding criteria "didn't have much effect"; P2000R4 encouraged the discussion to start in 2022. This paper is input to that discussion.
+The criteria question is the committee's own, asked in 2001 and open since. N1314 recorded that criteria "will need to be developed". P0939R0 recorded that the founding criteria "didn't have much effect". P2000R4 encouraged the discussion to start in 2022. This paper is input to that discussion.
-The gate model asks the evaluating room to calibrate its expectation before advocacy frames it, and to measure the paper against the calibrated expectation rather than against the persistence of its authors. The library instruments - the Coordination Problem, the GitHub Test, the Reach Test, the Complexity Budget, the Standardization Penalty, the Interaction Tax, Return on Complexity - are each measurable from public data, and each is calibrated in this paper against components the committee already admitted and the record those admissions produced. The language instruments are not supplied here; that expertise lives with the delegates who implement compilers and teach the language, and Section 6 marks the space for it.
+The gate model asks the evaluating room to calibrate its expectation before advocacy frames it, and to measure the paper against the calibrated expectation rather than against the persistence of its authors. The library instruments - the Coordination Problem, the GitHub Test, the Reach Test, the Complexity Budget, the Standardization Penalty, the Interaction Tax, Return on Complexity - are each measurable from public data, and each is calibrated in this paper against components the committee already admitted and the record those admissions produced. Here the language instruments are not supplied. That expertise lives with the delegates who implement compilers and teach the language, and Section 6 marks the space for it.
What the record shows without any model is already on the table: mailings the Direction Group calls unmanageable for any individual reader, chairs answering throughput questions with expectation management, a 2,679-page working draft that is 77 percent library text, a name index that quadrupled in fifteen years, and component after component that stopped competing once it shipped in the standard. A committee that operates a gate spends review - its scarcest resource, by its own accounting - only on components that can repay it. The next work is the language instruments, and it belongs to the delegates Section 6 names.
@@ -566,13 +566,13 @@ The author thanks Joaquín M López Muñoz and Peter Dimov for
[62] [libstdc++ manual: Dual ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html) - (GNU project, 2026).
-[63] [microsoft/STL issue 1652](https://github.com/microsoft/STL/issues/1652) - ": Excessive locking is slow" (Microsoft STL maintainers, 2021).
+[63] [microsoft/STL issue 1652](https://github.com/microsoft/STL/issues/1652) - "<locale>: Excessive locking is slow" (Microsoft STL maintainers, 2021).
[64] [P1433R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1433r0.pdf) - "Compile Time Regular Expressions" (Hana Dusíková, 2019).
[65] [llvm/llvm-project issue 60991](https://github.com/llvm/llvm-project/issues/60991) - "[optimization] libc++ std::regex and std::regex_match very slow, ~10x slower than libstdc++" (LLVM project, 2023).
-[66] [microsoft/STL issue 405](https://github.com/microsoft/STL/issues/405) - ": vNext overhaul" (Microsoft STL maintainers, 2019).
+[66] [microsoft/STL issue 405](https://github.com/microsoft/STL/issues/405) - "<regex>: vNext overhaul" (Microsoft STL maintainers, 2019).
[67] [GCC bug 118408](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118408) - "regex does not work under dual ABI" (GCC Bugzilla, 2025).
@@ -610,7 +610,7 @@ The author thanks Joaquín M López Muñoz and Peter Dimov for
[84] [cplusplus/papers issue 919](https://github.com/cplusplus/papers/issues/919) - WG21 paper tracker record for P2216 (2021).
-[85] [microsoft/STL issue 1802](https://github.com/microsoft/STL/issues/1802) - ": Improve performance" (Microsoft STL maintainers, 2021).
+[85] [microsoft/STL issue 1802](https://github.com/microsoft/STL/issues/1802) - "<format>: Improve performance" (Microsoft STL maintainers, 2021).
[86] [performance-tuning benchmark commit 29bfb1c](https://github.com/mattgodbolt/performance-tuning/commit/29bfb1c421076e8339d7d9751d0b1c639ebd0d1c) - (Matt Godbolt, 2026).
@@ -628,7 +628,7 @@ The author thanks Joaquín M López Muñoz and Peter Dimov for
[93] [LWG issue 4302](https://cplusplus.github.io/LWG/issue4302) - "Problematic vector_sum_of_squares wording" (LWG, 2026).
-[94] [microsoft/STL issue 4170](https://github.com/microsoft/STL/issues/4170) - "P1673R13 " (Microsoft STL maintainers, 2023).
+[94] [microsoft/STL issue 4170](https://github.com/microsoft/STL/issues/4170) - "P1673R13 <linalg>" (Microsoft STL maintainers, 2023).
[95] [kokkos/stdBLAS](https://github.com/kokkos/stdblas) - Reference implementation of P1673 (Kokkos project, 2026).
diff --git a/source/2026-07-july/d4251-ioawaitable-cuda.md b/source/2026-07-july/d4251-ioawaitable-cuda.md
index ccb1932..c37e83b 100644
--- a/source/2026-07-july/d4251-ioawaitable-cuda.md
+++ b/source/2026-07-july/d4251-ioawaitable-cuda.md
@@ -12,7 +12,7 @@ reply-to:
A protocol handler compiled once writes to a TCP socket or to GPU device memory without recompilation.
-C++ has a standard model for asynchronous execution in `std::execution`, validated in GPU kernel dispatch and heterogeneous scheduling; the byte-oriented data movement that feeds those kernels - host-device memcpy, inter-GPU collectives over NVLink, RDMA transfers between nodes, and TCP sockets - has no standard interface. These four transports share a common async completion model, and the IoAwaitable protocol captures it with an ABI-stable, type-erased interface. Independent projects at NVIDIA Labs, the University of Wisconsin-Madison, and Schrödinger converged on the same coroutine-based async completion pattern for GPU data movement without coordination, and CERN ported a GPU track-reconstruction pipeline onto the IoAwaitable protocol directly. Bidirectional bridges connect IoAwaitables and senders where byte-oriented I/O meets GPU dispatch, so each model serves its natural domain.
+C++ has a standard model for asynchronous execution in `std::execution`, validated in GPU kernel dispatch and heterogeneous scheduling. The byte-oriented data movement that feeds those kernels - host-device memcpy, inter-GPU collectives over NVLink, RDMA transfers between nodes, and TCP sockets - has no standard interface. These four transports share a common async completion model, and the IoAwaitable protocol captures it with an ABI-stable, type-erased interface. Independent projects at NVIDIA Labs, the University of Wisconsin-Madison, and Schrödinger converged on the same coroutine-based async completion pattern for GPU data movement without coordination, and CERN ported a GPU track-reconstruction pipeline onto the IoAwaitable protocol directly. Bidirectional bridges connect IoAwaitables and senders where byte-oriented I/O meets GPU dispatch, so each model serves its natural domain.
---
@@ -32,13 +32,13 @@ The author developed and maintains [Capy](https://github.com/cppalliance/capy)[3] specifies the protocol this paper examines; P4088R1[4], P4091R1[5], P4092R1[6], P4093R1[7], and P4123R0[8] examine adjacent questions.
+Companion papers: [P4003R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4003r3.pdf)[3] specifies the protocol this paper examines. P4088R1[4], P4091R1[5], P4092R1[6], P4093R1[7], and P4123R0[8] examine adjacent questions.
-The CUDA data-movement examples were produced with AI assistance and are presented as a research exercise, not as expert testimony. A compileable demonstration accompanies the paper.[9]
+The CUDA data-movement examples were produced with AI assistance and are presented as a research exercise. A compileable demonstration accompanies the paper.[9]
This paper asks for nothing.
@@ -48,13 +48,13 @@ This paper asks for nothing.
The paper reports five findings:
-1. Four data-movement APIs that cross four different hardware boundaries - `cudaMemcpyAsync`, NCCL collectives, RDMA verbs, and TCP sockets - fit one abstract interface: submit a buffer, receive an async completion, dispatch a compound result. POSIX and RDMA present the compound result natively; for CUDA and NCCL the wrapper synthesizes it (Sections 4 and 12).
+1. Four data-movement APIs that cross four different hardware boundaries - `cudaMemcpyAsync`, NCCL collectives, RDMA verbs, and TCP sockets - fit one abstract interface: submit a buffer, receive an async completion, dispatch a compound result. POSIX and RDMA present the compound result natively. For CUDA and NCCL the wrapper synthesizes it (Sections 4 and 12).
2. The IoAwaitable protocol captures this interface, and the notification mechanism is a free variable: callback, event polling, and deferred synchronization all satisfy it (Section 6). Working `cuda_stream` and `cuda_device_stream` demonstrations accompany the paper (Sections 8-9).
-3. Under type erasure, the awaitable form allocates nothing per operation and has a fixed vtable, which yields an ABI-stable stream interface; the sender form heap-allocates per operation (Sections 10-11).
+3. Under type erasure, the awaitable form allocates nothing per operation and has a fixed vtable, which yields an ABI-stable stream interface. The sender form heap-allocates per operation (Sections 10-11).
4. Eight independent projects - at NVIDIA Labs, the University of Wisconsin-Madison, Oddity AI, Schrödinger, the EPEXA project, and in the RDMA ecosystem - converged on coroutine-based async completion for data movement without coordination, and CERN ported its traccc track-reconstruction pipeline onto the IoAwaitable protocol itself (Section 15).
5. The sender model's strengths - zero-allocation compile-time composition, scheduler portability, structured concurrency for dynamic fan-out - are strongest in kernel dispatch, and bidirectional bridges connect the two domains (Sections 3, 16, and 18).
-Related work beyond the papers named above: P4088R1[4] analyzes what C++20 coroutines already provide the standard, P4091R1[5] the error models of regular C++ and the sender sub-language, P4123R0[8] the cost of senders for coroutine I/O, and P4092R1[6] and P4093R1[7] the two bridge directions between senders and coroutines.
+Related work beyond the papers named above: P4088R1[4] analyzes what C++20 coroutines already buy the standard, P4091R1[5] the error models of regular C++ and the sender sub-language, P4123R0[8] the cost of senders for coroutine I/O, and P4092R1[6] and P4093R1[7] the two bridge directions between senders and coroutines.
The paper's assumptions: the CUDA examples were produced with AI assistance and are offered for evaluation by domain experts rather than as expert testimony (Section 1); the benchmark figures in Section 10 come from the measurement setup documented in P4088R1[4]; and the surveys of sender-based networking (Section 14) and of convergent projects (Section 15) are bounded by the public record their methods searched.
@@ -84,7 +84,7 @@ Four APIs that move bytes across different hardware boundaries share a common as
**TCP `read`/`write`.** Bytes between hosts. Completion via IOCP (I/O completion ports) or io_uring, readiness via epoll.
-All four share the same structural pattern: submit a buffer of bytes, receive async completion via callback, poll, or file descriptor, receive a compound result (status plus byte count), and dispatch the result to the application thread via a reactor. The hardware boundaries differ - PCIe, NVLink, InfiniBand, Ethernet - and the abstract interface does not. Two of the four report the compound result natively (POSIX, RDMA); for CUDA and NCCL the wrapper synthesizes the byte count (Section 12). IoAwaitable handles all four with the same mechanism; Section 9 demonstrates a protocol handler written against this interface, and Section 11 traces the ABI consequence.
+All four share the same structural pattern: submit a buffer of bytes, receive async completion via callback, poll, or file descriptor, receive a compound result (status plus byte count), and dispatch the result to the application thread via a reactor. The hardware boundaries differ - PCIe, NVLink, InfiniBand, Ethernet - and the abstract interface does not. Two of the four report the compound result natively (POSIX, RDMA). For CUDA and NCCL the wrapper synthesizes the byte count (Section 12). IoAwaitable handles all four with the same mechanism. Section 9 demonstrates a protocol handler written against this interface, and Section 11 traces the ABI consequence.
The type vocabulary builds from this pattern:
@@ -96,13 +96,13 @@ The compound result type `io_result` delivers both status and byte
auto [ec, n] = co_await stream.write_some(buf);
```
-The `WriteStream` concept requires `write_some(buffers)` returning an `IoAwaitable` whose `await_resume` returns `io_result`. The `WriteSink` concept refines `WriteStream`, adding `write(buffers)` for complete-buffer writes and `write_eof()` for graceful shutdown.
+`WriteStream` requires `write_some(buffers)` returning an `IoAwaitable` whose `await_resume` returns `io_result`, and `WriteSink` refines it with `write(buffers)` for complete-buffer writes and `write_eof()` for graceful shutdown.
-The type-erased wrappers `any_write_stream` and `any_write_sink` wrap any `WriteStream` or `WriteSink` (respectively) behind a vtable whose per-operation entries - `await_ready`, `await_suspend`, `await_resume`, and `destroy` - have fixed signatures. The awaitable has a fixed, compile-time-known size, so the wrapper preallocates a single awaitable buffer at construction and reuses it for every operation; Section 10 explains why and analyzes the structural consequences, and Section 11 draws the ABI conclusion.
+The type-erased wrappers `any_write_stream` and `any_write_sink` wrap any `WriteStream` or `WriteSink` (respectively) behind a vtable whose per-operation entries - `await_ready`, `await_suspend`, `await_resume`, and `destroy` - have fixed signatures. The awaitable has a fixed, compile-time-known size, so the wrapper preallocates a single awaitable buffer at construction and reuses it for every operation. Section 10 explains why and analyzes the structural consequences, and Section 11 draws the ABI conclusion.
P2300R10[10] Section 4.15 agrees with the user-facing pattern: "we expect that coroutines and awaitables will be how a great many will choose to express their asynchronous code."
-One completion model spans all four transports, and the type vocabulary above expresses it; the rest of the paper examines what follows from that fact.
+One completion model spans all four transports, and the type vocabulary above expresses it. The rest of the paper examines what follows from that fact.
## 5. The IoAwaitable Protocol
@@ -157,11 +157,11 @@ CUDA streams are in-order queues where operations execute sequentially.[23]
`cudaLaunchHostFunc` is the recommended replacement for `cudaStreamAddCallback`, which is slated for deprecation.[23] Its host function fires on a dedicated internal CPU thread created by the CUDA driver, not the application thread.[26][27] It cannot call CUDA APIs and must not create transitive dependencies on outstanding CUDA work.
-The choice among the three is a scaling tradeoff, not a correctness one. All three satisfy `IoAwaitable` and, driving the same GPU pipeline, produce identical results at runtime; the accompanying notification-strategies example[9] demonstrates this directly. The slides of a CHEP (Computing in High Energy and Nuclear Physics) 2026 contribution on trigger scheduling[28] report that callback-based handlers scale poorly for multi-threaded jobs, while event polling and deferred synchronization are viable alternatives. In a multi-threaded framework, prefer polling or deferred synchronization; use the callback for its simplicity in low-concurrency settings.
+Among the three, the choice is a scaling tradeoff. All three satisfy `IoAwaitable` and, driving the same GPU pipeline, produce identical results at runtime, which the accompanying notification-strategies example[9] demonstrates directly. The slides of a CHEP (Computing in High Energy and Nuclear Physics) 2026 contribution on trigger scheduling[28] report that callback-based handlers scale poorly for multi-threaded jobs, while event polling and deferred synchronization are viable alternatives. In a multi-threaded framework, prefer polling or deferred synchronization. Use the callback for its simplicity in low-concurrency settings.
This is the same structural pattern as epoll readiness events or IOCP and io_uring completions arriving on arbitrary threads. In all cases, an async operation completes on a thread that is not the application's, and the application must dispatch the result to the correct execution context. This is the exact problem that Capy's executor-affinity dispatch was designed to solve.
-Each mechanism is a distinct `await_suspend` over the same protocol. The excerpts below are from the accompanying notification-strategies example,[9] which compiles and runs; trimmed to the suspension point, the three awaitables differ only in how they arrange for the continuation to be posted back through `env->executor`:
+Each mechanism is a distinct `await_suspend` over the same protocol. The excerpts below are from the accompanying notification-strategies example,[9] which compiles and runs. Trimmed to the suspension point, the three awaitables differ only in how they arrange for the continuation to be posted back through `env->executor`:
```cpp
// Callback: a CUDA host function re-posts through the executor.
@@ -204,7 +204,7 @@ deferred_sync_awaitable::await_suspend(
}
```
-The remainder of this paper uses the callback mechanism as the running example because it is the simplest to present; the polling and deferred-synchronization awaitables appear in full in the accompanying example.[9] The mechanism is a parameter of the awaitable; the protocol and the calling code are identical across all three.
+The remainder of this paper uses the callback mechanism as the running example because it is the simplest to present. Polling and deferred-synchronization awaitables appear in full in the accompanying example.[9] The mechanism is a parameter of the awaitable. Across all three, the protocol and the calling code are identical.
## 7. Hand-Rolled Awaitables Lose the Execution Environment
@@ -239,7 +239,7 @@ This works. But `resume()` executes on the CUDA driver callback thread. There is
## 8. `cuda_stream`: Data Movement as IoAwaitables
-The `cuda_stream` class wraps a CUDA stream handle and provides data-movement member functions that return IoAwaitables. The class follows the Rule of Five (copy deleted, move implemented, null-guarded destructor). The helper function `make_cuda_error`, defined by the accompanying demonstration[9] rather than by Capy, converts a `cudaError_t` to `std::error_code` via a CUDA error category.
+The `cuda_stream` class wraps a CUDA stream handle and provides data-movement member functions that return IoAwaitables. It follows the Rule of Five (copy deleted, move implemented, null-guarded destructor). The helper function `make_cuda_error`, defined by the accompanying demonstration[9] rather than by Capy, converts a `cudaError_t` to `std::error_code` via a CUDA error category.
The key mechanism is `resume_ctx`: a pre-allocated member that captures the executor and continuation for `cudaLaunchHostFunc`. The `on_complete` callback posts the continuation back to the application's executor, providing the executor-affinity dispatch that the hand-rolled awaitable in Section 7 lacks.
@@ -355,9 +355,9 @@ public:
};
```
-The `resume_ctx` is a pre-allocated member of `cuda_stream`, not heap-allocated per operation. This is safe under a single-owner discipline, which is a precondition rather than a consequence of suspension: one coroutine owns the `cuda_stream`, and because that coroutine suspends on each `co_await`, only one operation is in flight at a time. Two coroutines sharing a `cuda_stream` would race on the pre-allocated state; the same contract governs Capy's sockets and their pre-allocated op states in the networking domain. The CUDA Programming Guide[23] confirms that operations in a stream execute in enqueue order, and the CUDA Runtime API documentation[15] states that `cudaLaunchHostFunc` callbacks block later work in the stream until they return.[29] Under the discipline, the pre-allocated `resume_ctx` is never accessed concurrently.
+The `resume_ctx` lives inside `cuda_stream` as a pre-allocated member, so no per-operation heap allocation occurs. This is safe under a single-owner discipline, which is a precondition rather than a consequence of suspension: one coroutine owns the `cuda_stream`, and because that coroutine suspends on each `co_await`, only one operation is in flight at a time. Two coroutines sharing a `cuda_stream` would race on the pre-allocated state. In the networking domain, the same contract governs Capy's sockets and their pre-allocated op states. The CUDA Programming Guide[23] confirms that operations in a stream execute in enqueue order, and the CUDA Runtime API documentation[15] states that `cudaLaunchHostFunc` callbacks block later work in the stream until they return.[29] Under the discipline, the pre-allocated `resume_ctx` is never accessed concurrently.
-`cudaLaunchHostFunc` has documented constraints that production code must respect. The callback must not call CUDA APIs or synchronize on outstanding CUDA work.[15] A single CUDA-internal worker thread may service all callbacks across all streams; on loaded systems, OS scheduling can starve this thread, producing latency spikes up to 12ms between callback completion and stream resumption.[30] The 12ms figure is a single user report that NVIDIA's forum responder could not reproduce on other GPU models. If the callback blocks on a user lock while the CUDA launch queue is full, the enqueuing thread blocks too, producing deadlock.[31] Notification is unidirectional: `cudaLaunchHostFunc` provides stream-to-CPU notification only and cannot make the stream wait for a CPU-side signal.[32] These constraints apply equally to any pattern that uses `cudaLaunchHostFunc` for completion notification, including the hand-rolled awaitable in Section 7 and any sender-based wrapper that uses the same mechanism. They do not invalidate the pattern but they bound its applicability in high-throughput pipelines. The first three are specific to the callback mechanism, and the polling and deferred-synchronization awaitables of Section 6 sidestep them; the fourth, unidirectional notification, is a property of GPU-to-host completion generally. The CHEP 2026 slides[28] show the alternatives scaling better in multi-threaded jobs, and CERN's traccc port[33] implements all three strategies over this one protocol so the mechanism can be selected per deployment. The IoAwaitable protocol is the same in every case; only the notification source changes.
+`cudaLaunchHostFunc` has documented constraints that production code must respect. The callback must not call CUDA APIs or synchronize on outstanding CUDA work.[15] A single CUDA-internal worker thread may service all callbacks across all streams. On loaded systems, OS scheduling can starve this thread, producing latency spikes up to 12ms between callback completion and stream resumption.[30] The 12ms figure is a single user report that NVIDIA's forum responder could not reproduce on other GPU models. If the callback blocks on a user lock while the CUDA launch queue is full, the enqueuing thread blocks too, producing deadlock.[31] Notification is unidirectional: `cudaLaunchHostFunc` provides stream-to-CPU notification only and cannot make the stream wait for a CPU-side signal.[32] These constraints apply equally to any pattern that uses `cudaLaunchHostFunc` for completion notification, including the hand-rolled awaitable in Section 7 and any sender-based wrapper that uses the same mechanism. They do not invalidate the pattern but they bound its applicability in high-throughput pipelines. The first three are specific to the callback mechanism, and the polling and deferred-synchronization awaitables of Section 6 sidestep them. Unidirectional notification, the fourth, is a property of GPU-to-host completion generally. The CHEP 2026 slides[28] show the alternatives scaling better in multi-threaded jobs, and CERN's traccc port[33] implements all three strategies over this one protocol so the mechanism can be selected per deployment. In every case, the IoAwaitable protocol is the same. Only the notification source changes.
One caveat: `cudaMemcpyAsync` is only truly asynchronous with pinned (page-locked) memory.[34] With pageable memory allocated via `malloc` or `new`, the call blocks the host thread despite the `Async` suffix.[35] For multi-gigabyte model weight transfers, this distinction matters.
@@ -377,7 +377,7 @@ When using grouped NCCL calls, `cudaLaunchHostFunc` must be enqueued after `nccl
## 9. `cuda_device_stream`: GPU Memory as a WriteStream
-The `cuda_device_stream` class reshapes the memcpy pattern to satisfy the `WriteStream` concept, enabling GPU device memory to hide behind `any_write_stream`. Error handling delivers errors via `io_result` rather than exceptions:
+The `cuda_device_stream` class reshapes the memcpy pattern to satisfy the `WriteStream` concept, enabling GPU device memory to hide behind `any_write_stream`. Errors travel through `io_result` instead of exceptions:
```cpp
class cuda_device_stream
@@ -516,56 +516,56 @@ any_write_stream dest(&sock); // non-owning
co_await ingest(dest, payload); // -> network
```
-The `ingest` handler and the GPU leg are exercised by the accompanying demonstration,[9] with an in-memory `WriteStream` standing in for the socket; the TCP leg is the same pattern over Capy's existing socket streams.
+The `ingest` handler and the GPU leg are exercised by the accompanying demonstration,[9] with an in-memory `WriteStream` standing in for the socket. The TCP leg is the same pattern over Capy's existing socket streams.
The algorithm in `protocol.cpp` is compiled once. At link time, swap the transport. No recompilation. Zero per-operation allocation in all cases, by the fixed-size-awaitable mechanism of Section 10. Section 11 traces the design lineage and the ABI consequence.
## 10. The Type Erasure Asymmetry
-The link-time polymorphism shown in Section 9 is a structural property of how the two models interact with the type system.
+Shown in Section 9, the link-time polymorphism is a structural property of how the two models interact with the type system.
-**Awaitable under type erasure.** `await_suspend` takes `coroutine_handle<>` - type-erased by the language itself. The awaitable has a fixed, compile-time-known size. The type-erased wrapper preallocates one awaitable buffer at construction and placement-constructs each operation into it; its per-operation vtable entries - `await_ready`, `await_suspend`, `await_resume`, `destroy` - have fixed signatures. Result: zero per-operation allocation, even through a virtual stream interface.
+**Awaitable under type erasure.** `await_suspend` takes `coroutine_handle<>` - type-erased by the language itself. The awaitable has a fixed, compile-time-known size. At construction, the type-erased wrapper preallocates one awaitable buffer and placement-constructs each operation into it. Its per-operation vtable entries - `await_ready`, `await_suspend`, `await_resume`, `destroy` - have fixed signatures. Result: zero per-operation allocation, even through a virtual stream interface.
**Sender under type erasure.** `connect(sender, receiver)` produces an operation state whose type depends on both the sender and the receiver. Under type erasure (`any_sender`), the receiver's type is unknown at compile time. The operation state's size is unknown. The coroutine frame cannot absorb it. `any_sender::connect` must heap-allocate.[8] stdexec mitigates this with a 64-byte small buffer optimization,[36] but this paper estimates a nested `starts_on` operation state under `any_sender`/`any_receiver` double erasure at 72-152 bytes from its components - the schedule operation state, the result variant, the `starts_on` glue, and the erasure wrappers - exceeding that buffer, so the allocation stands.
-Table 1 shows per-operation time and heap allocations for native and type-erased stream reads, 100 million `read_some` calls on a single thread; the measurement setup is documented in P4088R1.[4]
+Table 1 shows per-operation time and heap allocations for native and type-erased stream reads, 100 million `read_some` calls on a single thread. The measurement setup is documented in P4088R1.[4]
| Stream type | Coroutine (Capy) | Sender pipeline |
|---|---|---|
| Native | 31.4 ns/op, 0 alloc/op | 30.0 ns/op, 0 alloc/op |
| Type-erased | 36.4 ns/op, **0 alloc/op** | 53.4 ns/op, **1 alloc/op** |
-Native performance is comparable - 30.0 ns vs 31.4 ns, a 1.4 ns difference. Under type erasure the two paths separate: the coroutine path stays at 36.4 ns with zero allocations, while the sender path rises to 53.4 ns and incurs one heap allocation per operation. The 17 ns gap and the per-operation allocation are structural. They follow from how each model interacts with type erasure.
+Native performance is comparable - 30.0 ns vs 31.4 ns, a 1.4 ns difference. Under type erasure the two paths separate: the coroutine path stays at 36.4 ns with zero allocations, while the sender path rises to 53.4 ns and incurs one heap allocation per operation. The 17 ns gap and the per-operation allocation are structural, following from how each model interacts with type erasure.
The same asymmetry applies to any byte-oriented operation that goes through a type-erased interface - GPU memory transfers, network sockets, RDMA queue pairs. For domains where type erasure is the natural interface (a protocol compiled once, linked against any conforming transport), the coroutine model has a structural advantage.
-The same asymmetry determines which model can provide a stable binary interface for I/O. Section 11 draws this consequence.
+This asymmetry also determines which model can provide a stable binary interface for I/O. Section 11 takes it up.
## 11. ABI Stability as a Structural Consequence
The type erasure asymmetry in Section 10 has a further consequence: an ABI-stable interface for async I/O.
-The type-erased wrapper's per-operation vtable entries - `await_ready`, `await_suspend`, `await_resume`, and `destroy` - have fixed signatures. The signature `await_suspend(coroutine_handle<>, io_env const*)` is fixed because `coroutine_handle<>` is type-erased by the language itself. The awaitable size and vtable layout are known at compile time. The interface can be compiled into a shared library (`.so`/`.dll`) and the implementation swapped without recompiling the consumer.
+The type-erased wrapper's per-operation vtable entries - `await_ready`, `await_suspend`, `await_resume`, and `destroy` - have fixed signatures. The signature `await_suspend(coroutine_handle<>, io_env const*)` is fixed because `coroutine_handle<>` is type-erased by the language itself. Awaitable size and vtable layout are known at compile time, so the interface can be compiled into a shared library (`.so`/`.dll`) and the implementation swapped without recompiling the consumer.
-Sender pipelines provide this only at the cost the previous section measured. Without type erasure, `connect(sender, receiver)` produces an operation state whose type and size depend on both the sender and the receiver; every new combination is a new type - a new ABI surface - and changing the I/O implementation forces recompilation of every consumer. With type erasure (`any_sender`), the boundary becomes fixed but every operation heap-allocates (Section 10).
+Sender pipelines provide this only at the cost the previous section measured. Without type erasure, `connect(sender, receiver)` produces an operation state whose type and size depend on both the sender and the receiver. Every new combination is a new type - a new ABI surface - and changing the I/O implementation forces recompilation of every consumer. With type erasure (`any_sender`), the boundary becomes fixed but every operation heap-allocates (Section 10).
-This ABI stability requires no engineering effort and no policy constraint; it is a structural consequence of the coroutine model's type erasure, because the language provides the fixed-type boundary. Three consequences follow: a design lineage (the abstraction arc), a maintenance property (security patching), and a deployment story (the inference stack).
+This ABI stability requires no engineering effort and no policy constraint. It falls out of the coroutine model's type erasure, because the language provides the fixed-type boundary. Three consequences follow: a design lineage (the abstraction arc), a maintenance property (security patching), and a deployment story (the inference stack).
### The abstraction arc
-The interface/implementation split follows the design trajectory of Thrust and the C++17 parallel algorithms - a standard interface over hardware-specific implementation. The precedent covers the interface, not the ABI: both precedents are compile-time template interfaces with no stable binary boundary. The fixed vtable is the element this design adds.
+The interface/implementation split follows the design trajectory of Thrust and the C++17 parallel algorithms - a standard interface over hardware-specific implementation. The precedent covers the interface, not the ABI: both precedents are compile-time template interfaces with no stable binary boundary. What this design adds is the fixed vtable.
**Thrust (2009).** GPU parallel algorithms behind an STL-compatible interface. Customers wrote to the STL vocabulary, ran on NVIDIA's GPU. The interface was vendor-neutral: customers could retarget to TBB or OpenMP. N3408 (2012) carried this into C++17 parallel algorithms.[37]
-**C++17 parallel algorithms.** Standard interface, hardware-specific implementation. Write `std::sort(std::execution::par, ...)`, link against NVIDIA's implementation or Intel's. The standard owns the interface; the vendor owns the implementation.
+**C++17 parallel algorithms.** Standard interface, hardware-specific implementation. Write `std::sort(std::execution::par, ...)`, link against NVIDIA's implementation or Intel's. The standard owns the interface, and the vendor owns the implementation.
-**IoAwaitable streams.** Write `ingest(any_write_stream&, payload)`, link against the demonstrated `cuda_device_stream`, a TCP socket, or - hypothetically today - a ROCm or RDMA transport written to the same concepts. Same pattern, applied to data transport instead of parallel algorithms. The abstraction level rises again; the application code stays the same. A demonstration accompanies this paper[9] in which the same `ingest` handler is compiled once and exercised against both `cuda_device_stream` and an in-memory `WriteStream`.
+**IoAwaitable streams.** Write `ingest(any_write_stream&, payload)`, link against the demonstrated `cuda_device_stream`, a TCP socket, or - hypothetically today - a ROCm or RDMA transport written to the same concepts. Same pattern, applied to data transport instead of parallel algorithms. The abstraction level rises again, and the application code stays the same. A demonstration accompanies this paper[9] in which the same `ingest` handler is compiled once and exercised against both `cuda_device_stream` and an in-memory `WriteStream`.
### Security patching without recompilation
-The ABI-stable boundary means a TLS (Transport Layer Security) stream implementation can be upgraded for a security patch - or swapped out for a different implementation entirely - without recompiling the application. The protocol handler was compiled against `any_write_stream`. The TLS implementation sits behind that interface. Replace the shared library, restart the process.
+The ABI-stable boundary means a TLS (Transport Layer Security) stream implementation can be upgraded for a security patch - or swapped out for a different implementation entirely - without recompiling the application. The protocol handler was compiled against `any_write_stream`. Behind that interface sits the TLS implementation. Replace the shared library, restart the process.
-This is how security-critical infrastructure is maintained in practice: the application binary does not change, only the transport layer underneath it. A non-erased sender pipeline stamps both types into the operation state at `connect`, so changing the TLS implementation changes the type and with it the ABI; the sender route to the same property is `any_sender`, which incurs the per-operation allocation of Section 10.
+This is how security-critical infrastructure is maintained in practice: the application binary does not change, only the transport layer underneath it. At `connect`, a non-erased sender pipeline stamps both types into the operation state, so changing the TLS implementation changes the type and with it the ABI. The sender route to the same property is `any_sender`, which incurs the per-operation allocation of Section 10.
### The complete inference stack
@@ -573,7 +573,7 @@ An inference server receives HTTP requests (TCP transport), dispatches to GPU co
## 12. Partial Success Requires a Compound Result
-Byte-oriented operations deliver results as a compound pair: status plus byte count. The pattern spans hardware boundaries. A POSIX `read` returns `(errno, bytes_read)`. An RDMA work completion returns `(wr_id, status, byte_len)`. CUDA and NCCL report only a status at completion: the transfer count is the caller's own argument, which the IoAwaitable wrapper echoes back, and the transfer either completes in full or fails (Section 9). Where partial success is native, both values are always present and the byte count is not redundant with the error code: a `read` that returns 0 bytes with no error means EOF, and a `read` that returns `ECONNRESET` with 47 bytes means 47 bytes arrived before the peer reset the connection.
+Byte-oriented operations deliver results as a compound pair, status plus byte count, and the pattern spans hardware boundaries. A POSIX `read` returns `(errno, bytes_read)`. An RDMA work completion returns `(wr_id, status, byte_len)`. CUDA and NCCL report only a status at completion: the transfer count is the caller's own argument, which the IoAwaitable wrapper echoes back, and the transfer either completes in full or fails (Section 9). Where partial success is native, both values are always present and the byte count is not redundant with the error code: a `read` that returns 0 bytes with no error means EOF, and a `read` that returns `ECONNRESET` with 47 bytes means 47 bytes arrived before the peer reset the connection.
P2300R10[10] Section 4.14, titled "Senders can represent partial success," poses this directly: "This begs the question of how they can be used to represent async operations that partially succeed." P2300R10 answers it by passing both the error code and the result through the value channel. The cost of that answer is what the rest of this section examines.
@@ -583,7 +583,7 @@ The sender model provides three completion channels: `set_value`, `set_error`, a
- Route the error through `set_error`: the byte count is lost.
- Route through `set_stopped`: both values are lost.
-The best available option is routing both through `set_value` as a compound type. But this means I/O errors bypass the `set_error` channel, disadvantaging sender algorithms that operate on error and stopped channels. P4091R1[5] documents all six positions that have been proposed; each carries a cost.
+The best available option is routing both through `set_value` as a compound type. But this means I/O errors bypass the `set_error` channel, disadvantaging sender algorithms that operate on error and stopped channels. P4091R1[5] documents all six positions that have been proposed. Each carries a cost.
The coroutine version sidesteps the channel choice entirely:
@@ -597,13 +597,13 @@ if (ec == errc::connection_reset)
}
```
-Structured bindings deliver both values. No data loss, no channel to choose, no impedance mismatch with downstream algorithms. The application has the full compound result and decides how to handle it.
+Structured bindings deliver both values, with no data loss and no channel to choose. The application has the full compound result and decides how to handle it.
This is a domain mismatch, not a sender defect. The three-channel model was designed for operations that succeed, fail, or are cancelled - a natural fit for GPU kernel dispatch, where `cudaErrorLaunchFailure` is fatal and carries no partial result. Byte-oriented data movement operates in a domain where partial success is routine and both the status and the byte count must reach the application.
## 13. HPC Networking Plans at Runtime
-The sender model's compile-time pipeline visibility eliminates virtual dispatch and heap allocation - costs on the order of tens of nanoseconds per operation (Table 3 lists 30-60 ns for a malloc-backed frame). These are real costs in nanosecond-scale GPU kernel dispatch. The question is whether they are measurable at the latency scale of network data transfers.
+The sender model's compile-time pipeline visibility eliminates virtual dispatch and heap allocation - costs on the order of tens of nanoseconds per operation (Table 3 lists 30-60 ns for a malloc-backed frame). These are real costs in nanosecond-scale GPU kernel dispatch. But are they measurable at the latency scale of network data transfers?
HPC networking APIs use runtime completion models:
@@ -614,7 +614,7 @@ ncclAllReduce(send, recv, count,
// UCX: callback from progress engine
ucp_tag_send_nbx(ep, buffer, length,
- tag, ¶m);
+ tag, ¶m);
// NVSHMEM: GPU-initiated put with fence
nvshmem_int_put(dest, src, count,
@@ -633,26 +633,26 @@ Five libraries, five different async models: streams, callbacks, GPU-initiated o
Planning decisions in HPC networking are runtime:
- **Topology discovery** happens at communicator creation via `ncclCommInitRank`.[16] NCCL discovers NVLink/NVSwitch/InfiniBand topology and selects ring vs tree algorithms, chooses transports, and builds channel structures. These decisions are driven by hardware probing rather than compile-time type information.
-- **Compute/communication overlap** is expressed through CUDA stream dependencies via `cudaEventRecord` and `cudaStreamWaitEvent`.[24] The scheduler does not need to see the type of the collective to overlap it with compute; it needs the data dependency, captured by the event.
+- **Compute/communication overlap** is expressed through CUDA stream dependencies via `cudaEventRecord` and `cudaStreamWaitEvent`.[24] The scheduler does not need to see the type of the collective to overlap it with compute. It needs the data dependency, captured by the event.
- **Memory registration** is setup-time: `ibv_reg_mr` pins pages, maps GPU base address register (BAR) regions, and exchanges rkeys with peers.[17] All done before the first byte moves.
-The RDMA completion channel exposes a plain file descriptor (`ibv_comp_channel.fd`) that works with epoll - the same reactor pattern as TCP sockets. The work completion returns `(wr_id, status, byte_len)` - the same compound result pattern. The `wr_id` is a natural coroutine dispatch key.
+The RDMA completion channel exposes a plain file descriptor (`ibv_comp_channel.fd`) that works with epoll - the same reactor pattern as TCP sockets. The work completion returns `(wr_id, status, byte_len)`, the same compound result pattern, and the `wr_id` is a natural coroutine dispatch key.
-The stdexec repository focuses on compute scheduling; HPC networking integration is not yet represented. The Maxwell FDTD example uses MPI (Message Passing Interface) for communication, invoked manually inside `then()` callbacks - the network I/O is not expressed as senders. Coroutine-based integration could complement stdexec here: NCCL, RDMA, and NVLink all use runtime completion models (streams, callbacks, file descriptors) that map naturally to the IoAwaitable pattern, providing the data-movement layer that compute scheduling sits on top of.
+The stdexec repository focuses on compute scheduling. HPC networking integration is not yet represented. The Maxwell FDTD example uses MPI (Message Passing Interface) for communication, invoked manually inside `then()` callbacks - the network I/O is not expressed as senders. Coroutine-based integration could complement stdexec here: NCCL, RDMA, and NVLink all use runtime completion models (streams, callbacks, file descriptors) that map naturally to the IoAwaitable pattern, providing the data-movement layer that compute scheduling sits on top of.
-The closest project to sender-based HPC networking in active development is LCI (Lightweight Communication Interface), a C++17 async communication library with libibverbs and libfabric backends and prototype GPU-Direct RDMA, published at SC'25.[38] The LCI paper documents its integration with the HPX runtime as an RDMA transport layer. This is sender-adjacent HPC networking through a runtime wrapper rather than direct sender composition over the wire protocol, but it suggests the space is being explored.
+In active development, the closest project to sender-based HPC networking is LCI (Lightweight Communication Interface), a C++17 async communication library with libibverbs and libfabric backends and prototype GPU-Direct RDMA, published at SC'25.[38] The LCI paper documents its integration with the HPX runtime as an RDMA transport layer. This is sender-adjacent HPC networking through a runtime wrapper rather than direct sender composition over the wire protocol, but it suggests the space is being explored.
Whether any per-operation planning decision in HPC networking benefits from compile-time type visibility of the send and receive calls themselves remains an open question. For communication patterns known at compile time, the answer may be yes. For data-dependent communication patterns determined at runtime, the record shows no example.
## 14. Sender-Based Networking: Deployed Evidence
-The sender/receiver model has been deployed at scale for compute scheduling and infrastructure (Section 3). The question is whether it has been deployed for byte-oriented data movement - the domain this paper examines.
+At scale, the sender/receiver model has been deployed for compute scheduling and infrastructure (Section 3). Has it been deployed for byte-oriented data movement, the domain this paper examines?
Meta deploys the sender/receiver model in production through libunifex. Their internal guidance is instructive. From GitHub issue #586[39] (December 2023):
> "Our experience at Meta has been that coroutines are easier to read, write, debug, and just generally maintain than composition-of-sender algorithms-style code. The cost of that ease is basically overhead; coroutines don't optimize as well as raw senders (either for size or speed). The advice we give to internal teams adopting Unifex is that they should prefer coroutines until they know that the overheads are unacceptable, at which point they can refactor to the lower-level abstraction of raw senders."
-In libunifex, coroutines consume senders, so the guidance concerns the authoring surface on top of a sender substrate: the team that ships sender/receiver in production directs that surface to coroutines for the common case. The public record does not show whether Meta's production use includes byte-oriented networking of the kind this section surveys; the deployment stands as sender implementation experience, with its data-movement domain unresolved.
+In libunifex, coroutines consume senders, so the guidance concerns the authoring surface on top of a sender substrate: the team that ships sender/receiver in production directs that surface to coroutines for the common case. The public record does not show whether Meta's production use includes byte-oriented networking of the kind this section surveys. The deployment is sender implementation experience, with its data-movement domain unresolved.
Table 2 lists the sender-based networking projects outside Meta that the survey found, with each project's foundation and status:
@@ -670,15 +670,15 @@ None are production-grade. The most complete (uring_exec) is a single developer'
SG14, the study group for low-latency systems practitioners, has formally recommended ([P4029R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4029r0.pdf)[12] Section 2): "Networking (SG4) should not be built on top of P2300."
-The gap between networking ambition and deployed evidence suggests that data movement and compute dispatch have different enough completion models that a single abstraction does not serve both optimally. The independent validation in Section 15 shows where each model fits naturally. The bridge between models (Section 18) connects the two domains without requiring either to subsume the other.
+The gap between networking ambition and deployed evidence suggests that data movement and compute dispatch have different enough completion models that a single abstraction does not serve both optimally. Section 15's independent validation shows where each model fits, and the bridge in Section 18 connects the two domains.
## 15. Eight Projects Converged; CERN Adopted
-Eight independent projects have arrived at the same design - coroutine-based async completion for GPU and HPC data movement - and a ninth, CERN's Next Generation Triggers project, ported a working track-reconstruction pipeline onto the IoAwaitable protocol itself. The notification mechanism that bridges GPU completion to coroutine resumption varies - a host-function callback (`cudaLaunchHostFunc`, or its driver-level equivalent `cuLaunchHostFunc`), event polling, or deferred stream synchronization - but the coroutine completion model is common to all of them. Where a project documents a single bridge (cuda-oxide, Taro), it is the callback, the simplest to wire up; CERN's port implements all three.
+Eight independent projects have arrived at the same design - coroutine-based async completion for GPU and HPC data movement - and a ninth, CERN's Next Generation Triggers project, ported a working track-reconstruction pipeline onto the IoAwaitable protocol itself. The notification mechanism that bridges GPU completion to coroutine resumption varies - a host-function callback (`cudaLaunchHostFunc`, or its driver-level equivalent `cuLaunchHostFunc`), event polling, or deferred stream synchronization - but the coroutine completion model is common to all of them. Where a project documents a single bridge (cuda-oxide, Taro), it is the callback, the simplest to wire up. CERN's port implements all three.
**cuda-oxide (NVIDIA Labs, Rust).**[47] NVIDIA's own research lab implemented the same mechanism in Rust. Their `DeviceFuture` submits GPU work, enqueues a `cuLaunchHostFunc` callback that sets an `AtomicBool` and wakes a Tokio `Waker`, and the async runtime resumes the task on the next poll. Zero busy-wait. The three-state machine (Idle, Executing, Complete) is structurally identical to a network socket future. The vendor's own research lab reached the same `cudaLaunchHostFunc`-to-async-runtime pattern independently, in a different language.
-**CERN wp1.7-traccc (adoption, not convergence).**[33] As part of the Next Generation Triggers wp1.7 work package evaluating C++20 coroutines for task scheduling, the CERN team ported the traccc GPU track-reconstruction pipeline - research code rather than production - from stdexec to Capy, in a pull request open as of this writing. This is not independent convergence - it is an outside team adopting the published protocol, which is evidence of a different kind: the protocol as published is usable by a team that did not design it. The pre-port state is recorded here because it cuts the other way: traccc's coroutine layer ran on stdexec first, so the same repository is also sender implementation experience; the pull request does not state the team's reasons for moving, and this paper does not infer them. It implements its CUDA completion strategies behind a single `await_strategy` selector - among them a `cudaLaunchHostFunc` callback, event polling, and deferred `cudaStreamSynchronize` - each an awaitable with the signature `await_suspend(std::coroutine_handle<>, boost::capy::io_env const*)` that posts the coroutine handle back to `env->executor`. That a real reconstruction workload exercises all three notification mechanisms over one protocol is the most concrete evidence in this survey that the coroutine model is not bound to the callback.
+**CERN wp1.7-traccc (adoption, not convergence).**[33] As part of the Next Generation Triggers wp1.7 work package evaluating C++20 coroutines for task scheduling, the CERN team ported the traccc GPU track-reconstruction pipeline - research code rather than production - from stdexec to Capy, in a pull request open as of this writing. This is an outside team adopting the published protocol, evidence of a different kind: the protocol as published is usable by a team that did not design it. Because it cuts the other way, the pre-port state is recorded here: traccc's coroutine layer ran on stdexec first, so the same repository is also sender implementation experience. The pull request does not state the team's reasons for moving, and this paper does not infer them. It implements its CUDA completion strategies behind a single `await_strategy` selector: a `cudaLaunchHostFunc` callback, event polling, and deferred `cudaStreamSynchronize`. Each is an awaitable with the signature `await_suspend(std::coroutine_handle<>, boost::capy::io_env const*)` that posts the coroutine handle back to `env->executor`. That a real reconstruction workload exercises all three notification mechanisms over one protocol is the most concrete evidence in this survey that the coroutine model is not bound to the callback.
**Taro (University of Wisconsin-Madison).**[48] A C++20 coroutine task-graph system for CPU-GPU workloads. GPU tasks suspend the CPU thread via coroutines when waiting for GPU completion, allowing other tasks to run. Uses `cudaLaunchHostFunc` for the callback. Published at Euro-Par 2024 (as TaroRTL) and presented at CppCon 2023. TaroRTL reported a 40-80% speedup over RTLflow, a state-of-the-art GPU-accelerated register-transfer-level (RTL) simulator.
@@ -690,7 +690,7 @@ Eight independent projects have arrived at the same design - coroutine-based asy
**RDMA coroutine libraries.** Three independent projects wrap RDMA verbs as coroutine awaitables: RDMA++ (rdmapp)[52] wraps libibverbs with C++20 coroutines, completing operations from a completion-queue polling thread; Loom[53] provides C++23 typed bindings over libfabric with `co_await ep.async_receive(buf, asio::use_awaitable)`; and FORD[54] (USENIX FAST 2022) implements coroutine-enabled distributed transactions over one-sided RDMA, spawning multiple follow-on systems (Motor, CREST at ASPLOS 2026).
-These projects span GPU compute, molecular dynamics, high-energy physics, RDMA networking, and distributed systems, and they range in maturity: Desmond ships in production, cuda-oxide and the CERN work are research code, and Taro and the RDMA libraries are academic or single-developer projects. Judged by the deployment standard Section 14 applies to sender networking, this survey too contains exactly one production system; the convergence claim is about independent design choice rather than deployment success. The eight converging projects were built by independent teams with no coordination. Two caveats bound what the convergence shows: the two Rust projects had no sender alternative in their language, and FORD (published 2022) and Taro (presented 2023) predate a usable `std::execution`, so part of the convergence reflects what was available rather than a comparative choice. What remains is a finding: teams that needed GPU data movement inside an async runtime repeatedly built awaitable completion on the GPU's own notification primitives. Three of these projects (Taro, TTG/PaRSEC, Desmond) also extend the coroutine pattern to kernel dispatch and GPU pipeline orchestration, placing that evidence in the record without this paper needing to reproduce it. That three of the eight operate in the dispatch domain cuts both ways: it strengthens the case that the coroutine completion model generalizes, and it complicates any strict assignment of dispatch to senders; this paper's domain split describes the centers of the two domains, not a border. The survey's limits are stated in Section 19.5.
+These projects span GPU compute, molecular dynamics, high-energy physics, RDMA networking, and distributed systems, and they range in maturity: Desmond ships in production, cuda-oxide and the CERN work are research code, and Taro and the RDMA libraries are academic or single-developer projects. Judged by the deployment standard Section 14 applies to sender networking, this survey too contains exactly one production system. The convergence claim is about independent design choice rather than deployment success. The eight converging projects were built by independent teams with no coordination. Two caveats bound what the convergence shows: the two Rust projects had no sender alternative in their language, and FORD (published 2022) and Taro (presented 2023) predate a usable `std::execution`, so part of the convergence reflects what was available. What remains is a finding: teams that needed GPU data movement inside an async runtime repeatedly built awaitable completion on the GPU's own notification primitives. And three of these projects (Taro, TTG/PaRSEC, Desmond) extend the coroutine pattern to kernel dispatch and GPU pipeline orchestration, placing that evidence in the record without this paper needing to reproduce it. That three of the eight operate in the dispatch domain cuts both ways: it strengthens the case that the coroutine completion model generalizes, and it complicates any strict assignment of dispatch to senders. This paper's domain split describes the centers of the two domains, not a border. Section 19.5 states the survey's limits.
## 16. CUDA Graphs Optimize a Different Layer
@@ -711,9 +711,9 @@ cudaGraphLaunch(instance, stream);
The CUDA Graph documentation quantifies per-kernel launch overhead at 20-200 us in deep-learning applications.[57] That figure includes framework dispatch above the raw C++ launch cost that Table 3 lists at 1-5 us. In DALLE2 inference (740 kernels, 3.4ms GPU time on an H100), 75% of end-to-end latency is CPU launch delays.[58] Replaying a captured graph replaces those per-kernel round trips with a single launch.
-CUDA Graphs and sender compile-time fusion optimize different layers. CUDA Graphs eliminate per-kernel CPU-GPU dispatch round trips at the driver level - language transitions, runtime processing, driver operations - the 20-200 us per-kernel cost above. Sender fusion eliminates host-side C++ abstraction overhead - allocations, virtual dispatch, type erasure - at the language level. nvexec intercepts sender algorithms and replaces them with CUDA kernel launches on streams; a code search of the stdexec repository finds no CUDA Graph API use in nvexec, and a machine-generated documentation site over the repository reports the same,[59] so per-kernel host launch overhead appears to remain unless CUDA Graphs are used separately. These optimizations are complementary rather than substitutes.
+CUDA Graphs and sender compile-time fusion optimize different layers. CUDA Graphs eliminate per-kernel CPU-GPU dispatch round trips at the driver level: the language transitions, runtime processing, and driver operations that make up the 20-200 us per-kernel cost above. Sender fusion eliminates host-side C++ abstraction overhead - allocations, virtual dispatch, type erasure - at the language level. nvexec intercepts sender algorithms and replaces them with CUDA kernel launches on streams. A code search of the stdexec repository finds no CUDA Graph API use in nvexec, and a machine-generated documentation site over the repository reports the same,[59] so per-kernel host launch overhead appears to remain unless CUDA Graphs are used separately. These optimizations are complementary.
-CUDA Graph replay composes naturally with coroutine-based data movement: the coroutine provides the outer loop with data-dependent control flow (memcpy in, graph launch, memcpy out, check result), and the pre-captured graph is the inner optimized hot path. Schrödinger's Desmond engine (GTC 2024)[50] uses both techniques in the same production engine - coroutine-overlapped simulations and CUDA Graphs - with up to 2.02x speedup in drug discovery workloads; the published account lists the techniques together without describing their composition.
+CUDA Graph replay composes naturally with coroutine-based data movement: the coroutine provides the outer loop with data-dependent control flow (memcpy in, graph launch, memcpy out, check result), and the pre-captured graph is the inner optimized hot path. Schrödinger's Desmond engine (GTC 2024)[50] uses both techniques in the same production engine - coroutine-overlapped simulations and CUDA Graphs - with up to 2.02x speedup in drug discovery workloads. The published account lists the techniques together without describing their composition.
Two questions remain open in the record: whether sender fusion adds measurable value once graph capture has eliminated the driver-level dispatch overhead, and whether GPU pipelines beyond Desmond's structure benefit from coroutine orchestration around pre-captured graphs.
@@ -744,13 +744,13 @@ Table 3 places frame allocation next to the GPU operations a frame orchestrates.
A coroutine frame allocation with a PMR pool is roughly two to nine orders of magnitude cheaper than the GPU operations it orchestrates. For a 600B-parameter model's AllReduce that takes seconds, the 5 ns frame allocation is at least eight orders of magnitude smaller.
-One caveat: the latency table assumes GPU operations in the microsecond-to-second range. For high-frequency kernel dispatch where individual kernel execution times approach the sub-microsecond range, the frame allocation cost relative to the operation cost may be different, and whether it becomes a measurable bottleneck there is an open question for domain experts. Additionally, `cudaLaunchHostFunc` callback latency can spike to 12ms on loaded multi-GPU systems, per the single unreproduced report discussed in Section 8,[30] which means the callback dispatch latency can dominate both frame allocation and the GPU operation itself. The 2-5 ns frame allocation cost is not always the relevant comparison.
+One caveat: the latency table assumes GPU operations in the microsecond-to-second range. For high-frequency kernel dispatch where individual kernel execution times approach the sub-microsecond range, the frame allocation cost relative to the operation cost may be different, and whether it becomes a measurable bottleneck there is an open question for domain experts. A second caveat: `cudaLaunchHostFunc` callback latency can spike to 12ms on loaded multi-GPU systems, per the single unreproduced report discussed in Section 8,[30] which means the callback dispatch latency can dominate both frame allocation and the GPU operation itself. The 2-5 ns frame allocation cost is not always the relevant comparison.
## 18. The Bridge Between Domains
The preceding sections argue that senders and IoAwaitables each serve a domain well: senders for GPU kernel dispatch and heterogeneous scheduling, IoAwaitables for byte-oriented I/O and type-erased streams. The bridge is where the domains meet.
-Capy provides two bridge functions with working implementations in its bench and example code[9]: `await_sender`[6] consumes a sender from within a coroutine via `co_await`, and `as_sender`[7] wraps an IoAwaitable as a P2300R10 sender for use in a sender pipeline. Both compile and run today. One bridge direction currently relies on behavior the standard would need to bless; [P4092R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4092r1.pdf)[6] and [P4093R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4093r1.pdf)[7] are the dedicated design papers for each direction.
+Capy provides two bridge functions with working implementations in its bench and example code[9]: `await_sender`[6] consumes a sender from within a coroutine via `co_await`, and `as_sender`[7] wraps an IoAwaitable as a P2300R10 sender for use in a sender pipeline. Both compile and run today. One bridge direction currently relies on behavior the standard would need to bless. [P4092R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4092r1.pdf)[6] and [P4093R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4093r1.pdf)[7] are the dedicated design papers for each direction.
`await_sender` is the natural bridge for the common case: a coroutine that performs I/O and dispatches to a GPU scheduler. An inference pipeline that uses each model in its natural domain:
@@ -799,11 +799,11 @@ task<> handle_request(
}
```
-Network I/O uses `any_read_source` and `any_write_sink` - type-erased, zero per-operation allocation, compound results via structured bindings. GPU dispatch uses `nvexec::launch` on the stream scheduler - compile-time composition, scheduler-agnostic portability. Because nvexec runs the launched work on the device, `run_model` is a `__device__` function and the trailing `stdexec::continues_on(cpu)` returns completion to the host before the host-only `await_sender` bridge resumes the coroutine - so the handler takes a host scheduler alongside the GPU context. The `await_sender` bridge connects the two without requiring either model to subsume the other.
+Network I/O uses `any_read_source` and `any_write_sink` - type-erased, zero per-operation allocation, compound results via structured bindings. GPU dispatch uses `nvexec::launch` on the stream scheduler - compile-time composition, scheduler-agnostic portability. Because nvexec runs the launched work on the device, `run_model` is a `__device__` function and the trailing `stdexec::continues_on(cpu)` returns completion to the host before the host-only `await_sender` bridge resumes the coroutine. Therefore the handler takes a host scheduler alongside the GPU context. The `await_sender` bridge connects the two without requiring either model to subsume the other.
-The device-to-host `cudaMemcpy` and the per-request `cudaMalloc`/`cudaFree` in the example are deliberate simplifications that keep the bridge visible; a production handler would use `cuda_stream`'s `memcpy_d2h` awaitable and pooled device allocations.
+The device-to-host `cudaMemcpy` and the per-request `cudaMalloc`/`cudaFree` in the example are deliberate simplifications that keep the bridge visible. A production handler would use `cuda_stream`'s `memcpy_d2h` awaitable and pooled device allocations.
-The network transport behind `client` and `response` can be TCP, TLS, RDMA, or any transport that satisfies the stream concepts. The GPU scheduler can be `nvexec::stream_scheduler`, a CPU thread pool, or any scheduler that provides `schedule()`. Neither side needs to know about the other's implementation.
+Behind `client` and `response`, the network transport can be TCP, TLS, RDMA, or any transport that satisfies the stream concepts. The GPU scheduler can be `nvexec::stream_scheduler`, a CPU thread pool, or any scheduler that provides `schedule()`. Neither side needs to know about the other's implementation.
`as_sender` provides the reverse direction: a sender pipeline that consumes an IoAwaitable. This is useful when an existing sender pipeline needs to incorporate a byte-oriented operation:
@@ -828,29 +828,29 @@ The preceding sections present convergent findings. This section addresses fores
### 19.1 Laziness and Composition
-**Awaitables commit to eager execution.** Awaitables are lazy. `write_some` returns an inert object. No `cudaMemcpyAsync` is issued, no syscall is made, until `co_await` triggers `await_suspend`. The trigger is explicit in both models: senders do no work until `start()` is called; awaitables do no work until `co_await` is evaluated. A coroutine can capture the awaitable, defer the `co_await`, and decide at runtime whether to submit the operation. This concern does not distinguish the two models.
+**Awaitables commit to eager execution.** Awaitables are lazy. `write_some` returns an inert object. Until `co_await` triggers `await_suspend`, no `cudaMemcpyAsync` is issued and no syscall is made. In both models, the trigger is explicit: senders do no work until `start()` is called, and awaitables do no work until `co_await` is evaluated. A coroutine can capture the awaitable, defer the `co_await`, and decide at runtime whether to submit the operation. This concern does not distinguish the two models.
**The scheduler cannot see the full task graph.** Sender pipelines compose as a graph the scheduler can inspect before `start()`. This is valuable for GPU kernel dispatch where the work graph is known ahead of time - CUDA Graphs (Section 16) exploit this property at the driver level, replacing per-kernel launch overhead of 20-200 us with a single graph launch.[57] Data movement is different. The next transfer depends on the result of the previous one: how many bytes arrived, whether the peer reset the connection, whether the RDMA completion carried an error. There is no static graph to inspect because control flow branches on runtime data. NCCL topology discovery, RDMA memory registration, and NVLink channel selection are all runtime decisions driven by hardware probing (Section 13). Coroutine control flow - `if`, `for`, `while` - is the natural expression of data-dependent sequential decisions.
-**Senders separate description from execution; coroutines conflate them.** The separation is valuable when the same algorithm can run on CPU or GPU by swapping the scheduler. The Maxwell FDTD benchmark demonstrates this: identical sender code achieves parity with raw CUDA on GPU and runs correctly on a CPU thread pool (Section 3). Data movement operations are bound to specific hardware resources at submission time. A `cudaMemcpyAsync` targets a specific CUDA stream on a specific device. An `ibv_post_send` targets a specific queue pair on a specific host channel adapter (HCA). A `read` targets a specific file descriptor. The description cannot be retargeted by swapping a scheduler because the operation is bound to the resource. For compute dispatch, description-execution separation enables scheduler-agnostic portability. For data transport, the binding to hardware resources makes the separation vacuous.
+**Senders separate description from execution. Coroutines conflate them.** The separation is valuable when the same algorithm can run on CPU or GPU by swapping the scheduler. The Maxwell FDTD benchmark demonstrates this: identical sender code achieves parity with raw CUDA on GPU and runs correctly on a CPU thread pool (Section 3). Data movement operations are bound to specific hardware resources at submission time. A `cudaMemcpyAsync` targets a specific CUDA stream on a specific device, an `ibv_post_send` a specific queue pair on a specific host channel adapter (HCA), and a `read` a specific file descriptor. The description cannot be retargeted by swapping a scheduler because the operation is bound to the resource. For compute dispatch, description-execution separation enables scheduler-agnostic portability. For data transport, the binding to hardware resources makes the separation vacuous.
### 19.2 Consumer Choice and Return Types
**Data movement operations should return senders so the caller can choose how to consume them.** The choice is symmetric. `as_sender`[7] wraps an awaitable for sender pipeline consumption. `await_sender`[6] wraps a sender for coroutine consumption. Neither return type gives every consumer zero-cost access. Returning a sender forces a per-operation allocation under type erasure (Section 10: 53.4 ns/op, 1 alloc/op). Returning an awaitable preserves zero-allocation type erasure (Section 10: 36.4 ns/op, 0 alloc/op) and gives sender pipeline consumers access through `as_sender`. The question is which consumer bears the cost. For data movement where the protocol handler is compiled once against a type-erased stream (Section 9), the type-erased consumer is the common case. P4088R1[4] Section 10 documents the full design fork analysis.
-**The bridge proves senders are more fundamental.** The bridge is symmetric: each model can consume the other's operations through the pair of functions described in Section 18. CPU and GPU interact through memory copies; that does not make one side more fundamental. The bridge is evidence of complementarity between models that serve different domains - compute dispatch and data transport. P4088R1[4] Section 9 addresses this directly.
+**The bridge proves senders are more fundamental.** The bridge is symmetric: each model can consume the other's operations through the pair of functions described in Section 18. CPU and GPU interact through memory copies. That does not make one side more fundamental. The bridge is evidence of complementarity between models that serve different domains - compute dispatch and data transport. P4088R1[4] Section 9 addresses this directly.
### 19.3 Type Erasure and Allocation
**Type erasure should be opt-in, not baked into the abstraction.** Byte-oriented data movement is a domain where the transport is inherently runtime-determined. An inference server does not know at compile time whether input arrives over TCP, RDMA, or NVLink - the transport depends on the deployment topology, which is discovered at communicator creation time via `ncclCommInitRank` or equivalent (Section 13). Type erasure is the natural interface for this domain. Senders' compile-time visibility optimizes for static dispatch, which is not the bottleneck when every operation crosses a kernel boundary (1,000-5,000 ns) or a PCIe bus (10,000+ ns). This is the same design trajectory traced in Section 11. P4088R1[4] Section 7.1 documents the structural mechanism.
-**Coroutine frames allocate; sender operation states do not.** Acknowledged. Sender `operation_state` is a compile-time construct with no heap allocation. Coroutine frames allocate. PMR pools amortize this to near zero (Section 17). The relevant comparison for data movement is total allocation across the stream's lifetime. Under type erasure, the sender model allocates once per `any_sender::connect` (Section 10). The coroutine model allocates once per frame (Section 10). For N operations through a type-erased stream, the coroutine model allocates once; the sender model allocates N times. P4088R1[4] Sections 4 and 7.9 cover the general case.
+**Coroutine frames allocate. Sender operation states do not.** Acknowledged. Sender `operation_state` is a compile-time construct with no heap allocation. Coroutine frames allocate. PMR pools amortize this to near zero (Section 17). For data movement, the relevant comparison is total allocation across the stream's lifetime. Under type erasure, the sender model allocates once per `any_sender::connect` (Section 10). The coroutine model allocates once per frame (Section 10). For N operations through a type-erased stream, the coroutine model allocates once. The sender model allocates N times. P4088R1[4] Sections 4 and 7.9 cover the general case.
-**Compile-time optimization is lost.** Coroutine handles are opaque; the compiler cannot see through `resume()`. Sender pipelines are fully visible, statically dispatched, inlinable. This visibility matters for GPU kernel dispatch where individual operations cost nanoseconds and the compiler can fuse host-side abstraction overhead (Section 3). The latency scale of data movement dwarfs indirect-call overhead (Section 17). The optimization target for data movement is allocation elimination under type erasure (Section 10). P4088R1[4] Section 4 documents the optimization barrier.
+**Compile-time optimization is lost.** Coroutine handles are opaque. The compiler cannot see through `resume()`. Sender pipelines are fully visible, statically dispatched, inlinable. This visibility matters for GPU kernel dispatch where individual operations cost nanoseconds and the compiler can fuse host-side abstraction overhead (Section 3). The latency scale of data movement dwarfs indirect-call overhead (Section 17). For data movement, the optimization target is allocation elimination under type erasure (Section 10). P4088R1[4] Section 4 documents the optimization barrier.
### 19.4 Composition and Algorithms
-**Senders provide 30 generic algorithms; awaitables provide none.** The awaitable composition mechanism is the language's own control flow: `if`, `for`, `while`, `try/catch`, structured bindings. These compose naturally with data-dependent decisions - the `if(ec == errc::connection_reset)` in Section 12 is a branch on runtime data that determines the next operation. For GPU dispatch where the full work graph must be visible to the scheduler before launch, the sender composition algebra is justified (Section 3). For data movement where each operation depends on the result of the previous one, ordinary control flow is the natural mechanism and is debuggable with standard tools. P4088R1[4] Section 2.2 compares the two vocabularies.
+**Senders provide 30 generic algorithms. Awaitables provide none.** The awaitable composition mechanism is the language's own control flow: `if`, `for`, `while`, `try/catch`, structured bindings. These compose naturally with data-dependent decisions - the `if(ec == errc::connection_reset)` in Section 12 is a branch on runtime data that determines the next operation. For GPU dispatch where the full work graph must be visible to the scheduler before launch, the sender composition algebra is justified (Section 3). For data movement where each operation depends on the result of the previous one, ordinary control flow is the natural mechanism and is debuggable with standard tools. P4088R1[4] Section 2.2 compares the two vocabularies.
**Compound results can be routed through set_value.** Route `(error_code, bytes_transferred)` through `set_value` as a compound type. This is physically possible. It is also what Section 12 documents: if all data-movement results route through `set_value`, then `set_error` and `set_stopped` are vestigial for these operations. The three-channel model's value - that different channels enable different downstream algorithms (`retry`, `upon_error`) - is nullified. P2300R10[10] Section 4.14, "Senders can represent partial success," poses the question - "This begs the question of how they can be used to represent async operations that partially succeed" - and answers it with exactly this value-channel routing. The three channels match GPU kernel dispatch, where `cudaErrorLaunchFailure` is fatal and carries no partial result. Byte-oriented operations produce compound results where both status and byte count are always present. P4091R1[5] analyzes all six positions.
@@ -858,15 +858,15 @@ The preceding sections present convergent findings. This section addresses fores
**Structured concurrency is weaker in the coroutine model.** Acknowledged (Section 3). Senders provide `counting_scope` for dynamic fan-out with guaranteed completion before scope destruction. Coroutines provide lexical-scope safety via `when_all` but dynamic fan-out needs explicit library support. Data movement is ordered per stream or connection - one buffer at a time, one completion at a time, the one-at-a-time invariant on the CUDA stream (Section 8) - and practical overlap comes from multiple streams or connections in flight, each individually ordered. Dynamic fan-out across an unknown number of tasks belongs to the compute dispatch domain, where senders provide it.
-**The sender-based networking survey may be incomplete.** Acknowledged. The survey (Section 14) reports every project its search of the public record found; its recall is bounded by that record. Production-grade sender-based networking that the search missed would strengthen the case for sender-based I/O and belongs in a future revision. The search method for both surveys was not recorded when they were run; the tables list what was found, and the absence claims carry that caveat.
+**The sender-based networking survey may be incomplete.** Acknowledged. The survey (Section 14) reports every project its search of the public record found. Its recall is bounded by that record. Production-grade sender-based networking that the search missed would strengthen the case for sender-based I/O and belongs in a future revision. The search method for both surveys was not recorded when they were run. The tables list what was found, and the absence claims carry that caveat.
-**The CUDA examples were generated with AI assistance.** Disclosed in Section 1. The examples are presented as a research exercise for evaluation by domain experts. Errors in the CUDA code would indicate where the examples need refinement; the structural observation stands on the independent projects in Section 15, whose code this paper did not write.
+**The CUDA examples were generated with AI assistance.** Disclosed in Section 1. The examples are presented as a research exercise for evaluation by domain experts. Errors in the CUDA code would indicate where the examples need refinement. The structural observation stands on the independent projects in Section 15, whose code this paper did not write.
**The paper's P2300R10 quotations may be taken out of context.** Both quotations state positions P2300R10 holds in its own voice: Section 4.14 poses the partial-success question and the paper presents P2300R10's own answer (value-channel routing) in the same paragraph, and Section 4.15 states the coroutine-consumption expectation as the design's intent. Each is quoted with its section number.[10]
## 20. Conclusion
-The findings converge from three directions. Structurally, the four transports examined here present one abstract interface - submit a buffer, await completion, receive a compound result - and the IoAwaitable protocol expresses that interface with zero per-operation allocation. A coroutine suspends on each `co_await`, so at most one operation is in flight per single-owner stream and the pre-allocated op-state pattern that networking sockets use carries over; the CUDA Programming Guide's stream-ordering guarantee[23] secures the invariant for every notification mechanism. Empirically, independent projects at NVIDIA Labs (cuda-oxide),[47] the University of Wisconsin-Madison (Taro),[48] and Schrödinger (Desmond)[50] arrived at coroutine-based completion for data movement without coordination, and CERN[33] moved its traccc reconstruction pipeline onto the protocol directly. The notification mechanism is a free variable the protocol does not fix: the traccc port implements the callback, event polling, and deferred synchronization as interchangeable awaitables, and the slides of a CHEP 2026 contribution[28] find that only the callback fails to scale in their multi-threaded setup.
+From three directions, the findings converge. Structurally, the four transports examined here present one abstract interface - submit a buffer, await completion, receive a compound result - and the IoAwaitable protocol expresses that interface with zero per-operation allocation. A coroutine suspends on each `co_await`, so at most one operation is in flight per single-owner stream and the pre-allocated op-state pattern that networking sockets use carries over. The CUDA Programming Guide's stream-ordering guarantee[23] secures the invariant for every notification mechanism. Empirically, independent projects at NVIDIA Labs (cuda-oxide),[47] the University of Wisconsin-Madison (Taro),[48] and Schrödinger (Desmond)[50] arrived at coroutine-based completion for data movement without coordination, and CERN[33] moved its traccc reconstruction pipeline onto the protocol directly. The notification mechanism is a free variable the protocol does not fix: the traccc port implements the callback, event polling, and deferred synchronization as interchangeable awaitables, and the slides of a CHEP 2026 contribution[28] find that only the callback fails to scale in their multi-threaded setup.
`cudaLaunchHostFunc` has documented limitations (Section 8) that bound the applicability of the callback mechanism in high-throughput GPU pipelines. Those limitations are specific to the callback: the protocol equally admits event polling and deferred synchronization, which sidestep them where they apply.
@@ -874,9 +874,9 @@ The findings converge from three directions. Structurally, the four transports e
Taro, TTG/PaRSEC, and Desmond demonstrate the coroutine pattern extending beyond byte movement to kernel dispatch and GPU pipeline orchestration, placing that evidence in the record alongside this paper's byte-movement analysis.
-Bridges (`await_sender`[6], `as_sender`[7]) connect the two models where the domains meet: a networking coroutine consumes a GPU sender for compute dispatch, and a sender pipeline wraps an IoAwaitable for composition. Neither model needs to subsume the other. Senders serve compute dispatch, where compile-time work graphs and scheduler-agnostic portability are decisive; awaitables serve data transport, where type-erased streams, zero-allocation link-time polymorphism, and ABI stability (Section 11) are the working interface.
+Bridges (`await_sender`[6], `as_sender`[7]) connect the two models where the domains meet: a networking coroutine consumes a GPU sender for compute dispatch, and a sender pipeline wraps an IoAwaitable for composition. Neither model needs to subsume the other. Senders serve compute dispatch, where compile-time work graphs and scheduler-agnostic portability are decisive. Awaitables serve data transport, where type-erased streams, zero-allocation link-time polymorphism, and ABI stability (Section 11) are the working interface.
-The record bears on [P4003R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4003r3.pdf)[3], which proposes the IoAwaitable protocol for standardization. The surveyed projects each rebuilt coroutine completion on the GPU's own notification primitives, and the three properties that protocol specifies - executor affinity, cancellation, and frame allocation control - are the properties this paper's analysis (Sections 5 and 7) finds those hand-built integrations leave out. The evaluation of these findings now sits with the domain experts of SG1 and with the authors of P4003R3; this paper places the record before them.
+The record bears on [P4003R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4003r3.pdf)[3], which proposes the IoAwaitable protocol for standardization. The surveyed projects each rebuilt coroutine completion on the GPU's own notification primitives, and the three properties that protocol specifies - executor affinity, cancellation, and frame allocation control - are the properties this paper's analysis (Sections 5 and 7) finds those hand-built integrations leave out. Now the evaluation of these findings sits with the domain experts of SG1 and with the authors of P4003R3. This paper places the record before them.
## Acknowledgements
diff --git a/source/2026-07-july/d4297-severing-profiles-claim.md b/source/2026-07-july/d4297-severing-profiles-claim.md
index 64071f9..efcefa6 100644
--- a/source/2026-07-july/d4297-severing-profiles-claim.md
+++ b/source/2026-07-july/d4297-severing-profiles-claim.md
@@ -13,7 +13,7 @@ reply-to:
This paper asks EWG (the Evolution Working Group) to sever an unadopted architecture claim from the wording it is bundled with, so that the wording proceeds and the claim gets its own paper and poll.
-A proposal for addressing undefined behavior in the C++ standard bundles two things that can be evaluated separately: wording transformations for 77 runtime-checkable cases of UB, and a claim that Profiles are a higher-level feature building on top of the proposal's machinery. The wording is headed into case-by-case review; the architecture claim advances without its own ballot. Without explicit input from EWG, approval of those review outcomes may close the evolution path for Profiles.
+A proposal for addressing undefined behavior in the C++ standard bundles two things that can be evaluated separately: wording transformations for 77 runtime-checkable cases of UB, and a claim that Profiles are a higher-level feature building on top of the proposal's machinery. The wording is headed into case-by-case review, while the architecture claim advances without its own ballot. Without explicit input from EWG, approval of those review outcomes may close the evolution path for Profiles.
Section 4 reconstructs the proposal's seven-poll history and shows none adopted the architecture. Section 5 shows the layering question is substantive, contested, and grounded in a decade of deployment evidence. Section 6 discloses the search method behind the finding that no published WG21 paper contests the claim. Section 8 proposes three polls: a scope statement that wording approvals do not adopt the layering, a process commitment that the layering requires a dedicated paper and explicit poll, and an intent statement that EWG will weigh deployment experience when that poll is taken.
@@ -23,7 +23,7 @@ Section 4 reconstructs the proposal's seven-poll history and shows none adopted
### R0: July 2026
-- Initial version. An earlier working draft circulated before publication asked EWG to defer case-by-case wording review pending implementation and deployment experience; this published version withdraws that request. The review proceeds on its merits, and the ask is stated in Section 8 as three polls. This version adds the Brno 2026-06 poll to the poll history (Table 1, row 7, sourced from the public paper tracker) and identifies the foundational wording clauses that carry the architecture (Table 2).
+- Initial version. An earlier working draft circulated before publication asked EWG to defer case-by-case wording review pending implementation and deployment experience. This published version withdraws that request. The review proceeds on its merits, and the ask is stated in Section 8 as three polls. This version adds the Brno 2026-06 poll to the poll history (Table 1, row 7, sourced from the public paper tracker) and identifies the foundational wording clauses that carry the architecture (Table 2).
---
@@ -33,13 +33,13 @@ The authors provide information and serve at the pleasure of the committee.
Vinnie Falco is the founder of the C++ Alliance, which sponsors a Clang implementation of Profiles. Ville Voutilainen is a longtime WG21 member and a co-author of P3608R0, which Sections 5 and 6 quote, and of other published critiques of the C++26 Contracts process.
-This paper takes no position on which architecture is correct; it reports the public deployment record and asks that the ownership question be polled. It is one of a set in the July 2026 mailing on the runtime checking of core-language undefined behavior. It works only from the published record; committee-internal documents may contain answers that record does not. It uses machine-assisted drafting.
+This paper takes no position on which architecture is correct. It reports the public deployment record and asks that the ownership question be polled. One of a set in the July 2026 mailing on the runtime checking of core-language undefined behavior, it works only from the published record, and committee-internal documents may contain answers that the record does not. It uses machine-assisted drafting.
---
## 2. Introduction
-P3100R8 pairs proposed wording for 77 runtime-checkable cases of core-language undefined behavior with an architecture claim: that Profiles are a higher-level feature built on top of that wording's machinery. The wording is headed into case-by-case EWG review; the architecture claim advances alongside it without a ballot of its own. This paper asks EWG to sever the two, so wording review proceeds and the layering is decided by a ballot written for it.
+P3100R8 pairs proposed wording for 77 runtime-checkable cases of core-language undefined behavior with an architecture claim: that Profiles are a higher-level feature built on top of that wording's machinery. The wording is headed into case-by-case EWG review. Alongside it, the architecture claim advances without a ballot of its own. This paper asks EWG to sever the two, so wording review proceeds and the layering is decided by a ballot written for it.
The layering claim sits between two competing bodies of published work: P3100R8's implicit contract assertions, configured through the Labels facility of P3400R3, and the Profiles work of P3984R0, P3081R2, and P3589R2. Section 3 sets both out and shows where P3100R8 places Profiles beneath its own tools. Two companion papers in the July 2026 mailing take up adjacent questions: P4306R0[1] supplies the dedicated comparison of the two configuration-ownership models that this paper's Poll 2 contemplates, and P4310R0[2] examines the separate question of the response to a detected core-language violation.
@@ -60,7 +60,7 @@ Section 2 named the two competing bodies of work. On one side, P3100R8's implici
- **P3100-first.** P3100's machinery is the foundation. A profile is a named preset that selects from that machinery's settings.
- **Profiles-first.** The Profiles framework is the foundation. It owns the guarantees and the response to a failed check, and P3100's tools sit underneath it.
-P3100R8's Appendix A enumeration of every case of explicit core language undefined behavior (80 cases, classified by diagnosability), its five named evaluation semantics that give existing vendor mechanisms a coherent vocabulary, and its backward-compatible wording that invalidates no existing implementation are real achievements independent of the layering question; what follows is about the architecture claim alone.
+P3100R8's Appendix A enumeration of every case of explicit core language undefined behavior (80 cases, classified by diagnosability), its five named evaluation semantics that give existing vendor mechanisms a coherent vocabulary, and its backward-compatible wording that invalidates no existing implementation are real achievements independent of the layering question. What follows is about the architecture claim alone.
P3100R8 characterizes Profiles as a preset layered on top of its own tools. Its Section 4.4 states the characterization in conditional terms, but the paper does not rest on the hedge: as the Figure 4 caption below shows, the same layering is stated declaratively, and Section 5.6 (discussed later) acts on it. Section 4.4, under "Configuration":
@@ -76,19 +76,19 @@ Its Section 7.2 states what the layering means for P3589R2. Granular control of
And the same section offers Profiles two futures: a profile "can be defined as essentially a declaration that expands to [P3400R3] directives", or Profiles can be redesigned "as an auditing feature rather than a configuration feature", where a profile no longer configures anything and instead renders a program ill-formed when configuration chosen elsewhere violates its guarantees[4].
-The proposal's characterization of Profiles has not been stable across its own revisions. [P3100R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3100r2.pdf)[5] (May 2025) stated the opposite position: a profile "should never dictate whether a runtime check is enabled or disabled or what should happen if that check fails". [P3100R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3100r4.pdf)[6] (August 2025) and every revision since states the current one: a profile "could be defined as being a named configuration preset for these features". Same paper number, opposite claim. The reversal itself was never polled; the one adjacent ballot, the Sofia endorsement of slide 53 as "a good basis" (June 2025, Table 1 poll 4, discussed in Section 4), fell between the two revisions and endorsed the slide that carries the new characterization.
+Across its own revisions, the proposal's characterization of Profiles has not been stable. [P3100R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3100r2.pdf)[5] (May 2025) stated the opposite position: a profile "should never dictate whether a runtime check is enabled or disabled or what should happen if that check fails". [P3100R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3100r4.pdf)[6] (August 2025) and every revision since states the current one: a profile "could be defined as being a named configuration preset for these features". Same paper number, opposite claim. The reversal itself was never polled. The one adjacent ballot, the Sofia endorsement of slide 53 as "a good basis" (June 2025, Table 1 poll 4, discussed in Section 4), fell between the two revisions and endorsed the slide that carries the new characterization.
The proposal has also acted on the claim once. In its Section 5.6, P3100R8 withdraws the `detection_mode` enumerators from its own proposed wording and characterizes the relationship to [P3081R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3081r1.pdf)[7] this way:
> ... unlike earlier revisions of this paper and unlike [P3081R1], which adopted its library API from those earlier revisions, we no longer propose to add new enumerators to the enumeration detection_mode to encode the category of error (Initialization, Bounds, and so on); instead, this encoding can be accomplished more effectively and flexibly via Labels (see Section 7.1).
-The consequence is concrete. P3081R2's proposed wording still adds those enumerators - `detection_mode::type`, `detection_mode::bounds`, and `detection_mode::lifetime`, each defined as indicating that "the contract assertion was evaluated as part of" the corresponding profile, with violation handling passing "the detection_mode value corresponding to P" - while P3100R8 proposes none. Those checks were to be delivered by P3100's machinery, as the P3100 authors' own P3543R0 states (Section 6); when P3100R8 moved category encoding to Labels, P3081R2's enumerators lost the mechanism that would produce them. P3081R2, from February 2025, remains the latest revision[8], and no revision has answered. When one feature owns the configuration mechanism, a change to it can leave another paper's wording stranded through independent revision, without the coordination that P3100R8's own Section 7.2 now says is needed.
+The consequence is concrete. P3081R2's proposed wording still adds those enumerators - `detection_mode::type`, `detection_mode::bounds`, and `detection_mode::lifetime`, each defined as indicating that "the contract assertion was evaluated as part of" the corresponding profile, with violation handling passing "the detection_mode value corresponding to P" - while P3100R8 proposes none. Those checks were to be delivered by P3100's machinery, as the P3100 authors' own P3543R0 states (Section 6). When P3100R8 moved category encoding to Labels, P3081R2's enumerators lost the mechanism that would produce them. P3081R2, from February 2025, remains the latest revision[8], and no revision has answered. When one feature owns the configuration mechanism, a change to it can leave another paper's wording stranded through independent revision, without the coordination that P3100R8's own Section 7.2 now says is needed.
-Read together, P3100R8's Section 4.4, Figure 4, Section 5.6, and Section 7.2 make one claim: P3100's machinery is the base, and Profiles are either a preset that configures it or an auditor that checks it. In that arrangement, P3100 is the foundation and Profiles are defined in its terms.
+Read together, P3100R8's Section 4.4, Figure 4, Section 5.6, and Section 7.2 make one claim: P3100's machinery is the base, and Profiles are either a preset that configures it or an auditor that checks it. Either way, P3100 is the foundation and Profiles are defined in its terms.
-P3100R8 therefore contains two things that can be evaluated separately. The first is wording: 77 runtime-checkable cases of undefined behavior, each with a proposed transformation, each standing on its own technical merits regardless of whether Profiles sit above or below P3100's machinery. The second is the architecture claim, which depends on the wording and cannot advance without it. The architecture claim is separable: it advances alongside the wording review and gains standing from each approval, yet the review never directly examines or polls it.
+P3100R8 therefore contains two things that can be evaluated separately. The first is wording: 77 runtime-checkable cases of undefined behavior, each with a proposed transformation, each standing on its own technical merits regardless of whether Profiles sit above or below P3100's machinery. The second is the architecture claim, which depends on the wording and cannot advance without it. It is nonetheless separable: it advances alongside the wording review and gains standing from each approval, yet the review never directly examines or polls it.
-P3100 bundles reviewable wording with an architecture claim that has never been polled on its own. Without explicit input from EWG, approving the outcomes of the case-by-case review may close the evolution path for Profiles. This paper asks EWG to sever them - let the wording proceed on its merits, and require the architecture claim to be decided by its own paper and poll.
+In short, reviewable wording travels with an architecture claim that has never been polled on its own. Without explicit input from EWG, approving the outcomes of the case-by-case review may close the evolution path for Profiles. The ask is severance - let the wording proceed on its merits, and require the architecture claim to be decided by its own paper and poll.
---
@@ -96,15 +96,15 @@ P3100 bundles reviewable wording with an architecture claim that has never been
We examine the proposal's poll record: first why every poll about the proposal looks low-stakes, then what the polls actually decided.
-The polls look low-stakes because the wording requires nothing of any implementation. P3100R8's Section 5.2:
+Because the wording requires nothing of any implementation, the polls look low-stakes. P3100R8's Section 5.2:
> Note that no implementation is actually required to implement these checks: a valid implementation choice is to make all 77 cases always have the ignore semantic. It follows that all existing implementations of C++ are already conforming with this wording transformation.
-Every evaluation semantic is implementation-defined per case; the proposal's own wording states that "There is no requirement that any particular semantic choice be available for the implicit contract assertion"[4]. This design has a legitimate engineering rationale - the wording is adoptable without breaking any implementation - and a procedural effect: because a poll about it compels no vendor and breaks no code, each vote is easy to cast and easy to justify. But requiring nothing is not the same as deciding nothing. The votes still accumulate toward something concrete: the layering in P3100R8's Figure 4 and the configuration ownership in its Section 7.2.
+Every evaluation semantic is implementation-defined per case, and the proposal's own wording states that "There is no requirement that any particular semantic choice be available for the implicit contract assertion"[4]. This design has a legitimate engineering rationale - the wording is adoptable without breaking any implementation - and a procedural effect: because a poll about it compels no vendor and breaks no code, each vote is easy to cast and easy to justify. But requiring nothing is not the same as deciding nothing. The votes still accumulate toward something concrete: the layering in P3100R8's Figure 4 and the configuration ownership in its Section 7.2.
-P3100R8's Section 2, "History and polls", lists what it presents as the committee history through Croydon (March 2026). P3100R8, dated July 2026, is the latest revision at the time of writing. Rows 1-6 of Table 1 reproduce every poll from that section, quoted from the paper, with the tallies the paper itself gives; there is no independent public list to check those six against, except as noted below. Row 7 is a later poll, taken at Brno in June 2026, after the period Section 2's history covers; it is absent from P3100R8's self-reported history and is quoted here from the public WG21 paper tracker.
+P3100R8's Section 2, "History and polls", lists what it presents as the committee history through Croydon (March 2026). At the time of writing, P3100R8 itself, dated July 2026, is the latest revision. Rows 1-6 of Table 1 reproduce every poll from that section, quoted from the paper, with the tallies the paper itself gives. There is no independent public list to check those six against, except as noted below. Row 7 is a later poll, taken at Brno in June 2026, after the period Section 2's history covers. It is absent from P3100R8's self-reported history and is quoted here from the public WG21 paper tracker.
-Table 1: The six polls in P3100R8's self-reported history (its Section 2, rows 1-6), plus a seventh poll taken at Brno after that history's coverage (row 7, from the public paper tracker). Poll text abridged only by ellipsis; tallies and result labels as printed in the cited source. The rightmost column classifies what each poll asked for. SG21 is the Contracts study group, SG23 the Safety and Security study group, and EWG the Evolution Working Group.
+Table 1: The six polls in P3100R8's self-reported history (its Section 2, rows 1-6), plus a seventh poll taken at Brno after that history's coverage (row 7, from the public paper tracker). Poll text abridged only by ellipsis. Tallies and result labels as printed in the cited source. The rightmost column classifies what each poll asked for. SG21 is the Contracts study group, SG23 the Safety and Security study group, and EWG the Evolution Working Group.
| # | Body, meeting | Poll (as quoted in P3100R8) | SF/F/N/A/SA | Result (as printed) | What was asked |
|---|---|---|---|---|---|
@@ -116,21 +116,21 @@ Table 1: The six polls in P3100R8's self-reported history (its Section 2, rows 1
| 6 | EWG, Croydon, 2026-03 | "Update P3100R5 by applying the presented rules to all cases of runtime-checkable UB in the standard, as listed in appendix A, and bring it back to EWG for case-by-case wording review" | 39/19/5/2/1 | Strong consensus | A wording update across all 77 cases, and more review |
| 7 | EWG, Brno, 2026-06 | "EWG Approves of the overall direction of P3100R7, agrees to attend/spend time reviewing every line item in Telecons, and re-consider this in Búzios." | 16/15/6/2/0 | Consensus | Direction, a telecon commitment, and reconsideration at Búzios |
-The Hagenberg poll and its tally are independently public in [P3656R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3656r1.pdf)[9], the white paper process document by its appointed editors. The Brno poll (row 7) and its tally are independently public on the WG21 paper tracker[10]. The remaining tallies are as self-reported in P3100R8.
+The Hagenberg poll and its tally are independently public in [P3656R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3656r1.pdf)[9], the white paper process document by its appointed editors. On the WG21 paper tracker[10], the Brno poll (row 7) and its tally are independently public. The remaining tallies are as self-reported in P3100R8.
Three observations follow from the table:
-First, none of the seven polls adopts anything. Two are direction polls, one creates a white paper and appoints its editors, one endorses a diagram as a basis for that white paper, one recommends a target, and one requests a wording update and further review; the seventh, at Brno, approves the overall direction and commits EWG to line-item telecon review with reconsideration at Búzios. The one poll that established a content-approval process - Sofia's per-clause approval in telecons - never ran. The paper itself reports:
+First, none of the seven polls adopts anything. Two are direction polls, one creates a white paper and appoints its editors, one endorses a diagram as a basis for that white paper, one recommends a target, and one requests a wording update and further review. At Brno, the seventh approves the overall direction and commits EWG to line-item telecon review with reconsideration at Búzios. The one poll that established a content-approval process - Sofia's per-clause approval in telecons - never ran. The paper itself reports:
> However, the telecons for per-clause approval of this paper into the white paper were never scheduled, and the pursuit of the white paper as a ship vehicle has stalled. To make progress, we decided to instead target C++29 with the present proposal.
-Second, the endorsements were for a white paper that no longer exists. The Hagenberg poll created a joint, editor-curated white paper "in the C++26 timeframe"; the Sofia polls endorsed a diagram and a process for that white paper. The white paper stalled, the proposal retargeted to C++29 as an ordinary International Standard track paper, and the endorsements remain in its history section, now attached to a target those polls never named.
+Second, the endorsements were for a white paper that no longer exists. The Hagenberg poll created a joint, editor-curated white paper "in the C++26 timeframe", and the Sofia polls endorsed a diagram and a process for that white paper. The white paper stalled, the proposal retargeted to C++29 as an ordinary International Standard track paper, and the endorsements remain in its history section, now attached to a target those polls never named.
-Third, the paper's own characterization of this record is stronger than the poll texts and tallies. Its Section 1 states: "The proposed design has been reviewed and approved by SG21, SG23, and EWG."[4] Table 1 records no adoption poll. Within its Section 2, the prose introducing the Kona poll reads "approved it with strong consensus"; the poll box directly beneath records "Result: Consensus", with one Against and two Strongly Against, and the poll text asks about direction, which in WG21 procedure does not adopt or approve a design.
+Third, the paper's own characterization of this record is stronger than the poll texts and tallies. Its Section 1 states: "The proposed design has been reviewed and approved by SG21, SG23, and EWG."[4] Table 1 records no adoption poll. Within its Section 2, the prose introducing the Kona poll reads "approved it with strong consensus". The poll box directly beneath records "Result: Consensus", with one Against and two Strongly Against, and the poll text asks about direction, which in WG21 procedure does not adopt or approve a design.
-The accumulation works in numbered steps. (1) Each recorded consensus becomes the starting point for the next question. (2) Each one raises the cost of objecting later, because a subsequent objection must unseat a standing result rather than address an open one. (3) The Croydon poll routes the proposal into review of 77 cases, one at a time, and each case is a small, technical, reasonable question, none of them the architecture question of P3100R8's Section 4.4. (4) When the last case is approved, the architecture may be settled in effect without ever being polled on its own. This is a ratchet: not a claim that the outcome is inevitable, but a series of small forward steps that are individually easy and collectively hard to undo. The architecture's one ballot appearance was as "a good basis" for the abandoned white paper (Table 1, poll 4).
+The accumulation works in numbered steps. (1) Each recorded consensus becomes the starting point for the next question. (2) Each one raises the cost of objecting later, because a subsequent objection must unseat a standing result rather than address an open one. (3) The Croydon poll routes the proposal into review of 77 cases, one at a time, and each case is a small, technical, reasonable question, none of them the architecture question of P3100R8's Section 4.4. (4) When the last case is approved, the architecture may be settled in effect without ever being polled on its own. This is a ratchet: a series of small forward steps that are individually easy and collectively hard to undo. Nothing here says the outcome is inevitable. The architecture's one ballot appearance was as "a good basis" for the abandoned white paper (Table 1, poll 4).
-The review's structure shows where that architecture actually lives. P3100R8's wording (its Section 6) is not 77 independent edits: it rests on six foundational changes that establish the framework, after which each individual case is a mechanical application of it. Table 2 lists them.
+The review's structure shows where that architecture lives. P3100R8's wording (its Section 6) is not 77 independent edits: it rests on six foundational changes that establish the framework, after which each individual case is a mechanical application of it. Table 2 lists them.
Table 2: The six foundational wording changes in P3100R8's Section 6 that carry the architecture. Once these are approved, the remaining individual cases are mechanical applications of the framework they establish.
@@ -143,24 +143,24 @@ Table 2: The six foundational wording changes in P3100R8's Section 6 that carry
| [basic.contract.eval] | Adds the assume semantic and restricts it to implicit assertions | Puts the backwards-compatibility escape hatch and the explicit/implicit asymmetry into normative wording |
| [basic.contract.implicit] | Adds the section defining implicit contract assertions, stating that all undefined behavior has a guarding contract assertion | The clause that makes the whole framework normative |
-The consequence for the ratchet is concrete. The architecture is decided when these six clauses are approved, not spread evenly across all 77 cases. Once they stand, each remaining case is the small, technical, reasonable question that step (3) describes - change "the behaviour is undefined" to "there is an implicit precondition assertion that this does not occur." A member reviewing the fortieth case is no longer positioned to reopen the framework; that decision was made when the foundational clauses passed. The ratchet is not 77 equal steps but six foundational ones followed by the rest as mechanical applications.
+These six clauses front-load the ratchet: the architecture is decided when they are approved. Once they stand, each remaining case is the small, technical, reasonable question that step (3) describes - change "the behaviour is undefined" to "there is an implicit precondition assertion that this does not occur." A member reviewing the fortieth case is no longer positioned to reopen the framework, because that decision was made when the foundational clauses passed. The ratchet is not 77 equal steps but six foundational ones followed by the rest as mechanical applications.
-To the response that direction polls are only encouragement and the real decision comes later: the defaults arrive earlier. By the time an adoption poll exists, the characterization will have seven recorded consensus results and 77 case approvals behind it, and whoever contests the accumulated record carries the burden of proof. Reversal at that point is possible but expensive. The committee removed the earlier Contracts design from the C++20 working draft after adopting it, once design disagreements surfaced that consensus could not resolve[11], and it walked away from [P0443R14](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0443r14.html)[12] after the unified executor design absorbed fourteen revisions of committee direction and was never deployed as designed - a history [P4094R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4094r1.pdf)[13] documents with its costs. Both reversals cost years, and both show the committee can undo even an adopted design once the case is made. The concern here is narrower and earlier: not that reversal is impossible, but that its cost accrues before any adoption poll, while the record is built case by case. Reversal stays available; what the accumulation removes is the occasion to decide the architecture before that cost is incurred.
+To the response that direction polls are only encouragement and the real decision comes later: the defaults arrive earlier. By the time an adoption poll exists, the characterization will have seven recorded consensus results and 77 case approvals behind it, and whoever contests the accumulated record carries the burden of proof. Reversal at that point is possible but expensive. The committee removed the earlier Contracts design from the C++20 working draft after adopting it, once design disagreements surfaced that consensus could not resolve[11]. It walked away from [P0443R14](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0443r14.html)[12] after the unified executor design absorbed fourteen revisions of committee direction and was never deployed as designed - a history [P4094R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4094r1.pdf)[13] documents with its costs. Both reversals cost years, and both show the committee can undo even an adopted design once the case is made. The concern here is narrower and earlier: the cost of reversal accrues before any adoption poll, while the record is built case by case. Reversal stays available - what the accumulation removes is the occasion to decide the architecture before that cost is incurred.
---
## 5. The Claim Decides Who Owns Runtime-Check Configuration
-The bundled architecture claim carries real design stakes. This section shows what the layering decides, then what the deployment record says about the two architectures it chooses between.
+The bundled architecture claim carries real design stakes: this section shows what the layering decides, then what the deployment record says about the two architectures it chooses between.
Four design consequences follow from the layering claim, each taken from the published texts:
-- **It decides who writes guarantees.** Under P3984R0's model, a profile writes the guarantee itself: "A profile cannot change the semantics of a program beyond defining the meaning of some forms of undefined behavior", and its overflow example has the profile choose wraparound, saturation, or an exception[14]. Under P3100R8's Section 4.4, a profile defines nothing; it selects a configuration of the proposal's semantics. The difference is ownership: the profile author writes the guarantee, or the preset author chooses from the proposal's menu.
+- **It decides who writes guarantees.** Under P3984R0's model, a profile writes the guarantee itself: "A profile cannot change the semantics of a program beyond defining the meaning of some forms of undefined behavior", and its overflow example has the profile choose wraparound, saturation, or an exception[14]. Under P3100R8's Section 4.4, a profile defines nothing. It selects a configuration of the proposal's semantics. The difference is ownership: the profile author writes the guarantee, or the preset author chooses from the proposal's menu.
- **It decides who owns configuration.** P3100R8's Section 7.2 requires that either Labels or the Profiles framework be specified in terms of the other, and the proposal nominates Labels, sketching a profile as "essentially a declaration that expands to [P3400R3] directives". If per-clause review normalizes that arrangement case by case, P3589R2 arrives at its own EWG review already defined as syntax sugar over another proposal's facility.
-- **It decides the scope of Profiles.** The alternative future that Section 7.2 offers - Profiles as "an auditing feature rather than a configuration feature" - removes Profiles from configuration entirely. An auditing profile cannot enable anything; it can only reject programs whose configuration, chosen through P3100R8's mechanisms, violates its guarantees. That is a real and possibly useful feature. It is also strictly smaller than the framework the Direction Group endorsed in [P3970R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3970r0.pdf)[15].
+- **It decides the scope of Profiles.** The alternative future that Section 7.2 offers - Profiles as "an auditing feature rather than a configuration feature" - removes Profiles from configuration entirely. An auditing profile cannot enable anything. It can only reject programs whose configuration, chosen through P3100R8's mechanisms, violates its guarantees. Such a feature is real and possibly useful, but strictly smaller than the framework the Direction Group endorsed in [P3970R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3970r0.pdf)[15].
- **It applies a test to Profiles that the proposal does not apply to itself.** P3100R8's Section 4.3.2 rejects conditional refined behavior: "We also cannot have two different language dialects where the same expression means two different things (overflow or wraparound)."[4] Its Section 5.4 then maps signed integer overflow, for the same expression, to wraparound under ignore, a diagnostic under observe or enforce, an abort under quick-enforce, and undefined behavior under assume - selected per case by an implementation-defined mechanism. Whether five implementation-selected meanings for one expression are themselves dialects is a question per-clause review will never ask, because no single clause raises it. The dialect question implicates both models, P3100's implementation-selected semantics and P3984's profile-defined semantics alike, which is one more reason to settle it in a paper of its own rather than as a byproduct of wording review.
-The deployment record speaks to which architecture matches existing practice. The named-check-set form the Profiles papers describe has shipped for a decade under vendor names:
+The deployment record speaks to which architecture matches existing practice. For a decade, the named-check-set form the Profiles papers describe has shipped under vendor names:
- **Core Guidelines checkers:** clang-tidy since LLVM 3.8 (March 2016)[16]; MSVC installed by default from VS 2017[17].
- **Hardened libc++:** since LLVM 18 (March 2024), four named modes, a failed check "reliably terminated", a build setting in Xcode 16[18][19]; deployed across Google server-side production at approximately 0.30% average cost[20].
@@ -169,41 +169,41 @@ The deployment record speaks to which architecture matches existing practice. Th
Every one of these is a named, vendor-defined check-set. None routes through the `std::contracts` violation handler adopted for C++26, and none is configured by a Label. libc++ comes closest: as an experimental feature added in LLVM 21 (2025)[23], it lets a translation unit select among four assertion semantics named after the C++26 evaluation semantics (ignore, observe, quick-enforce, enforce), and it lets vendors, though explicitly not users, override the assertion handler[18]. Even there, the semantic is chosen for a build through a vendor macro rather than per assertion through a Label, and the handler is the vendor's rather than the replaceable `std::contracts` one.
-The proposal's distinctive machinery, by contrast, ships nowhere. The contract-violation runtime adopted for C++26 ([P2900R14](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2900r14.pdf)[24], adopted February 2025[25]) has one compiler implementation: GCC 16.1 (April 2026), opt-in, under GCC's blanket experimental C++26 label[26]; Clang reports "No"[27]; MSVC reports "not yet implemented"[22]. Implicit contract assertions have no implementation, and P3100R8 reports no deployment experience of the proposed machinery: the word "experience" does not appear in it[4]. Labels are future tense in the proposal's own text: they "will provide the ability to choose and constrain the evaluation semantic in code"[4]. Two symmetries belong on the table: neither proposed specification is deployed - the Profiles framework syntax of P3589R2 has no implementation either (the Clang Profiles work of Section 1 implements individual profiles, not that syntax) - and both forms have deep lineage, the named check-set in the vendor deployments above and the compiler-inserted check in the sanitizers and `-ftrapv`/`-fwrapv`, which P3100R8 maps into its model. What deployment validates on both sides is per-build selection through vendor flags and macros, not the in-source per-assertion Labels or the replaceable `std::contracts` handler that distinguish the proposal. C++26 has, on paper, assigned hardening's future to contract terms - [P3471R4](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3471r4.html)[28] is the first user of the adopted Contracts feature[25] - while every shipping deployment runs the named-guarantee form.
+By contrast, the proposal's distinctive machinery ships nowhere. The contract-violation runtime adopted for C++26 ([P2900R14](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2900r14.pdf)[24], adopted February 2025[25]) has one compiler implementation: GCC 16.1 (April 2026), opt-in, under GCC's blanket experimental C++26 label[26]; Clang reports "No"[27]; MSVC reports "not yet implemented"[22]. Implicit contract assertions have no implementation, and P3100R8 reports no deployment experience of the proposed machinery: the word "experience" does not appear in it[4]. Labels are future tense in the proposal's own text: they "will provide the ability to choose and constrain the evaluation semantic in code"[4]. Two symmetries are worth stating. Neither proposed specification is deployed - the Profiles framework syntax of P3589R2 has no implementation either (the Clang Profiles work of Section 1 implements individual profiles, not that syntax). Both forms also have deep lineage: the named check-set in the vendor deployments above and the compiler-inserted check in the sanitizers and `-ftrapv`/`-fwrapv`, which P3100R8 maps into its model. On both sides, what deployment validates is per-build selection through vendor flags and macros. The in-source per-assertion Labels and the replaceable `std::contracts` handler, the parts that distinguish the proposal, have no such validation. C++26 has, on paper, assigned hardening's future to contract terms - [P3471R4](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3471r4.html)[28] is the first user of the adopted Contracts feature[25] - while every shipping deployment runs the named-guarantee form.
The governing standard comes from the committee's direction paper, [P2000R5](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p2000r5.pdf)[29]: "We change the language and standard library by gradually building on previous work or by providing a better alternative to an existing feature." That standard cuts two ways here, and this analysis does not adjudicate between them: P3100 builds on P2900, the most recently adopted prior work, while the deployed named-guarantee form is the existing practice a Profiles framework would build on. Which reading governs is what Poll 3 asks EWG to weigh. Three committee members applied the existing-practice reading in this exact domain in [P3608R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3608r0.html)[30], writing about what to ship in C++26: "the standard library hardening is existing practice, and comes with very positive field experience reports." The existing practice it names is the named-guarantee form, so the reading transfers to the ownership question. Who wrote this standard matters, so here it is: Stroustrup, an author on one side of the dispute examined here, co-authors P2000R5 and P3970R0, and P3608R0 is co-authored by an author of this paper (Section 1). The deployment facts above stand on vendor documentation and do not depend on those papers. Profiles' own direction lineage - [P2687R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2687r0.pdf)[31] (2022) back to the C++ Core Guidelines, announced September 2015[32] - is weighed exactly as Table 1 weighs the proposal's polls: direction, not adoption.
-The layering is also a runtime arrangement, not only a diagram. Under P3100R8 a detected core-language violation is routed to the single program-wide contract-violation handler regardless of whether the build selects observe, enforce, or quick-enforce; the log-and-continue shape of the observe semantic already ships at the library level in Bloomberg's `bsls_review`[33]. Whoever owns the handler owns the response, and under P3100R8 that owner is neither the operation nor any profile - it is the handler. A profile that must guarantee terminate-or-reject for the categories it covers is then defined over a substrate whose configuration can route the response through a handler the profile does not control, which is why the ownership question belongs on its own ballot rather than in case-by-case review.
+The layering is a runtime arrangement as well as a diagram. Under P3100R8 a detected core-language violation is routed to the single program-wide contract-violation handler regardless of whether the build selects observe, enforce, or quick-enforce. The log-and-continue shape of the observe semantic already ships at the library level in Bloomberg's `bsls_review`[33]. Whoever owns the handler owns the response, and under P3100R8 that owner is neither the operation nor any profile - it is the handler. A profile that must guarantee terminate-or-reject for the categories it covers is then defined over a substrate whose configuration can route the response through a handler the profile does not control. Hence the ownership question needs a ballot of its own, separate from the case-by-case review.
-To the response that the two features are complementary and the layering a detail: complementarity is not symmetric here, and P3100R8 says so. Its Section 7.2 states that one feature must be specified in terms of the other, and the paper places Labels underneath. P3081R1 took the complementary path - it adopted the proposal's API into its own wording - and P3100R8's Section 5.6 then withdrew that API, as Section 3 showed. Complementarity without settled configuration ownership has already produced one stranded dependency. The layering is not a detail; it is the decision. A question with this much contested evidence belongs on its own ballot, not bundled with 77 wording cases whose technical merits are independent of it.
+One response holds that the two features are complementary and the layering a detail. But complementarity is not symmetric here, and P3100R8 says so. Its Section 7.2 states that one feature must be specified in terms of the other, and the paper places Labels underneath. P3081R1 took the complementary path - it adopted the proposal's API into its own wording - and P3100R8's Section 5.6 then withdrew that API, as Section 3 showed. Complementarity without settled configuration ownership has already produced one stranded dependency. The layering is the decision, not a detail. With this much contested evidence behind it, the question deserves a dedicated ballot, away from 77 wording cases whose technical merits are independent of it.
---
## 6. No Published Paper Contests the Characterization
-The claim of this section is deliberately narrow. Using the search method below, the search found no published WG21 paper, through the 2026-05 pre-Brno mailing (the most recent published mailing at the 2026-07-07 fetch), that directly contests P3100R8's characterization of Profiles. This is a statement about the public paper record only. It says nothing about whether anyone has objected in committee discussion, which is outside this scope.
+The claim of this section is deliberately narrow. Through the 2026-05 pre-Brno mailing (the most recent published mailing at the 2026-07-07 fetch), the search method below found no published WG21 paper that directly contests P3100R8's characterization of Profiles. This is a statement about the public paper record only. It says nothing about whether anyone has objected in committee discussion, which is outside this scope.
-The characterization has been in print since June 2025 - first on slide 53 of [P3754R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3754r0.pdf)[34] (headed "Configurable Profiles", reading "Named configuration presets for the features below"), endorsed by the Sofia diagram poll, then in P3100R4 (August 2025) and every revision since.
+Since June 2025, the characterization has been in print - first on slide 53 of [P3754R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3754r0.pdf)[34] (headed "Configurable Profiles", reading "Named configuration presets for the features below"), endorsed by the Sofia diagram poll, then in P3100R4 (August 2025) and every revision since.
Why the absence is structural rather than accidental: a paper with no normative effect never forces anyone to respond. No wording changes what any implementation must do, no forwarding poll on the layering is scheduled, and no individual clause in the review asks the Profiles question. Anyone who objects is objecting to something that, today, does nothing, so the claim moves forward because there is never anything to vote against.
-The method, so the absence claim can be re-run: we enumerated all papers in the public open-std 2025 and 2026 mailing directories whose titles match profile, safety, harden, undefined behaviour, UB, erroneous, contract, preset, P3100, or P3754, together with every revision of P3100 and P3754 and the P2687/P3274/P3081/P3589/P3970/P3984 lineage - 121 documents, fetched 2026-07-07 - and searched the full text of each for the characterization and its layering language (preset, built on top of, higher-level feature, substrate). We also checked the public GitHub paper tracker and the full WG21 paper index, author by author, for 2025-2026 papers by Stroustrup, Dos Reis, Sutter, and Vandevoorde. A contesting paper with a title outside the keyword net would escape the search; the author scan and the tracker check are the mitigation, not a guarantee.
+The method, so the absence claim can be re-run: we enumerated all papers in the public open-std 2025 and 2026 mailing directories whose titles match profile, safety, harden, undefined behaviour, UB, erroneous, contract, preset, P3100, or P3754, together with every revision of P3100 and P3754 and the P2687/P3274/P3081/P3589/P3970/P3984 lineage - 121 documents, fetched 2026-07-07. We searched the full text of each for the characterization and its layering language (preset, built on top of, higher-level feature, substrate). We also checked the public GitHub paper tracker and the full WG21 paper index, author by author, for 2025-2026 papers by Stroustrup, Dos Reis, Sutter, and Vandevoorde. A contesting paper with a title outside the keyword net would escape the search. The author scan and the tracker check mitigate that risk. They do not close it.
The result: the characterization occurs only in the proposal's own papers and its companions. [P3543R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3543r0.pdf)[35] (December 2024, co-authored by Doumler and Berne) states that P3081's runtime checks "are already preconditions introduced as implicit preconditions into the language itself by [P3100]". [P3599R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3599r0.pdf)[36] (February 2025) proposes to "restrict [P3081R1] (Profiles) to static checks".
-On the Profiles side, the published papers assert an incompatible architecture and do not engage the characterization. P3589R2 contains no occurrence of "contract", "label", or "preset" in any revision - though its latest revision (May 2025) predates the characterization's first publication, so its silence reflects timing, not agreement[37]. P3984R0 post-dates the characterization by eight months and asserts a profile that owns its semantics directly: "For example, signed arithmetic overflow is UB so a profile can define it to be wraparound like unsigned arithmetic (though I wouldn't do that), to be saturated arithmetic, or to throw an exception." The strings "P3100", "contract", and "preset" do not occur anywhere in it[14]. P3970R0, the Direction Group's January 2026 statement, comes nearest: it reports "a stream of uncoordinated proposals to address problems from different perspectives, often not even mentioning Profiles" and reasserts the P3589R2 framework as the way forward - without naming P3100[15]. The interaction question itself was identified as open eighteen months ago, in P3608R0: "We have a very unclear picture on how contracts and profiles should interact and interoperate"[30]. The question was asked before the characterization existed. The characterization is the proposal's answer. No published response has appeared.
+On the Profiles side, the published papers assert an incompatible architecture and do not engage the characterization. P3589R2 contains no occurrence of "contract", "label", or "preset" in any revision - though its latest revision (May 2025) predates the characterization's first publication, so its silence reflects timing, not agreement[37]. P3984R0 post-dates the characterization by eight months and asserts a profile that owns its semantics directly: "For example, signed arithmetic overflow is UB so a profile can define it to be wraparound like unsigned arithmetic (though I wouldn't do that), to be saturated arithmetic, or to throw an exception." The strings "P3100", "contract", and "preset" do not occur anywhere in it[14]. P3970R0, the Direction Group's January 2026 statement, comes nearest: it reports "a stream of uncoordinated proposals to address problems from different perspectives, often not even mentioning Profiles" and reasserts the P3589R2 framework as the way forward - without naming P3100[15]. Eighteen months ago, in P3608R0, the interaction question itself was identified as open: "We have a very unclear picture on how contracts and profiles should interact and interoperate"[30]. That question came first. The characterization is the proposal's answer, and no published response has appeared.
-The Profiles papers keep asserting the opposite architecture in parallel, as if both could be true. Severance fixes this: the wording review continues on its own track, and the architecture question gets its own poll.
+In parallel, the Profiles papers keep asserting the opposite architecture, as if both could be true. Severance fixes this: the wording review continues on its own track, and the architecture question gets its own poll.
---
## 7. Objections
-Each heading below is an objection this paper expects, stated in its strongest form; each response draws only on evidence already presented.
+Each heading below is an objection this paper expects, stated in its strongest form. Each response draws only on evidence already presented.
### "These polls are tautological; wording review obviously covers only its own wording." Then affirming it costs nothing
-If the separation were self-evident, Poll 1 would cost nothing and only record what everyone already believes; it is not, because Section 4 shows accumulated wording approvals settling the Section 4.4 layering without a ballot, and interrupting that default now is cheap where reversing it later has cost the committee years.
+If the separation were self-evident, Poll 1 would cost nothing and only record what everyone already believes. It is not, because Section 4 shows accumulated wording approvals settling the Section 4.4 layering without a ballot. Interrupting that default now is cheap where reversing it later has cost the committee years.
### "Nothing normative changes, so nothing is decided." The architecture still changes
@@ -215,25 +215,25 @@ If the layering claim is purely expository, Poll 1 is free - it asks EWG to affi
### "P3100R8 already is the dedicated paper, so Poll 2 is satisfied." Then the question can be put to a vote
-A paper whose title, abstract, and stated subject is the systematic treatment of undefined behavior wording is not a paper dedicated to the question of which feature owns configuration. But suppose it is. Then the layering question is formally before EWG in this review - in which case the chairs can run a poll that states it, so the record shows what was decided. Either the layering is out of scope of the wording review, or it is in scope and votable. Both answers serve the severance; the ask here is only that the committee pick one.
+A paper whose title, abstract, and stated subject is the systematic treatment of undefined behavior wording is not a paper dedicated to the question of which feature owns configuration. But suppose it is. Then the layering question is formally before EWG in this review - in which case the chairs can run a poll that states it, so the record shows what was decided. Either the layering is out of scope of the wording review, or it is in scope and votable. Both answers serve the severance - the ask is only that the committee pick one.
-A variant holds that the dedicated venue already exists in the separate EWG reviews of P3400R3 and P3589R2: adopt either and configuration ownership is settled without severance. But those reviews poll each mechanism on its own merits, not the layering between them - neither ballot asks which feature owns the other - and by the time either adoption poll runs, the characterization will carry the consensus record and case approvals of Section 4 behind it, which is the accumulation Poll 1 and Poll 2 exist to interrupt.
+A variant holds that the dedicated venue already exists in the separate EWG reviews of P3400R3 and P3589R2: adopt either and configuration ownership is settled without severance. But those reviews poll each mechanism on its own merits. Neither ballot asks which feature owns the other. By the time either adoption poll runs, the characterization will carry the consensus record and case approvals of Section 4 behind it, which is the accumulation Poll 1 and Poll 2 exist to interrupt.
### "Severing is Profiles advocacy by other means." The scope statement binds both camps
-Severance favors neither architecture; it prevents both from winning without a direct ballot. Poll 1 binds both directions: a Profiles framework paper that accumulated wording approvals would face the same scope statement. Poll 2 requires a dedicated paper from whichever side proposes the layering. The wording review proceeds unblocked. The only thing severed is the claim that has never appeared on a ballot.
+Severance favors neither architecture: it prevents both from winning without a direct ballot. Poll 1 binds both directions: a Profiles framework paper that accumulated wording approvals would face the same scope statement. Poll 2 requires a dedicated paper from whichever side proposes the layering. The wording review proceeds unblocked. The only thing severed is the claim that has never appeared on a ballot.
### "The Profiles relationship is already going to be discussed." A discussion is not a decision
-A scheduled discussion, or a reconsideration folded into a broader poll, does not decide which feature owns the configuration of runtime checking; only a poll on that question does. The three polls in Section 8 cost nothing if such a decision is already intended: Poll 2 records the intention where it exists and supplies it where it does not. A discussion that reaches no recorded decision leaves the default identified here, settlement through accumulated wording approvals (Section 4), in place.
+A scheduled discussion, or a reconsideration folded into a broader poll, does not decide which feature owns the configuration of runtime checking. Only a poll on that question does. If such a decision is already intended, the three polls in Section 8 cost nothing: Poll 2 records the intention where it exists and supplies it where it does not. A discussion that reaches no recorded decision leaves the default identified here, settlement through accumulated wording approvals (Section 4), in place.
---
## 8. Making the Design Commitment Explicit
-The concern this paper raises requires no intent on anyone's part. Through the formulations of P3100R8's Sections 4.4 and 7.2, EWG may be unintentionally committing itself to closing the design space for Profiles, one approval at a time. No one needs to choose that outcome for it to arrive; the review only needs to keep running while the claim advances unpolled. The remedy for an unintentional commitment is to make the question intentional: write it out, put it in front of EWG, and let the room decide with open eyes.
+The concern this paper raises requires no intent on anyone's part. Through the formulations of P3100R8's Sections 4.4 and 7.2, EWG may be unintentionally committing itself to closing the design space for Profiles, one approval at a time. No one needs to choose that outcome for it to arrive - the review only needs to keep running while the claim advances unpolled. The remedy for an unintentional commitment is to make the question intentional: write it out, put it in front of EWG, and let the room decide with open eyes.
-Any one of three things suffices. A minuted statement at the review sessions that approval of wording cases neither adopts nor endorses the layering. A sentence in a future revision of P3100 placing the Profiles relationship out of scope of the wording review. Or the polls below.
+Any one of three things suffices. At the review sessions, a minuted statement that approval of wording cases neither adopts nor endorses the layering. A sentence in a future revision of P3100 placing the Profiles relationship out of scope of the wording review. Or the polls below.
Severance delays nothing: as of this writing, the architecture decision is not scheduled at all. Case-by-case review has no final poll on the layering, so the decision arrives only as a side effect after the last case is approved. A dedicated paper and poll can be scheduled directly, and review proceeds in the meantime. Severance creates the venue.
@@ -241,19 +241,19 @@ A delegate who supports the wording review and has formed no view on the layerin
> **Poll 1.** EWG agrees that approval of individual undefined-behavior cases during P3100's case-by-case wording review does not adopt or endorse the layering described in P3100R8 Section 4.4 and Figure 4, in which Profiles are defined as a higher-level feature building on top of the proposal's tools, among them implicit contract assertions.
-Poll 1 is a scope statement: approving wording cases does not decide the Profiles relationship. It constrains what the approvals mean, not what the review may discuss; the case-by-case sessions proceed exactly as planned. It binds both camps - a Profiles framework paper accumulating wording approvals would face the same ruling. If EWG's view is instead that wording approvals do decide the architecture, better to have the minutes say so than to leave it implied.
+Poll 1 is a scope statement: approving wording cases does not decide the Profiles relationship. It constrains what the approvals mean, not what the review may discuss. The case-by-case sessions proceed exactly as planned. It binds both camps - a Profiles framework paper accumulating wording approvals would face the same ruling. If EWG's view is instead that wording approvals do decide the architecture, better to have the minutes say so than to leave it implied.
> **Poll 2.** Whether the Profiles framework (P3589) or the implicit-contract-assertion machinery of P3100 and its Labels (P3400) governs the configuration of runtime checking of core-language undefined behavior is to be decided by explicit EWG poll on a paper dedicated to that design question, not as a consequence of case-by-case wording approvals.
-Poll 2 is a process commitment: the layering gets its own paper and its own poll, from whichever side proposes it. Its premise is Table 1 - no poll has decided the layering - and its commitment cuts in both directions. Poll 2 also supplies the agreement P3100R8's own Section 7.2 asks for when it says the two features, if both are kept, must be specified one in terms of the other; a paper that requests that agreement cannot object to a poll that records it. If neither the Profiles authors nor the P3100 authors bring the dedicated paper, the authors of this paper will; the commitment is to a ballot, not to a particular author.
+Poll 2 is a process commitment: the layering gets its own paper and its own poll, from whichever side proposes it. Its premise is Table 1 - no poll has decided the layering - and its commitment cuts in both directions. Poll 2 also supplies the agreement P3100R8's own Section 7.2 asks for when it says the two features, if both are kept, must be specified one in terms of the other. A paper that requests that agreement cannot object to a poll that records it. If neither the Profiles authors nor the P3100 authors bring the dedicated paper, the authors of this paper will. The commitment is to the ballot itself, whoever writes the paper.
> **Poll 3.** When EWG polls on the relationship between the Profiles framework (P3589) and implicit contract assertions (P3100), EWG intends to weigh implementation and deployment experience with both architectures, and expects the dedicated paper of Poll 2 to report that experience.
-Poll 3 is an intent statement about the evidence standard. It gates no review and no ballot; it sets the evidence the dedicated paper is expected to bring, so the standard is fixed before the ballot rather than argued at it. One asymmetry belongs on the table: the named-check-set form has more deployment history today than the implicit-contract-assertion form (Section 5).
+Poll 3 is an intent statement about the evidence standard. It gates no review and no ballot. It sets the evidence the dedicated paper is expected to bring, so the standard is fixed before the ballot rather than argued at it. One asymmetry belongs on the table: the named-check-set form has more deployment history today than the implicit-contract-assertion form (Section 5).
If the polls pass, C++ gains a direct venue for the architecture decision and loses nothing: wording review proceeds, implementations proceed, experience accrues, and the layering question arrives at its own ballot with evidence the committee can weigh. If the polls fail, the architecture question continues to be settled by default, one wording case at a time, with no ballot and no reversal mechanism except the kind that cost the committee years in the Contracts and P0443 precedents (Section 4). Whoever writes the dedicated layering proposal builds on this work next.
-These three polls are themselves small consensus steps - but each names the question it decides. A named question can be debated, amended, or voted down. A default cannot.
+These three polls are themselves small consensus steps - but each names the question it decides, and a named question can be debated, amended, or voted down. A default cannot.
---
diff --git a/source/2026-07-july/d4302-require-published-paper.md b/source/2026-07-july/d4302-require-published-paper.md
index fca918b..d45e5ea 100644
--- a/source/2026-07-july/d4302-require-published-paper.md
+++ b/source/2026-07-july/d4302-require-published-paper.md
@@ -12,7 +12,7 @@ reply-to:
The committee takes recorded polls on paper revisions that were never published in a mailing.
-The pre-meeting mailing exists so that every national body can review what the committee will decide before it decides. When the revision that is polled never appeared in a mailing, the delegates who prepared from the mailing prepared against text that is not the text being decided, and the delegates who prepared most thoroughly lose the most. This paper documents the pattern at two consecutive meetings and proposes a single bright-line rule: no poll may be taken on a paper unless the polled revision appeared in a pre-meeting mailing, with one narrow exception for wording corrections at the final meeting before a release. The rule's purpose is not to block those revisions but to change what authors optimize for. When the mailed revision is the only revision that can be polled, authors make the mailed revision their best revision, and the committee stops spending its scarcest resource, the prepared attention of its delegates, on text that will not survive to the vote.
+The pre-meeting mailing exists so that every national body can review what the committee will decide before it decides. When the revision that is polled never appeared in a mailing, the delegates who prepared from the mailing prepared against text that is not the text being decided, and the delegates who prepared most thoroughly lose the most. This paper documents the pattern at two consecutive meetings and proposes a single bright-line rule: no poll may be taken on a paper unless the polled revision appeared in a pre-meeting mailing, with one narrow exception for wording corrections at the final meeting before a release. Its purpose is to change what authors optimize for, not to block those revisions. When the mailed revision is the only revision that can be polled, authors make the mailed revision their best revision. Then the committee stops spending its scarcest resource, the prepared attention of its delegates, on text that will not survive to the vote.
---
@@ -28,11 +28,11 @@ The pre-meeting mailing exists so that every national body can review what the c
The author provides information and serves at the pleasure of the committee.
-The author is the founder of the C++ Alliance. The author maintains competing proposals in the `std::execution` space: [P4003R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4003r3.pdf)[1], [P4007R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4007r3.pdf)[2], [P2583R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p2583r4.pdf)[3], and [P4100R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4100r1.pdf)[4], a coroutine-native model for byte-oriented I/O. This paper proposes a process rule that would apply to every paper in every feature area, including the author's own. The author's preferred asynchronous model competes with `std::execution`. The reader should calibrate everything that follows accordingly.
+The author is the founder of the C++ Alliance and maintains competing proposals in the `std::execution` space: [P4003R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4003r3.pdf)[1], [P4007R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4007r3.pdf)[2], [P2583R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p2583r4.pdf)[3], and [P4100R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4100r1.pdf)[4], a coroutine-native model for byte-oriented I/O. This paper proposes a process rule that would apply to every paper in every feature area, including the author's own. His preferred asynchronous model competes with `std::execution`. Accordingly, the reader should calibrate everything that follows.
-The proposed rule, if it had been in effect, would also have prevented the author from seeking a poll on any last-minute normative revision to his own papers. The author accepts that constraint.
+If it had been in effect, the proposed rule would also have prevented the author from seeking a poll on any last-minute normative revision to his own papers. The author accepts that constraint.
-This paper is one of a series by the author on committee process; companion papers on the train model, on voting dynamics, and on appointment as policy are in preparation. This paper examines the mailing and the poll.
+This paper is one of a series by the author on committee process. Companion papers on the train model, on voting dynamics, and on appointment as policy are in preparation. This paper examines the mailing and the poll.
This paper was prepared with the assistance of generative tools. The author is responsible for its content, and every quotation and citation in it has been verified against a public source.
@@ -46,19 +46,19 @@ I care about the standard more than I care about my position in the room. Two fa
### 2.1. The Conflict, Stated Plainly
-I have competing papers, and the evidence in Section 6 draws heavily from `std::execution`, the feature area my own proposals compete with. It is the largest feature area in the C++26 cycle and generates more in-meeting revisions than any other, so the proposed rule would constrain it most. That conflict is disclosed in Section 1; what follows explains why it runs opposite to this paper's argument.
+I have competing papers, and the evidence in Section 6 draws heavily from `std::execution`, the feature area my own proposals compete with. It is the largest feature area in the C++26 cycle and generates more in-meeting revisions than any other, so the proposed rule would constrain it most. That conflict is disclosed in Section 1. What follows explains why it runs opposite to this paper's argument.
If I wanted `std::execution` to ship with defects, I would argue for the opposite of what I propose here. I would argue for an environment where last-minute changes go unreviewed, where wording written in a conference room on a Tuesday is voted on Saturday. That environment maximizes defect probability, and every defect that ships makes my competing proposals look better. I am arguing for the discipline that reduces that probability. I want C++ to win even when winning costs me the competitive advantage of a rival's mistake.
-The authors of the in-meeting revisions in Section 6 did what was locally rational at every step. They invested years in `std::execution`. When specification review surfaced issues at the final meeting of the cycle, their choice was to fix the wording in the room or ship a known defect. That is not a real choice; the process left them no other. Each author, at each step, did what he believed was best for C++. The problem is structural, not personal: no amount of skill or good intention changes the risk of writing normative wording under deadline pressure and voting on it before the review chain has seen it. The authors were not given good choices.
+The authors of the in-meeting revisions in Section 6 did what was locally rational at every step. They invested years in `std::execution`. When specification review surfaced issues at the final meeting of the cycle, their choice was to fix the wording in the room or ship a known defect. That is not a real choice. The process left them no other. At each step, each author did what he believed was best for C++. The problem is structural, not personal: no amount of skill or good intention changes the risk of writing normative wording under deadline pressure and voting on it before the review chain has seen it. The authors were not given good choices.
### 2.2. What Preparation Cost Me
-I prepared for the March 2026 Croydon meeting the way the process asks every delegate to prepare. I arrived with printed notes on nineteen papers in my areas: cross-referenced wording, specification-consistency checks, and questions for authors. During the meeting week, six of those nineteen changed under me. The notes I had prepared did not become partially outdated; they were structurally invalidated, because the wording and design had moved in ways that touched every point I had written down.
+I prepared for the March 2026 Croydon meeting the way the process asks every delegate to prepare. I arrived with printed notes on nineteen papers in my areas: cross-referenced wording, specification-consistency checks, and questions for authors. During the meeting week, six of those nineteen changed under me. The notes I had prepared did not become partially outdated. They were structurally invalidated, because the wording and design had moved in ways that touched every point I had written down.
I watched design compromises get locked into the working draft under time pressure, in versions no national body expert outside the room could have reviewed. I was a new delegate, and I could see no way to object that would not mark me as the person who delayed the room. So I said nothing.
-The effect on my own behavior was immediate and measurable. I came to Croydon with notes on nineteen papers. I came to the next meeting with notes on none. No one decided to prepare less; I simply learned what the structure rewards. That is a single delegate after a single meeting. The argument of this paper is that the same incentive acts on every delegate who prepares thoroughly, and that its cumulative effect is the slow erosion of the committee's review capacity.
+The effect on my own behavior was immediate and measurable. I came to Croydon with notes on nineteen papers. I came to the next meeting with notes on none. No one decided to prepare less. I learned what the structure rewards. That is a single delegate after a single meeting. The argument of this paper is that the same incentive acts on every delegate who prepares thoroughly, and that its cumulative effect is the slow erosion of the committee's review capacity.
---
@@ -68,7 +68,7 @@ The proposed rule is a single sentence. No poll may be taken on a paper unless t
The trigger is the poll, not the presentation. Any document may be presented and discussed at any time: a draft on the committee wiki, a revision posted between mailings, a sketch on a whiteboard. Discussion is how the committee does its work, and nothing here restricts it. The rule engages only when the committee takes a poll, because a poll is the act that converts discussion into committee weight - a recorded position that later sessions treat as settled.
-The bright line is objective: did the polled revision appear in a pre-meeting mailing, yes or no. It requires no judgment about whether a change is large or small, design or wording, normative or editorial. SD-4[5] already defines the pre-meeting mailing deadline through SD-7[6] as the Monday four weeks before a meeting, and already states the purpose of that deadline: "Requiring papers to be received on time ensures that national body experts have sufficient time to consider the proposals in advance and arrive at the meeting prepared to participate in a productive discussion." The proposed rule extends that existing purpose from the agenda to the poll.
+The bright line asks one question: did the polled revision appear in a pre-meeting mailing, yes or no. It requires no judgment about whether a change is large or small, design or wording, normative or editorial. SD-4[5] already defines the pre-meeting mailing deadline through SD-7[6] as the Monday four weeks before a meeting, and already states the purpose of that deadline: "Requiring papers to be received on time ensures that national body experts have sufficient time to consider the proposals in advance and arrive at the meeting prepared to participate in a productive discussion." The proposed rule extends that existing purpose from the agenda to the poll.
There is one exception. At the last meeting before a standard's publication deadline, polls on wording corrections that preserve the mailed design are permitted. A wording correction preserves the mailed design when it does not add, remove, or rename any public-facing interface, does not change observable behavior, and does not narrow or eliminate options presented in the mailed revision. This exception exists at exactly one meeting because that is the only meeting where deferring a fix costs a full release: at every earlier meeting, the next mailing is always available, so even a wording correction can wait for it. Section 10 explains why the exception has to live where the circular problem lives, and nowhere else.
@@ -78,23 +78,23 @@ SD-4[5] permits "followup papers to an on-time paper, such as late or
## 4. The Incentive Inversion
-The first-order effect of the rule is that a revision not ready by the mailing deadline waits one mailing cycle before it can be polled. That effect is real, and it is not the reason to adopt the rule. The reason is the second-order effect: the rule changes what authors optimize for, and that change protects the committee's scarcest resource.
+The first-order effect of the rule is that a revision not ready by the mailing deadline waits one mailing cycle before it can be polled. Real as it is, that effect is not the reason to adopt the rule. The reason is the second-order effect: the rule changes what authors optimize for, and that change protects the committee's scarcest resource.
The committee's scarcest resource is the prepared attention of its delegates. A national body expert who reads a paper in the mailing, cross-references its wording, and arrives ready to engage has spent hours that do not scale and cannot be recovered. Multiply those hours across every delegate who prepares and every paper in a mailing, and preparation is the largest single investment the committee makes in the quality of the standard. It is also the investment the current structure quietly wastes.
-Consider what the current structure rewards. An author who submits polished wording by the mailing deadline exposes that wording to weeks of national body scrutiny. An author whose wording is still moving at the deadline can submit an incomplete revision, iterate in the room, and reach the same poll with far less review. The second author is not acting in bad faith; the structure simply rewards waiting. In parallel, the delegate who prepared thoroughly against the mailed revision discovers in the room that the revision has changed, and that the preparation no longer applies. The structure rewards the author who waits and penalizes the delegate who prepares. Over enough cycles, those rewards shape behavior.
+Consider what the current structure rewards. An author who submits polished wording by the mailing deadline exposes that wording to weeks of national body scrutiny. At the deadline, an author whose wording is still moving can submit an incomplete revision, iterate in the room, and reach the same poll with far less review. The second author is not acting in bad faith. Waiting is what the structure rewards. In parallel, the delegate who prepared thoroughly against the mailed revision discovers in the room that the revision has changed, and that the preparation no longer applies. Over enough cycles, those incentives shape behavior.
The proposed rule is designed to invert both incentives, and the mechanism is a short causal chain. First, if the mailed revision is the only revision that can be polled, the mailing deadline becomes the moment that decides whether a paper can advance at the next meeting. Second, an author who wants the paper to advance then has reason to make the mailed revision the strongest one, rather than treating the mailing as a checkpoint to clear and the room as the place to finish. Third, because the polled revision is the mailed revision, the version a delegate studies is the version the committee votes, so preparation keeps its value. The delegate side of this chain is the one with evidence: the n=1 record in Section 2 is a delegate who stopped preparing once preparation stopped paying. The author side is a prediction, not a proof - authors respond to the deadline that governs the outcome, and this rule moves that deadline to the mailing.
-The prediction that follows is that fewer papers end up waiting a cycle, not more. The rule reads as a delay, but it is an incentive to finish on time, and an incentive to finish on time tends to produce more finished-on-time work. A rule that only blocked late revisions would slow the committee. A rule that makes early preparation the paper's best path to a poll is intended to speed it up, by keeping the committee from spending its most expensive resource - delegate preparation - on text that will not survive to the vote. Whether the author-side incentive materializes as predicted is something the committee can observe after adopting the rule.
+The prediction that follows is that fewer papers end up waiting a cycle. Though the rule reads as a delay, it is an incentive to finish on time, and an incentive to finish on time tends to produce more finished-on-time work. A rule that only blocked late revisions would slow the committee. A rule that makes early preparation the paper's best path to a poll is intended to speed it up, by keeping the committee from spending its most expensive resource - delegate preparation - on text that will not survive to the vote. Whether the author-side incentive materializes as predicted is something the committee can observe after adopting the rule.
-This is the whole argument. The evidence that follows shows the cost of the current incentive at two consecutive meetings; the mechanism sections show why the incentive persists; and the objections section shows that the alternatives leave the incentive in place. The rule is worth adopting not for the revisions it stops but for the behavior it rewards.
+This is the whole argument. The evidence that follows shows the cost of the current incentive at two consecutive meetings, the mechanism sections show why the incentive persists, and the objections section shows that the alternatives leave the incentive in place.
---
## 5. Prior Art: A Committee Proposal, an Implementer Request, and a Sibling Committee
-This paper is not the first to identify the problem or to propose a cooling period for normative wording. This section places three pieces of prior art on the record: a committee proposal from 2021, an implementer request from 2026, and the standing practice of the sibling C committee. The three cover what they cover: the committee has proposed this discipline before, implementers have asked for it, and a peer body already operates a version of it.
+This paper is not the first to identify the problem or to propose a cooling period for normative wording. On the record it places three pieces of prior art: a committee proposal from 2021, an implementer request from 2026, and the standing practice of the sibling C committee. The three cover what they cover: the committee has proposed this discipline before, implementers have asked for it, and a peer body already operates a version of it.
### 5.1. The Committee Proposed a Cooling Period in 2021
@@ -106,7 +106,7 @@ The Library Evolution poll to adopt P2138R4 as official process did not reach co
| -: | -: | -: | -: | -: |
| 5 | 14 | 2 | 6 | 6 |
-The columns are the WG21 poll scale: strongly favor, weakly favor, neutral, weakly against, strongly against. Nineteen delegates favored adoption and twelve opposed; the recorded outcome was "No consensus." The direction had majority support and fell short of the bar. The objections were substantive and offered in good faith - concerns about gatekeeping, discouraging participation, and process weight. This paper treats P2138R4 as a direct ancestor and, in Section 9, argues that one contributing factor in its near-miss was the judgment-heavy mechanism it used, which the bright-line rule here avoids.
+The columns are the WG21 poll scale: strongly favor, weakly favor, neutral, weakly against, strongly against. Nineteen delegates favored adoption and twelve opposed. The recorded outcome was "No consensus." The direction had majority support and fell short of the bar. Offered in good faith, the objections were substantive - concerns about gatekeeping, discouraging participation, and process weight. This paper treats P2138R4 as a direct ancestor and, in Section 9, argues that one contributing factor in its near-miss was the judgment-heavy mechanism it used, which the bright-line rule here avoids.
### 5.2. Eighteen Implementers Asked the Committee to Slow Down
@@ -116,13 +116,13 @@ The people who build the standard asked for the kind of discipline P2138R4 propo
### 5.3. The C Committee Already Operates a Version of This
-The sibling C committee, ISO/IEC JTC1/SC22/WG14, operates a document deadline that a WG21 delegate would recognize. WG14 Standing Document 1[10] sets the deadline for documents in the pre-meeting collection at "four weeks prior to the meeting," and WG14's contributing guidance describes the resulting practice: "papers submitted before a meeting's mailing deadline will be discussed at the meeting. Others will be discussed at the subsequent meeting." The scheduling remains at the convener's discretion rather than an absolute prohibition, so this is a difference of degree rather than an exceptionless rule. The point stands that a peer ISO committee, producing a working standard, already treats the pre-meeting deadline as the gate for what a meeting takes up. WG21's own on-time-paper rule gates the agenda the same way; the proposed rule extends the gate to the poll.
+The sibling C committee, ISO/IEC JTC1/SC22/WG14, operates a document deadline that a WG21 delegate would recognize. WG14 Standing Document 1[10] sets the deadline for documents in the pre-meeting collection at "four weeks prior to the meeting," and WG14's contributing guidance describes the resulting practice: "papers submitted before a meeting's mailing deadline will be discussed at the meeting. Others will be discussed at the subsequent meeting." The scheduling remains at the convener's discretion rather than an absolute prohibition, so this is a difference of degree rather than an exceptionless rule. The point stands that a peer ISO committee, producing a working standard, already treats the pre-meeting deadline as the gate for what a meeting takes up. WG21's own on-time-paper rule gates the agenda the same way, and the proposed rule extends the gate to the poll.
---
## 6. The Croydon Evidence
-At the March 2026 Croydon meeting, `std::execution` papers were adopted in revisions that were first published only in the mailing that followed. This section documents that record from public sources, acknowledges the reasonable defense of each revision, and separates the design changes (the concern) from the wording corrections (not the concern).
+At the March 2026 Croydon meeting, `std::execution` papers were adopted in revisions that were first published only in the mailing that followed. This section documents that record from public sources, acknowledges the reasonable defense of each revision, and separates the design changes that concern this paper from the wording corrections that do not.
### 6.1. The Public Proof: the Mailing Date Column
@@ -130,17 +130,17 @@ The open-std.org annual papers index carries, for every paper, a "Mailing Date"
### 6.2. Design Changes Adopted in Unmailed Revisions
-**Narrowing three options to one.** [P3980R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3980r0.html)[11], "Task's Allocator Use" (Dietmar Kühl), appeared in the pre-Croydon 2026-02 mailing presenting three wording options, labeled A, B, and C, with the note that only one could be chosen. [P3980R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3980r1.html)[12] drops options B and C and was adopted at the meeting; its Mailing Date is 2026-04. The working group may well have discussed all three and directed the author to produce a clean revision with option A - that is the normal output of design review. The national body experts who read the mailing saw a choice among three; the revision that was voted presented one. Narrowing a design from three options to one is a design decision, and the revision that recorded it was never mailed before the vote.
+**Narrowing three options to one.** [P3980R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3980r0.html)[11], "Task's Allocator Use" (Dietmar Kühl), appeared in the pre-Croydon 2026-02 mailing presenting three wording options, labeled A, B, and C, with the note that only one could be chosen. [P3980R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3980r1.html)[12] drops options B and C and was adopted at the meeting. Its Mailing Date is 2026-04. Perhaps the working group discussed all three and directed the author to produce a clean revision with option A - that is the normal output of design review. The national body experts who read the mailing saw a choice among three, yet the revision that was voted presented one. Narrowing a design from three options to one is a design decision, and the revision that recorded it was never mailed before the vote.
**Making public concepts exposition-only.** [P4159R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4159r0.html)[13], "Make sender_to and receiver_of exposition-only" (Tim Song), has no previous revision and a Mailing Date of 2026-04: it was born at the meeting and adopted there. It removes two concepts from the public interface by making them exposition-only. A reasonable reader could classify this as interface simplification rather than a design change, since the underlying constraints remain and only the names become non-normative. What is not debatable is that the paper existed in no mailing at all, so it had zero days of national body review in any form before it was adopted.
**Revisions past the mailed version.** [P3941R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3941r2.html)[14], "Scheduler Affinity" (Dietmar Kühl), was the last mailed revision, in 2026-02. The revision adopted at Croydon was [P3941R4](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3941r4.html)[15], two revisions later, first mailed in 2026-04, carrying in-meeting rebasing tied to the sender-customization revisions discussed below. Kühl is among the most careful authors in the committee, and specification review examined the revision in the room. The structural fact is unchanged: the adopted revision was two revisions past anything a national body could have read in a mailing.
-**Two revisions of unmailed iteration.** [P3826R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3826r3.html)[16], "Fix Sender Algorithm Customization" (Eric Niebler), appeared in the 2026-01 mailing. The revision adopted at Croydon was [P3826R5](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3826r5.html)[17], two revisions later, first mailed in 2026-04. Its revision history records removing "the two uses of the `write_env` algorithm" for consistency with the in-meeting revision of Scheduler Affinity, integrating feedback from a specification review dated the Wednesday of the meeting week. The removal may have been a mechanical consequence of that Scheduler Affinity decision rather than a new design choice in the paper itself, and every individual change may have been correct. The concern is that the adopted revision was two revisions past the last mailed one and depended on another in-meeting revision. This is not new to Croydon: the same paper's public title history shows the design space moving from [P3826R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3826r0.html)[18], "Defer Sender Algorithm Customization to C++29," mailed before the November 2025 Kona meeting, to [P3826R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3826r1.html)[19], "Fix or Remove Sender Algorithm Customization," dated the opening day of that meeting.
+**Two revisions of unmailed iteration.** [P3826R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3826r3.html)[16], "Fix Sender Algorithm Customization" (Eric Niebler), appeared in the 2026-01 mailing. The revision adopted at Croydon was [P3826R5](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3826r5.html)[17], two revisions later, first mailed in 2026-04. Its revision history records removing "the two uses of the `write_env` algorithm" for consistency with the in-meeting revision of Scheduler Affinity, integrating feedback from a specification review dated the Wednesday of the meeting week. Rather than a new design choice in the paper itself, the removal may have been a mechanical consequence of that Scheduler Affinity decision, and every individual change may have been correct. The concern is that the adopted revision was two revisions past the last mailed one and depended on another in-meeting revision. This is not new to Croydon: the same paper's public title history shows the design space moving from [P3826R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3826r0.html)[18], "Defer Sender Algorithm Customization to C++29," mailed before the November 2025 Kona meeting, to [P3826R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3826r1.html)[19], "Fix or Remove Sender Algorithm Customization," dated the opening day of that meeting.
### 6.3. Revisions That Referenced Each Other
-The in-meeting revisions cross-referenced each other, so no one of them could be reviewed in isolation. [P3927R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3927r1.html)[20] (Eric Niebler) rebases its wording on an unmailed revision of Scheduler Affinity; P3826R5 removes `write_env` for consistency with that same revision; and [P4154R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4154r0.html)[21], "Renaming various execution things" (Tim Song, Ruslan Arutyunyan, Arthur O'Dwyer), depends on P3826R5 having been applied. Cross-references among related papers are normal, and `std::execution` is large enough that a fix in one paper naturally propagates to others. The consequence is that a delegate seeking to understand what was being voted would have needed to read all of them together, in revisions that appeared only after the meeting. The public adoption poll for P3826R5, recorded on the public paper tracker, passed 9 for, 0 against, 0 neutral[22] - a unanimous vote on a revision the national body review chain had not seen.
+The in-meeting revisions cross-referenced each other, so no one of them could be reviewed in isolation. [P3927R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3927r1.html)[20] (Eric Niebler) rebases its wording on an unmailed revision of Scheduler Affinity. P3826R5 removes `write_env` for consistency with that same revision, and [P4154R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4154r0.html)[21], "Renaming various execution things" (Tim Song, Ruslan Arutyunyan, Arthur O'Dwyer), depends on P3826R5 having been applied. Cross-references among related papers are normal, and `std::execution` is large enough that a fix in one paper naturally propagates to others. In consequence, a delegate seeking to understand what was being voted would have needed to read all of them together, in revisions that appeared only after the meeting. The public adoption poll for P3826R5, recorded on the public paper tracker, passed 9 for, 0 against, 0 neutral[22] - a unanimous vote on a revision the national body review chain had not seen.
### 6.4. Wording Corrections Are Not the Concern
@@ -150,33 +150,33 @@ Other in-meeting revisions at Croydon were wording corrections that preserved a
## 7. The Brno Evidence
-One meeting later, at the June 2026 Brno meeting, the pattern recurred in a different feature area and in a form that sharpens the rule. A committee poll authorized an ongoing review keyed to a revision that has never appeared in any mailing, while the announcement that pointed members at the paper resolves to an older revision. The account below is built entirely from the public paper tracker, the open-std index, and live URL checks.
+One meeting later, at the June 2026 Brno meeting, the pattern recurred in a different feature area and in a form that sharpens the rule. A committee poll authorized an ongoing review keyed to a revision that has never appeared in any mailing, while the announcement that pointed members at the paper resolves to an older revision. From the public paper tracker, the open-std index, and live URL checks, the account below is built entirely.
### 7.1. A Poll That Names a Revision No Mailing Contains
-The published paper is [P3100R6](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3100r6.pdf)[27], "A framework for systematically addressing undefined behaviour in the C++ Standard" (Timur Doumler, Joshua Berne), which appeared in the 2026-05 mailing. The public paper tracker records the poll taken in the Brno Evolution session on 2026-06-10, with columns for strongly favor, favor, neutral, against, and strongly against[28]:
+The published paper is [P3100R6](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3100r6.pdf)[27], "A framework for systematically addressing undefined behaviour in the C++ Standard" (Timur Doumler, Joshua Berne), which appeared in the 2026-05 mailing. On 2026-06-10, the public paper tracker records the poll taken in the Brno Evolution session, with columns for strongly favor, favor, neutral, against, and strongly against[28]:
> EWG Approves of the overall direction of P3100R7, agrees to attend/spend time reviewing every line item in Telecons, and re-consider this in Búzios.
->
-> | SF | F | N | A | SA |
-> | -: | -: | -: | -: | -: |
-> | 16 | 15 | 6 | 2 | 0 |
->
-> Result: consensus.
-The poll names P3100R7. Three independent public checks confirm that no P3100R7 exists in any mailing. The open-std.org 2026 papers index enumerates only P3100R5 and P3100R6. A direct request for the paper at its constructed open-std URL returns HTTP 404. And the short link `wg21.link/p3100r7` returns HTTP 404, because that resolver is generated from the official index, so a 404 there means the revision is not a published paper. Meanwhile `wg21.link/P3100`, the unversioned short link a member would follow from an announcement, redirects to `p3100r6.pdf` - the older revision. The only "R7" artifact available anywhere in public is a draft at `isocpp.org/files/papers/D3100R7.pdf`[29], hosted outside the mailing system, marked D for draft rather than P for published, and internally dated 2026-07-12 - roughly a month after the June poll that referenced it. A member preparing from the mailing could not have read a P3100R7, because none was ever mailed; a member following the announcement link reads R6. The most charitable reading is that "R7" was a forward reference to a revision the authors intended to publish, not a claim that one already existed. Even on that reading, the poll recorded a committee position against a revision number no delegate outside the room could open, and the only draft that now carries that number is dated after the vote.
+| SF | F | N | A | SA |
+| -: | -: | -: | -: | -: |
+| 16 | 15 | 6 | 2 | 0 |
+
+The tracker records the result as consensus.
+
+The poll names P3100R7. Three independent public checks confirm that no P3100R7 exists in any mailing. The open-std.org 2026 papers index enumerates only P3100R5 and P3100R6. A direct request for the paper at its constructed open-std URL returns HTTP 404. And the short link `wg21.link/p3100r7` returns HTTP 404, because that resolver is generated from the official index, so a 404 there means the revision is not a published paper. Meanwhile `wg21.link/P3100`, the unversioned short link a member would follow from an announcement, redirects to `p3100r6.pdf` - the older revision. The only "R7" artifact available anywhere in public is a draft at `isocpp.org/files/papers/D3100R7.pdf`[29], hosted outside the mailing system, marked D for draft rather than P for published, and internally dated 2026-07-12 - roughly a month after the June poll that referenced it. A member preparing from the mailing could not have read a P3100R7, because none was ever mailed. Following the announcement link, a member reads R6. The most charitable reading is that "R7" was a forward reference to a revision the authors intended to publish, not a claim that one already existed. Even on that reading, the poll recorded a committee position against a revision number no delegate outside the room could open, and the only draft that now carries that number is dated after the vote.
### 7.2. Why the Rule Covers Every Poll, Not Only Wording Polls
-The Brno poll is the reason the rule triggers on any poll rather than on normative-wording polls alone. This poll changed no wording; by its own text it approved an overall direction, committed the group to review every line item in telecons, and reserved reconsideration for the next meeting. Under a rule that governed only normative-wording polls, it would be permitted. Yet it still records a committee position - a consensus direction, keyed to a named revision - and a recorded direction is a starting point that later sessions build from. Even with reconsideration reserved, the review now proceeds from an approved direction keyed to a revision the mailing chain never received.
+The Brno poll is the reason the rule triggers on any poll rather than on normative-wording polls alone. This poll changed no wording. By its own text it approved an overall direction, committed the group to review every line item in telecons, and reserved reconsideration for the next meeting. Under a rule that governed only normative-wording polls, it would be permitted. Yet it still records a committee position - a consensus direction, keyed to a named revision - and a recorded direction is a starting point that later sessions build from. Even with reconsideration reserved, the review now proceeds from an approved direction keyed to a revision the mailing chain never received.
-A rule that distinguished direction polls from wording polls would therefore leave the loophole open: present an unmailed revision, take a direction poll on it, and let the accumulated weight carry the wording later. The distinction between kinds of poll is a taxonomy that a determined process can navigate around. The distinction that cannot be navigated is whether the revision appeared in a mailing. That is why the bright line is any poll on a paper, full stop.
+A rule that distinguished direction polls from wording polls would therefore leave the loophole open: present an unmailed revision, take a direction poll on it, and let the accumulated weight carry the wording later. The distinction between kinds of poll is a taxonomy that a determined process can work around. What cannot be worked around is whether the revision appeared in a mailing. So the bright line is any poll on a paper, full stop.
### 7.3. The Same Gap at Two Meetings
-The reasonable defense is that the revision was reachable to those in the room and that the authors believed adequate notice had been given. That defense measures the gap rather than closing it. A revision reachable to the delegates physically present, and to no one else, is a revision the national body review chain outside the room did not receive. The mailing exists to reach every national body expert in every member country, including those who do not attend; a document that reaches only the room is the case the mailing was designed to prevent.
+The reasonable defense is that the revision was reachable to those in the room and that the authors believed adequate notice had been given. That defense measures the gap without closing it: a revision reachable to the delegates physically present, and to no one else, is a revision the national body review chain outside the room did not receive. Reaching every national body expert in every member country, including those who do not attend, is the mailing's purpose. A document that reaches only the room is the case the mailing was designed to prevent.
-Read together with Section 6, the two meetings show the same gap in two forms. At Croydon, revisions were adopted in versions mailed only afterward. At Brno, a poll approved a direction and a review series keyed to a revision that remains unpublished, and the short link that members were pointed to resolves to a different revision. The first spends a delegate's preparation on the wrong text within a single meeting; the second sets an approved direction against a revision the review chain has not seen. Two meetings do not establish a trend, but they are the two most recent, and in neither did the process require the polled revision to have been mailed.
+Read together with Section 6, the two meetings show the same gap in two forms. At Croydon, revisions were adopted in versions mailed only afterward. At Brno, a poll approved a direction and a review series keyed to a revision that remains unpublished, and the short link that members were pointed to resolves to a different revision. Within a single meeting, the first spends a delegate's preparation on the wrong text. The second sets an approved direction against a revision the review chain has not seen. Two meetings do not establish a trend, but they are the two most recent, and in neither did the process require the polled revision to have been mailed.
---
@@ -186,27 +186,27 @@ Section 4 stated the incentive the rule creates. This section examines why the c
### 8.1. The Asymmetry Nobody Designed
-The current structure creates an asymmetry that no one intended and no one wants. Wording submitted by the mailing deadline is exposed to weeks of national body scrutiny; wording that reaches its final form in the room is exposed to the review available during a busy meeting week. Both can reach the same poll. The most thoroughly prepared wording therefore receives the most scrutiny, and wording finished in the room receives less, which is the opposite of what a review process would choose if it were designing the incentive deliberately. SD-4[5] states that "any design change made between the ballot and publication will be expected to have near-unanimous consent in subgroups and in plenary." Near-unanimous consent from delegates who could not review the final text in advance is a different thing from consent formed after weeks of mailing review, and the difference is invisible in the tally.
+The current structure creates an asymmetry that no one intended and no one wants. Wording submitted by the mailing deadline is exposed to weeks of national body scrutiny. Wording that reaches its final form in the room is exposed to the review available during a busy meeting week. Both can reach the same poll. Therefore the most thoroughly prepared wording receives the most scrutiny, and wording finished in the room receives less, which is the opposite of what a review process would choose if it were designing the incentive deliberately. SD-4[5] states that "any design change made between the ballot and publication will be expected to have near-unanimous consent in subgroups and in plenary." Near-unanimous consent from delegates who could not review the final text in advance is a different thing from consent formed after weeks of mailing review, and the difference is invisible in the tally.
### 8.2. The Consensus Threshold Flips
-The most consequential effect is a change in who must clear the consensus bar. Consider a design option that enters a paper through an in-meeting revision and is then forwarded. A stakeholder group that reviewed the mailed revision, saw no such option, and did not attend now has to assemble a two-thirds majority to remove the option at a later meeting, because the option is the status quo once it is in the working draft. Had the same option waited for the next mailing, the stakeholders would have seen it, attended, and those seeking the option would have needed the two-thirds majority to add it. The same disagreement resolves in opposite directions depending only on whether the change entered before or after a mailing. Entering through an in-meeting revision does not only skip review; it moves the burden of the supermajority from those who want the change to those who do not.
+The most consequential effect is a change in who must clear the consensus bar. Consider a design option that enters a paper through an in-meeting revision and is then forwarded. A stakeholder group that reviewed the mailed revision, saw no such option, and did not attend now has to assemble a two-thirds majority to remove the option at a later meeting, because the option is the status quo once it is in the working draft. Had the same option waited for the next mailing, the stakeholders would have seen it, attended, and those seeking the option would have needed the two-thirds majority to add it. Depending only on whether the change entered before or after a mailing, the same disagreement resolves in opposite directions. Entering through an in-meeting revision does more than skip review. It moves the burden of the supermajority from those who want the change to those who do not.
-This is also why a "forward with the following changes" poll falls within the rule. A poll that forwards a paper together with a design modification not present in any mailed revision is a poll on unmailed normative wording, and it produces the same threshold flip. The modification becomes the status quo without ever having appeared in a mailing.
+This is also why a "forward with the following changes" poll falls within the rule. A poll that forwards a paper together with a design modification not present in any mailed revision is a poll on unmailed normative wording, and it produces the same threshold flip. Without ever having appeared in a mailing, the modification becomes the status quo.
### 8.3. The Pattern Is Not Driven by the Shipping Deadline
-A natural response is that this is a symptom of end-of-cycle pressure and will subside once a standard ships. The Brno evidence in Section 7 is the counterexample: Brno was the first meeting of the C++29 cycle, with no imminent publication deadline, and the pattern appeared anyway. The pressure to revise in the room and poll the result is not only the pressure of a shipping deadline; it is the standing incentive that the current structure creates at every meeting. A deadline intensifies it, but the deadline is not its source. That is why the remedy has to be a standing rule rather than a special measure for final meetings.
+A natural response is that this is a symptom of end-of-cycle pressure and will subside once a standard ships. The Brno evidence in Section 7 is the counterexample: Brno was the first meeting of the C++29 cycle, with no imminent publication deadline, and the pattern appeared anyway. At every meeting, the pressure to revise in the room and poll the result is the standing incentive that the current structure creates. A deadline intensifies it, but the deadline is not its source, which is why the remedy has to be a standing rule rather than a special measure for final meetings.
---
## 9. Why a Bright-Line Test Outperforms Chair Judgment
-A rule that turns on a judgment call carries three costs that a rule with an objective test avoids. First, the outcome depends on the skill, knowledge, and disposition of whoever makes the call, so the same rule yields different results under different chairs - a single point of failure. Second, a judgment call is contestable: a delegate who disagrees with the assessment can challenge it, and the challenge has standing because the rule invited interpretation. Third, the volume of judgment calls is exhausting; a chair asked to evaluate whether each in-meeting revision crosses a design threshold, under time pressure, at the end of a cycle, carries a burden the process could avoid placing on any individual.
+A rule that turns on a judgment call carries three costs that a rule with an objective test avoids. First, the outcome depends on the skill, knowledge, and disposition of whoever makes the call, so the same rule yields different results under different chairs - a single point of failure. Second, a judgment call is contestable: a delegate who disagrees with the assessment can challenge it, and the challenge has standing because the rule invited interpretation. Third, the volume of judgment calls is exhausting. A chair asked to evaluate whether each in-meeting revision crosses a design threshold, under time pressure, at the end of a cycle, carries a burden the process could avoid placing on any individual.
The proposed rule has an objective test: did the polled revision appear in a mailing, yes or no. That question is consistent across chairs, leaves nothing to interpret, and takes seconds to apply, so the general case cannot turn into a contest. Judgment survives in one place only - the final-meeting exception for wording corrections - and it is bounded there by the explicit definition in Section 3 and by the group boundary in Section 10, which route any genuine design question back to an evolution group. The discretion is confined to a single meeting rather than spread across every poll at every meeting.
-P2138R4[7] is instructive here. Its cooling period was sound, and Section 5 records that it drew majority support. Its bypass mechanism, however, required an explicit, minuted decision by both the design group and the specification group - a judgment call at the moment the process is most rushed. A mechanism that depends on discretion at the hardest moment invites the objections that a bright-line test does not. The rule proposed here keeps P2138R4's insight and drops the discretion.
+P2138R4[7] is instructive here. Its cooling period was sound, and Section 5 records that it drew majority support. However, its bypass mechanism required an explicit, minuted decision by both the design group and the specification group - a judgment call at the moment the process is most rushed. A mechanism that depends on discretion at the hardest moment invites the objections that a bright-line test does not. The rule proposed here keeps P2138R4's insight and drops the discretion.
---
@@ -216,21 +216,21 @@ The rule has a circular problem that has to be stated plainly. The train model (
The final-meeting exception in Section 3 exists to resolve this, and its scope is deliberate. At the last meeting before publication, polls on wording corrections that preserve the mailed design are permitted, and a removal that reverts the working draft to a known prior state is the cleanest such correction: it adds no new design, it withdraws one. The exception is confined to that meeting because that is the only meeting where waiting for the next mailing forfeits a release. At every earlier meeting the next mailing is available, so the circular problem does not arise and no exception is needed.
-A second mechanism keeps the exception from being stretched. CWG and LWG are specification groups; their task is to render an adopted design into wording, not to change the design. When specification review at a meeting determines that a design change is needed rather than a wording correction, the paper returns to EWG or LEWG, and a design change that returns to an evolution group appears in the next pre-meeting mailing with a new revision number before any further poll. The group boundary is itself a bright line: wording corrections stay, design changes go back to evolution and therefore back to the mailing. Between the narrow final-meeting exception and the group boundary, the rule permits the removals the train model depends on without opening a general path for unmailed design changes to reach a poll.
+A second mechanism keeps the exception from being stretched. CWG and LWG are specification groups. Their task is to render an adopted design into wording. When specification review at a meeting determines that a design change is needed rather than a wording correction, the paper returns to EWG or LEWG, and a design change that returns to an evolution group appears in the next pre-meeting mailing with a new revision number before any further poll. The group boundary is itself a bright line: wording corrections stay, design changes go back to evolution and therefore back to the mailing. Between the narrow final-meeting exception and the group boundary, the rule permits the removals the train model depends on without opening a general path for unmailed design changes to reach a poll.
---
## 11. Objections, Answered
-Each objection below is stated in the strongest form the author can give it, then answered only from evidence already presented.
+Below, each objection is stated in the strongest form the author can give it, then answered only from evidence already presented.
### "The author's own paper was presented without having been mailed"
-This is true, and it is the clearest illustration of the rule's boundary. The author has presented material to a study group that was not in a pre-meeting mailing, and no poll was taken on it. That is not what the rule governs. The rule triggers on the poll, not the presentation (Section 3). Presenting an unmailed document, discussing it, and taking feedback are unrestricted; the constraint applies only when the committee converts discussion into committee weight through a poll. The author's presentation would remain permitted under the rule, and the author accepts that the rule would equally forbid him from seeking a poll on any unmailed revision of his own papers.
+This is true, and it is the clearest illustration of the rule's boundary. The author has presented material to a study group that was not in a pre-meeting mailing, and no poll was taken on it. Because it triggers on the poll (Section 3), the rule does not reach that presentation. Presenting an unmailed document, discussing it, and taking feedback are unrestricted. The constraint applies only when the committee converts discussion into committee weight through a poll. The author's presentation would remain permitted under the rule, and the author accepts that the rule would equally forbid him from seeking a poll on any unmailed revision of his own papers.
### "Iterating within a meeting is efficient, and the rule throws that away"
-The rule throws none of it away. A group that is already engaged with a paper can present revisions, discuss them, and refine wording across the meeting week, just as today. The rule does not touch presentation or discussion; it touches only the poll (Section 3). An author may iterate all week and bring the result to a poll at the next meeting, after the revision has been in a mailing. What the rule removes is not iteration but the ability to convert same-week iteration into a recorded committee position before the review chain has seen it.
+The rule throws none of it away. A group that is already engaged with a paper can present revisions, discuss them, and refine wording across the meeting week, just as today. Only the poll (Section 3) does the rule touch, not presentation or discussion. An author may iterate all week and bring the result to a poll at the next meeting, after the revision has been in a mailing. All that goes away is the ability to convert same-week iteration into a recorded committee position before the review chain has seen it.
### "Study groups rely on quick polls to steer early work, and the rule forbids them"
@@ -238,15 +238,15 @@ Study groups do take polls, and many are quick reads of the room that guide disc
### "Chairs already weigh how much has changed and decide whether re-review is needed"
-They do, and Section 9 is the response: chair discretion is a judgment call, and a judgment call is a single point of failure, is contestable, and is most burdensome at the moment the cycle is most rushed. The proposed rule does not remove the chair; it removes the burden, by replacing a judgment about the size of a change with an objective test about whether the revision was mailed.
+They do, and Section 9 is the response: chair discretion is a judgment call, and a judgment call is a single point of failure, is contestable, and is most burdensome at the moment the cycle is most rushed. The proposed rule does not remove the chair. It removes the burden, by replacing a judgment about the size of a change with an objective test about whether the revision was mailed.
### "Better stakeholder notification would solve this instead"
-Notification helps with attendance, but it cannot solve the problem the evidence describes. At Brno (Section 7), the revision named in the poll existed in no mailing; notifying a national body expert that a session is happening does not give that expert a mailed revision to have read beforehand. One cannot be notified into having reviewed a document that was never published. Notification and a mailed revision are different things, and only the second is what the review chain depends on.
+Notification helps with attendance, but it cannot solve the problem the evidence describes. At Brno (Section 7), the revision named in the poll existed in no mailing. Notifying a national body expert that a session is happening does not give that expert a mailed revision to have read beforehand. One cannot be notified into having reviewed a document that was never published. Notification and a mailed revision are different things, and only the second is what the review chain depends on.
### "Specification review examined the revision in the room"
-Specification review is real review by careful readers, and nothing here diminishes it. But specification review is not the national body review chain. The mailing reaches every national body expert in every member country, including those who never attend; the room reaches those present. The evidence in Sections 6 and 7 turns on the versions the mailing chain did not receive, not on the quality of in-room review.
+Specification review is real review by careful readers, and nothing here diminishes it. But specification review is not the national body review chain. The mailing reaches every national body expert in every member country, including those who never attend. The room reaches those present. In Sections 6 and 7, the evidence turns on the versions the mailing chain did not receive.
### "The author's competing proposals explain the paper"
@@ -254,11 +254,11 @@ The conflict is real and is disclosed in Section 1 so every reader can weigh the
### "You are proposing to slow the committee down"
-Section 4 is the answer: the rule is an incentive to finish on time, not a delay, and its predicted effect is that fewer papers wait, because the mailing deadline becomes the checkpoint authors optimize for. Section 5 records that eighteen implementers[9] separately asked the committee to slow the addition of features; the discipline proposed here is narrower than that request and aimed at review quality rather than pace.
+Section 4 is the answer: the mailing deadline becomes the checkpoint authors optimize for, and the predicted effect is that fewer papers wait. Section 5 records that eighteen implementers[9] separately asked the committee to slow the addition of features. The discipline proposed here is narrower than that request and aimed at review quality rather than pace.
### "The rule would have killed C++26"
-For each affected paper in Section 6, the rule leaves two paths: poll the last mailed revision, or defer the delta one mailing. Neither removes the feature. If a delta was important enough to justify bypassing the review chain, it was important enough to survive one mailing cycle; if it could not survive one cycle, its importance did not justify the bypass.
+For each affected paper in Section 6, the rule leaves two paths: poll the last mailed revision, or defer the delta one mailing. Neither removes the feature. If a delta was important enough to justify bypassing the review chain, it was important enough to survive one mailing cycle. If it could not survive one cycle, its importance did not justify the bypass.
### "Evaluate each in-meeting revision case by case"
@@ -266,7 +266,7 @@ A case-by-case exception reintroduces the judgment the rule removes (Section 9).
### "The rule can be used to filibuster a paper"
-If every design change reset the clock, an objector might try to force design changes at each meeting to keep a paper from ever reaching a poll. A change resets the clock only if the room adopts it, so a failed motion is not a filibuster. Where a feature is genuinely large enough that real design findings surface at every meeting, the group boundary in Section 10 handles it: specification groups make wording corrections that preserve the design, and anything requiring a design decision returns to an evolution group and the next mailing.
+If every design change reset the clock, an objector might try to force design changes at each meeting to keep a paper from ever reaching a poll. Only if the room adopts it does a change reset the clock, so a failed motion is not a filibuster. Where a feature is large enough that real design findings surface at every meeting, the group boundary in Section 10 handles it: specification groups make wording corrections that preserve the design, and anything requiring a design decision returns to an evolution group and the next mailing.
### "The rule would gridlock national body comment resolution"
@@ -276,7 +276,7 @@ During the comment-resolution cycle, national bodies submit comments that the co
## 12. Proposed Amendment to SD-4
-The following text is offered as an amendment to SD-4[5] for the committee to contemplate. It is drafted to sit alongside the existing on-time-paper rule, which already gates the agenda; this extends the same principle to the poll.
+The following text is offered as an amendment to SD-4[5] for the committee to contemplate. It is drafted to sit alongside the existing on-time-paper rule, which already gates the agenda. This extends the same principle to the poll.
> **Mailing discipline for committee polls.** No poll may be taken on a paper unless the revision under consideration appeared in a pre-meeting mailing published before the meeting at which the poll is taken. This applies to every poll on a paper, whether the poll concerns direction, design, specification, or a request to forward, and regardless of the subgroup. Presentation and discussion of any document, including drafts and revisions not in a mailing, remain unrestricted; the constraint applies only to the taking of a poll.
@@ -292,9 +292,9 @@ For a champion who brings this forward, a poll could read: "Adopt the mailing-di
## 13. Conclusion
-The record at two consecutive meetings shows the committee polling revisions that its own review chain never received. At Croydon, design changes were adopted in revisions first mailed the month after the vote. At Brno, a poll authorized an ongoing review keyed to a revision that remains unpublished, while the link members were pointed to resolved to an older one. In both cases the delegates who prepared from the mailing prepared against text that was not the text being decided.
+The record at two consecutive meetings shows the committee polling revisions that its own review chain never received. At Croydon, design changes were adopted in revisions first mailed the month after the vote. At Brno, a poll authorized an ongoing review keyed to a revision that remains unpublished, while the link that members were pointed to resolved to an older one. In both cases the delegates who prepared from the mailing prepared against text that was not the text being decided.
-The rule proposed here moves the checkpoint for a poll back to the mailing, where national body preparation already happens. Its value is the incentive it creates rather than the revisions it defers: when the mailed revision is the only revision that can be polled, the mailing deadline becomes the moment authors work toward, and the version the review chain studies becomes the version the committee votes. The predicted result is that fewer papers wait a cycle, because early preparation becomes the strategy the structure rewards.
+The rule proposed here moves the checkpoint for a poll back to the mailing, where national body preparation already happens. Its value is the incentive it creates: when the mailed revision is the only revision that can be polled, the mailing deadline becomes the moment authors work toward, and the version the review chain studies becomes the version the committee votes. Because early preparation becomes the strategy the structure rewards, the predicted result is that fewer papers wait a cycle.
What the committee keeps by adopting the rule is the return on its own preparation: the hours national body experts spend reading the mailing are spent on the text that will be decided, and the consensus recorded in a poll is consensus about a document the whole review chain could see. What the committee keeps paying without the rule is an incentive that rewards waiting and penalizes preparation, and a distance between what is published and what is decided that was present at each of the last two meetings. The instrument is the short amendment to SD-4 in Section 12: no poll on a paper unless the polled revision was in a pre-meeting mailing, with the single final-meeting exception for wording corrections. This paper asks the committee to adopt it.
diff --git a/source/2026-07-july/d4306-config-runtime-checking.md b/source/2026-07-july/d4306-config-runtime-checking.md
index 5f1d794..5a0c94e 100644
--- a/source/2026-07-july/d4306-config-runtime-checking.md
+++ b/source/2026-07-july/d4306-config-runtime-checking.md
@@ -11,9 +11,9 @@ reply-to:
## Abstract
-The named-guarantee form of safety enforcement has a decade of shipped deployment, with its production cost measured in recent years; the machinery proposed to own its configuration has none.
+The named-guarantee form of safety enforcement has a decade of shipped deployment, with its production cost measured in recent years. The machinery proposed to own its configuration has none.
-Two proposals answer one question - how a program configures the runtime checking of core-language undefined behavior - and, as P3100R8's own Section 7.2 states, if both are kept then one must be specified in terms of the other. This paper assembles the public record and measures both against criteria already in the committee's record: existing practice, implementation and deployment experience, systematic coverage of undefined behavior, and freedom from dialects. Taken one by one, those criteria settle configuration ownership for neither candidate: the P3100 model leads on systematic coverage, though that lead does not resolve ownership, because both owners consume the same enumeration; existing practice reads both ways and names different owners. The guarantee-and-dialect question - in what an expression means and in what the noexcept operator may assume about it - is configuration-selected across every checkable operation under the P3100 menu. The record also tests the architectural premise of the proposed layering - one handler slot, one menu of evaluation semantics, one configuration base in whose terms every checking facility is specified - and finds no deployment of it, removed or condemned precedents for its nearest standardized relatives, and a first integration already departing from it. On deployment the two are asymmetric, and the reason matters: what has field experience is the named-guarantee form, not either proposal's syntax, so what the Profiles model standardizes is the deployed form while what the P3100 model standardizes is the undeployed part of its lineage. This comparison is supplied for the explicit decision its companion P4297R0 asks EWG to take, on the evidence.
+Two proposals answer one question - how a program configures the runtime checking of core-language undefined behavior - and, as P3100R8's own Section 7.2 states, if both are kept then one must be specified in terms of the other. This paper assembles the public record and measures both against criteria already in the committee's record: existing practice, implementation and deployment experience, systematic coverage of undefined behavior, and freedom from dialects. Taken one by one, those criteria settle configuration ownership for neither candidate: the P3100 model leads on systematic coverage, though that lead does not resolve ownership, because both owners consume the same enumeration. Existing practice reads both ways and names different owners. Under the P3100 menu, the guarantee-and-dialect question - in what an expression means and in what the noexcept operator may assume about it - is configuration-selected across every checkable operation. The record also tests the architectural premise of the proposed layering: one handler slot, one menu of evaluation semantics, one configuration base in whose terms every checking facility is specified. It finds no deployment of that premise, removed or condemned precedents for its nearest standardized relatives, and a first integration already departing from it. On deployment the two are asymmetric: what has field experience is the named-guarantee form, not either proposal's syntax. The Profiles model therefore standardizes the deployed form, and the P3100 model standardizes the undeployed part of its lineage. This comparison is supplied for the explicit decision its companion P4297R0 asks EWG to take, on the evidence.
---
@@ -21,7 +21,7 @@ Two proposals answer one question - how a program configures the runtime checkin
### R0: July 2026
-- Initial version. Companion to P4297, which asks EWG to decide the relationship between the two proposals by an explicit poll on a dedicated paper; this is that dedicated comparison.
+- Initial version. Companion to P4297, which asks EWG to decide the relationship between the two proposals by an explicit poll on a dedicated paper. This is that dedicated comparison.
---
@@ -29,11 +29,11 @@ Two proposals answer one question - how a program configures the runtime checkin
The authors provide information and serve at the pleasure of the committee.
-Vinnie Falco is the founder of the C++ Alliance, which funds a Clang implementation and a GCC implementation of the Profiles framework; the Clang implementation is public, with regularly released experimental builds that implement the framework attributes and an initial slice of the `std::init` profile[105], and the GCC implementation is in development. Ville Voutilainen is a longtime WG21 participant and a co-author of P3608R0, which Sections 4 and 7 cite, and of P3878R0, which Section 9 cites.
+Vinnie Falco is the founder of the C++ Alliance, which funds a Clang implementation and a GCC implementation of the Profiles framework. The Clang implementation is public, with regularly released experimental builds that implement the framework attributes and an initial slice of the `std::init` profile[105], and the GCC implementation is in development. Ville Voutilainen is a longtime WG21 participant and a co-author of P3608R0, which Sections 4 and 7 cite, and of P3878R0, which Section 9 cites.
This paper is a comparison, not a request. It places the public record for two competing proposals in front of EWG (the Evolution Working Group) and measures each against criteria already in the committee's record, with the provenance of each criterion stated, and it rests on published papers and primary vendor documentation. It is a companion to P4297, and that pairing carries a disclosure of its own: read as one act, the pair does ask for something - an explicit decision - and the reader should see that construction plainly rather than discover it.
-The authors favor the Profiles direction, and the reader should weigh the paper accordingly. The deployment and implementation facts in Section 6 stand on vendor documentation and the public committee record independent of that preference, save the authors' own Clang implementation, which is disclosed as such. This paper works only from the public record; committee-internal materials may contain answers the record does not. It uses machine-assisted drafting.
+The authors favor the Profiles direction, and the reader should weigh the paper accordingly. In Section 6, the deployment and implementation facts stand on vendor documentation and the public committee record independent of that preference, save the authors' own Clang implementation, which is disclosed as such. The paper works only from the public record, and committee-internal materials may contain answers the record does not. It uses machine-assisted drafting.
This paper asks for nothing.
@@ -43,7 +43,7 @@ This paper asks for nothing.
Two bodies of work now answer the same question: how a program configures the runtime checking of core-language undefined behavior. Kept together, as P3100R8's Section 7.2 states, one of them must be defined in the other's terms. The comparison below measures the two candidate owners of that configuration against criteria already in the committee's record, and it is the dedicated comparison its companion P4297R0[8] asks EWG to weigh: P4297R0 asks for the polls, and this comparison is the record those polls would weigh.
-The related work is two-sided. One side is the implicit-contract-assertion machinery of P3100R8[1] (Doumler and Berne), which configures runtime checks through the C++26 Contracts evaluation semantics and the Labels of P3400R3[2]. The other is the Profiles framework of P3589R2[3] (Dos Reis) with the individual profiles of P3984R0[4] (Stroustrup), under which a profile owns the guarantee directly. Section 3 sets the two side by side and states why they cannot both be primary. The criteria the comparison applies are drawn from the Direction Group's P2000R5[5], the deployment-experience standard applied in P3608R0[6] and proposed in the companion P4297, the polled Hagenberg mandate, and P3874R1[7], and Section 4 states the provenance of each.
+The related work is two-sided. One side is the implicit-contract-assertion machinery of P3100R8[1] (Doumler and Berne), which configures runtime checks through the C++26 Contracts evaluation semantics and the Labels of P3400R3[2]. On the other side is the Profiles framework of P3589R2[3] (Dos Reis) with the individual profiles of P3984R0[4] (Stroustrup), under which a profile owns the guarantee directly. Section 3 sets the two side by side and states why they cannot both be primary. The criteria the comparison applies are drawn from the Direction Group's P2000R5[5], the deployment-experience standard applied in P3608R0[6] and proposed in the companion P4297, the polled Hagenberg mandate, and P3874R1[7], and Section 4 states the provenance of each.
Four contributions follow:
@@ -52,15 +52,15 @@ Four contributions follow:
3. It separates the deployed form from the unshipped specification on the deployment criterion, so the experience is weighed against the right object (Section 6).
4. It tests the layering's single-architecture premise - one handler slot, one menu of evaluation semantics, one configuration mechanism as the base every checking facility is specified in terms of - against the deployed record of failure-response mechanisms (Section 9).
-One assumption underlies the comparison: that the two configuration mechanisms cannot both be primary. The proposal asserts the dependency where the two features collide - granular, in-source control (Section 7.2) - and the partition analysis in Section 3 extends it to the general case: wherever both features speak to the same check, one must be specified in terms of the other.
+One assumption underlies the comparison: that the two configuration mechanisms cannot both be primary. Where the two features collide - granular, in-source control (Section 7.2) - the proposal asserts the dependency, and the partition analysis in Section 3 extends it to the general case: wherever both features speak to the same check, one must be specified in terms of the other.
---
## 3. Two Proposals Compete to Own One Configuration
-The two bodies of work can coexist. But P3100R8's Section 7.2, quoted below, states that if both are kept, one must be specified in terms of the other. The same paper states in its Section 4.4 that "we must make it clear which feature is responsible for providing the user-facing configuration mechanism for which tool", and its Section 7.2 restates that requirement as "we need to make it clear"[1]. Read together with the revision record in Section 10, that requirement assigns the base role to one feature, and defines the other in its terms. That arrangement is called configuration ownership here. Which feature holds it is the question compared here.
+The two bodies of work can coexist. But P3100R8's Section 7.2, quoted below, states that if both are kept, one must be specified in terms of the other. In its Section 4.4, the same paper states that "we must make it clear which feature is responsible for providing the user-facing configuration mechanism for which tool", and its Section 7.2 restates that requirement as "we need to make it clear"[1]. Read together with the revision record in Section 10, that requirement assigns the base role to one feature, and defines the other in its terms. That arrangement is called configuration ownership here. Which feature holds it is the question under comparison.
-The first is the implicit-contract-assertion machinery of [P3100R8](https://isocpp.org/files/papers/P3100R8.pdf)[1] ("A framework for systematically addressing undefined behaviour in the C++ Standard", Doumler and Berne; the current revision of the framework). It guards the runtime-checkable cases of core-language undefined behavior with implicit contract assertions, configured through the evaluation semantics of C++26 Contracts and, for in-source granularity, through the Labels proposed in [P3400R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3400r3.pdf)[2]. On how Profiles relate to that machinery, its Section 4.4, under "Configuration", states the open question and then the suggested answer:
+The first is the implicit-contract-assertion machinery of [P3100R8](https://isocpp.org/files/papers/P3100R8.pdf)[1] ("A framework for systematically addressing undefined behaviour in the C++ Standard", Doumler and Berne - the current revision of the framework). It guards the runtime-checkable cases of core-language undefined behavior with implicit contract assertions, configured through the evaluation semantics of C++26 Contracts and, for in-source granularity, through the Labels proposed in [P3400R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3400r3.pdf)[2]. On how Profiles relate to that machinery, its Section 4.4, under "Configuration", states the open question and then the suggested answer:
> There is no consensus yet on how Profiles relate to and compose with other proposals such as the holistic strategy for removing UB from C++ proposed here.
@@ -70,7 +70,7 @@ The modality is the proposal's own: "seems logical", "could be defined". Those s
> For granular, in-source control of the evaluation semantics of implicit contract assertions, we need to agree whether this happens via directives such as the ones proposed in [P3400R3] and shown here, or by using the syntax proposed in the Profiles framework as proposed in [P3589R2]. If we want to have both, we need to specify one in terms of the other to avoid an incoherent and messy design.
-Section 7.2 also states what must be avoided: a situation "where the same functionality is provided simultaneously by different features in incompatible ways"[1]. "We need to agree whether" is an invitation to decide. The agreement the proposal asks for is the decision its companion P4297 proposes EWG schedule. The proposal thus states the ownership question in its own voice, and this paper's term for the answer - configuration ownership - names what its responsibility sentence asks.
+Section 7.2 also states what must be avoided: a situation "where the same functionality is provided simultaneously by different features in incompatible ways"[1]. "We need to agree whether" is an invitation to decide. The agreement the proposal asks for is the decision its companion P4297 proposes EWG schedule. Thus the proposal states the ownership question in its own voice, and this paper's term for the answer - configuration ownership - names what its responsibility sentence asks.
The second is the Profiles framework of [P3589R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3589r2.pdf)[3] (Dos Reis) together with the individual profiles of [P3984R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3984r0.pdf)[4] (Stroustrup). The framework provides per-translation-unit activation and local suppression attributes, supports standard, implementation-defined, and third-party profiles, and constrains a profile to only reject code, never to change the meaning of code that compiles[3]. In that model the profile owns the guarantee directly. P3984R0:
@@ -82,9 +82,9 @@ P3100R8's Section 7.2 offers a second arrangement of its own, which varies the p
> Alternatively, we could design Profiles as an auditing feature rather than a configuration feature: instead of actively enabling certain configuration options, the effect of a Profile would be that the program is ill-formed if the configuration options chosen via [P3400R3] directives or other mechanisms are not compatible with the guarantees that that Profile ensures.
-Under the first branch a profile is a preset that expands to the contract machinery's directives. Under the second a profile validates a configuration it does not own: the P3400 directives select the configuration, and the profile is reduced to a conformance checker over choices made elsewhere. Both branches assign configuration ownership to the contract machinery; what varies is only whether the profile selects the configuration or polices it. The auditing branch is also not what "profile" has meant where one has been standardized: Ada's Ravenscar profile, in the language's own rationale, "is a mode of operation", and "The general idea is that a profile is equivalent to a set of configuration pragmas"[64] - active configuration, standardized since Ada 2005. The audit shape does have deployed successes: Fedora's annocheck exists "to examine how a binary was built and to check that it has all of the appropriate security hardening features enabled"[65], and Debian's blhc "checks build logs for missing hardening flags"[66]. But in both, the distributions' default build flags inject the guarantees, and the audit polices that they survived the build system. Deployed audit rides on active configuration; it does not replace it. The alternative therefore confirms the comparison's premise twice: it is a second arrangement that is itself unimplemented, and it assigns ownership to the same owner while varying only the profile's role - under a proposal whose own text says there is no consensus yet on how the two features compose.
+Under the first branch a profile is a preset that expands to the contract machinery's directives. Under the second a profile validates a configuration it does not own: the P3400 directives select the configuration, and the profile is reduced to a conformance checker over choices made elsewhere. Both branches assign configuration ownership to the contract machinery. What varies is only whether the profile selects the configuration or polices it. The auditing branch is also not what "profile" has meant where one has been standardized: Ada's Ravenscar profile, in the language's own rationale, "is a mode of operation", and "The general idea is that a profile is equivalent to a set of configuration pragmas"[64] - active configuration, standardized since Ada 2005. The audit shape does have deployed successes: Fedora's annocheck exists "to examine how a binary was built and to check that it has all of the appropriate security hardening features enabled"[65], and Debian's blhc "checks build logs for missing hardening flags"[66]. But in both, the distributions' default build flags inject the guarantees, and the audit polices that they survived the build system. Deployed audit rides on active configuration rather than replacing it. The alternative therefore confirms the comparison's premise twice: it is a second arrangement that is itself unimplemented, and it assigns ownership to the same owner while varying only the profile's role - under a proposal whose own text says there is no consensus yet on how the two features compose.
-A third arrangement divides the territory instead of assigning a base; the framework owns per-translation-unit activation and the naming of guarantees, the contract machinery owns per-assertion semantics, and neither is specified in the other's terms. The texts already quoted foreclose it. A partition holds only where the spheres never meet, and both sides put both features on the same lever: P3984R0 gives the profile author the choice of the violating case's meaning[4], and P3100R8's Section 4.4 has the profile selecting configurations of the evaluation semantics[1]. Wherever an active profile and an in-source directive speak to the same check, something must say which wins, and Section 7.2 names the alternative: "an incoherent and messy design"[1]. A precedence rule at the collision points is an ownership assignment under another name. Partition relocates the question; it does not answer it.
+A third arrangement divides the territory instead of assigning a base: the framework owns per-translation-unit activation and the naming of guarantees, the contract machinery owns per-assertion semantics, and neither is specified in the other's terms. The texts already quoted foreclose it. Only where the spheres never meet does a partition hold, and both sides put both features on the same lever: P3984R0 gives the profile author the choice of the violating case's meaning[4], and P3100R8's Section 4.4 has the profile selecting configurations of the evaluation semantics[1]. Wherever an active profile and an in-source directive speak to the same check, something must say which wins, and Section 7.2 names the alternative: "an incoherent and messy design"[1]. At the collision points, a precedence rule is an ownership assignment under another name. Partition relocates the question. It does not answer it.
### Terms used in this comparison
@@ -92,7 +92,7 @@ This comparison uses terms from the Contracts and Profiles proposals, collected
- Implicit contract assertion: a check the compiler inserts at a core-language operation that can have undefined behavior - a pointer dereference, an array index, a signed addition - evaluated like a C++26 contract assertion on the operation's precondition.
- Evaluation semantic: the mode that decides what happens when a check's predicate is false. The P3100 model uses five. Ignore performs no check and runs the operation's existing behavior. Observe calls the violation handler and then continues. Enforce calls the handler and then terminates. Quick-enforce terminates immediately, without constructing a violation object or calling a handler. Assume performs no check and lets the compiler optimize on the predicate being true, as C++ does today.
-- Quick-enforce: the evaluation semantic that terminates on a failed check with no handler and no violation object; it is what a trap instruction implements, and it is the semantic production hardening uses today.
+- Quick-enforce: the evaluation semantic that terminates on a failed check with no handler and no violation object. It is what a trap instruction implements, and it is the semantic production hardening uses today.
- Violation handler: the replaceable function C++26 Contracts calls when a checked assertion fails. Depending on the semantic it may report and continue, report and terminate, or throw.
- Const-ification: the rule that a contract predicate treats the objects it reads as const, so evaluating the check cannot itself modify program state.
- Labels: the in-source directives proposed in P3400R3 for choosing and constraining the evaluation semantic of assertions at a chosen granularity.
@@ -108,27 +108,27 @@ The first is existing practice. [P2000R5](https://www.open-std.org/jtc1/sc22/wg2
> We change the language and standard library by gradually building on previous work or by providing a better alternative to an existing feature.
-Provenance: an advisory paper of the Direction Group, not a polled committee decision. Its authors include Bjarne Stroustrup, an author on the Profiles side of this comparison, so this criterion is one a disputant helped write; if the reader rejects it on that ground, the comparison in Sections 6 and 7 rests on the vendor deployment record directly.
+Provenance: an advisory paper of the Direction Group, without a poll behind it. Its authors include Bjarne Stroustrup, an author on the Profiles side of this comparison, so this criterion is one a disputant helped write. If the reader rejects it on that ground, the comparison in Sections 6 and 7 rests on the vendor deployment record directly.
-The second is implementation and deployment experience. Provenance, disclosed in full because it is closest to this paper: [P3608R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3608r0.html)[6] ("Contracts and profiles: what can we reasonably ship in C++26") applied it in this exact domain - "the standard library hardening is existing practice, and comes with very positive field experience reports" - and is co-authored by an author of this paper (Voutilainen) together with Wakely and Dos Reis, the author of P3589R2. The same criterion is the subject of P4297[8], a companion paper by this paper's authors, whose Poll 3 proposes that EWG weigh deployment experience when it decides this relationship; that poll has not been taken, and this criterion is therefore a proposed standard from one side of the dispute, not an adopted one. It is used here because it is the criterion a comparison of shipped practice can actually be run against.
+The second is implementation and deployment experience. Provenance, disclosed in full because it is closest to this paper: [P3608R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3608r0.html)[6] ("Contracts and profiles: what can we reasonably ship in C++26") applied it in this exact domain - "the standard library hardening is existing practice, and comes with very positive field experience reports" - and is co-authored by an author of this paper (Voutilainen) together with Wakely and Dos Reis, the author of P3589R2. The same criterion is the subject of P4297[8], a companion paper by this paper's authors, whose Poll 3 proposes that EWG weigh deployment experience when it decides this relationship. That poll has not been taken, and this criterion is therefore a standard proposed by one side of the dispute and not yet adopted. It is used here because it is the criterion a comparison of shipped practice can be run against.
-The third is systematic coverage of undefined behavior. Provenance: the one criterion here with a poll behind it. The Hagenberg poll's text, as reproduced in P3656R1 and in P3100R8's own history section, reads in full: "Pursue a language safety white paper in the C++26 timeframe containing systematic treatment of core language Undefined Behavior in C++, covering Erroneous Behavior, Profiles, and Contracts. Appoint Herb and Gašper as editors" - SF 32, F 31, N 6, A 4, SA 4, consensus[25][1]. The poll approves a work item and names both features as covered subject matter; it contains no configuration or ownership language, so it enters this comparison as a mandate for the systematic treatment, not as an assignment of the base role to either feature. This criterion the comparison can weigh immediately, because the record is not contested: P3100R8's Appendix A enumerates the cases of core-language undefined behavior - 80 cases, 77 of them runtime-checkable[1] - and no Profiles paper offers an equivalent enumeration. On systematic coverage, the P3100 model leads today, and its enumeration is useful to every safety effort regardless of which proposal ships. One property of this criterion matters for the weighing: it does not discriminate between the candidate owners. The enumeration answers what to check, and either owner consumes that answer identically - a profile can guard exactly the enumerated cases, and so can implicit assertions. Weighting this criterion dominant, as its poll invites, changes the comparison's totals but not its ownership finding, because both candidates inherit the enumeration.
+The third is systematic coverage of undefined behavior. Provenance: the one criterion here with a poll behind it. The Hagenberg poll's text, as reproduced in P3656R1 and in P3100R8's own history section, reads in full: "Pursue a language safety white paper in the C++26 timeframe containing systematic treatment of core language Undefined Behavior in C++, covering Erroneous Behavior, Profiles, and Contracts. Appoint Herb and Gašper as editors" - SF 32, F 31, N 6, A 4, SA 4, consensus[25][1]. The poll approves a work item and names both features as covered subject matter. It contains no configuration or ownership language, so it enters this comparison as a mandate for the systematic treatment rather than as an assignment of the base role to either feature. This criterion the comparison can weigh immediately, because the record is not contested: P3100R8's Appendix A enumerates the cases of core-language undefined behavior - 80 cases, 77 of them runtime-checkable[1] - and no Profiles paper offers an equivalent enumeration. On systematic coverage, the P3100 model leads today, and its enumeration is useful to every safety effort regardless of which proposal ships. One property of this criterion matters for the weighing: it does not discriminate between the candidate owners. The enumeration answers what to check, and either owner consumes that answer identically - a profile can guard exactly the enumerated cases, and so can implicit assertions. Weighting this criterion dominant, as its poll invites, changes the comparison's totals but not its ownership finding, because both candidates inherit the enumeration.
The fourth is the strength of the guarantee and freedom from dialects. Provenance: [P3874R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3874r1.pdf)[7] ("Should C++ be a memory-safe language?") states the guarantee standard, and the no-dialects standard is stated inside P3100R8 itself, quoted in Section 8 - the disputants' own texts, binding on their authors if on anyone.
Criteria the reader might expect and will not find here: wording maturity, integration with the already-adopted C++26 machinery, in-source granularity, and the cost of standardizing two configuration mechanisms. Each presupposes an answer to the ownership question rather than informing it. Wording maturity measures drafting progress, not fitness to own configuration. C++26 integration presupposes that building on the newest adoption is the operative reading of the direction sentence - Section 7's second reading, weighed there. In-source granularity compares a capability Labels propose and nothing has shipped, which the deployment criterion already covers. And the dual-mechanism cost is the cost the ownership decision exists to avoid, whichever owner is chosen - an argument for deciding.
-Sections 6 through 8 weigh the remaining three criteria in turn - deployment and field experience, existing practice, the guarantee and dialects - systematic coverage having been weighed above. Section 9 applies the deployment criterion to the layering's single-architecture premise, and Section 10 records what configuration ownership has already cost in practice. The criteria differ in provenance from advisory to polled to party-proposed, and each section's finding stands on the evidence inside it.
+Sections 6 through 8 weigh the remaining three criteria in turn - deployment and field experience, existing practice, the guarantee and dialects - systematic coverage having been weighed above. Section 9 applies the deployment criterion to the layering's single-architecture premise, and Section 10 records what configuration ownership has already cost in practice. From advisory to polled to party-proposed, the criteria differ in provenance, and each section's finding stands on the evidence inside it.
---
## 5. The Record at a Glance
-The tables below collect the evidence Sections 6 through 10 source and defend. Each cell is a cited fact; the exposition follows for readers who want provenance.
+The tables below collect the evidence Sections 6 through 10 source and defend. Each cell is a cited fact. For readers who want provenance, the exposition follows.
### Table A: What Has Shipped
-Neither proposal's specification has shipped; the asymmetry is in the deployed forms.
+Neither proposal's specification has shipped. The asymmetry is in the deployed forms.
| Implementation | Shipped | Default or opt-in | Measured cost | Response |
|---|---|---|---|---|
@@ -143,7 +143,7 @@ Neither proposal's specification has shipped; the asymmetry is in the deployed f
### Table B: Specification Status
-Both sides have unshipped specifications and deployed lineage; the objects of standardization differ.
+Both sides have unshipped specifications and deployed lineage. The objects of standardization differ.
| Component | Side | Implementation | Deployment |
|---|---|---|---|
@@ -167,7 +167,7 @@ No deployed hardened library constructs a `contract_violation` object or routes
### Table D: Precedents for Global Violation Handlers and Hooks
-The surviving committee handlers own single-purpose protocols; the removed or condemned mechanisms either adjudicated a violation class program-wide or exposed a writable global slot.
+The surviving committee handlers own single-purpose protocols. The removed or condemned mechanisms either adjudicated a violation class program-wide or exposed a writable global slot.
| Mechanism | Language | Outcome | Stated reason |
|---|---|---|---|
@@ -189,7 +189,7 @@ The departures include the handling channel itself, not only the predicate evalu
### Table F: Criterion-by-Criterion Summary
-On systematic coverage the P3100 model leads; on deployment the two are asymmetric.
+On systematic coverage the P3100 model leads. On deployment the two are asymmetric.
| Criterion | Provenance | Finding |
|---|---|---|
@@ -203,18 +203,18 @@ On systematic coverage the P3100 model leads; on deployment the two are asymmetr
## 6. Deployment and Field Experience: The Record Separates the Forms
-This is the criterion P4297 asks EWG to weigh, so it comes first. The comparison has to be stated carefully, because both proposals have an undeployed specification and a deployed lineage. The two are not the same thing. This section separates them.
+This is the criterion P4297 asks EWG to weigh, so it comes first. Because both proposals have an undeployed specification and a deployed lineage, the comparison has to be stated carefully. The two are not the same thing, and this section separates them.
-First, the record of what has shipped. The named-guarantee form of safety enforcement - a vendor-defined set of named guarantees a build turns on - has shipped for a decade, with its cost measured at production scale in recent years. Its rows are tagged by check domain, because the domains differ and the comparison does not turn on blurring them:
+First, the record of what has shipped. For a decade, the named-guarantee form of safety enforcement - a vendor-defined set of named guarantees a build turns on - has shipped, with its cost measured at production scale in recent years. Its rows are tagged by check domain, because the domains differ and the comparison does not turn on blurring them:
- The C++ Core Guidelines checkers (domain: static analysis): clang-tidy has carried the `cppcoreguidelines-*` checks since LLVM 3.8 (March 2016)[11], and the MSVC Core Guidelines checker has been installed by default since Visual Studio 2017[12].
- Hardened standard libraries (domain: library-precondition checking): libc++ has shipped hardening since LLVM 18 (March 2024) with four named modes[13], where a failed check is "reliably terminated" and hardening is an Xcode 16 build setting[14], deployed across Google server-side production at an average cost of about 0.30%[15]; libstdc++ has shipped `_GLIBCXX_ASSERTIONS` since GCC 6 (2016), on by default for unoptimized builds since GCC 15[16]; and the MSVC STL has shipped hardening since Visual Studio 2022 17.14 (May 2025), where a failed check calls `__fastfail()`: "As C++26 Contracts are not yet implemented, this defaults to calling __fastfail() for hardened precondition violations."[17]
-Consumers deploy the same form at vendor scale. Apple's WebKit ships libc++ hardening at its extensive level in release builds and reports, after optimization work, that "The end to end performance cost in WebKit has been zero"[75]. Firefox 145 grew a cross-vendor build flag that enables all three vendors' hardening macros "even in non-debug builds", motivated by Mozilla's own release-mode container checks having shipped "with negligible performance impact"; the flag ships, and release defaults await performance testing[76]. And the form's failure response has already been exercised in a production fire: when GCC 15's default-on libstdc++ assertions met a live bug in Fedora Rawhide, dnf5 aborted on a `string_view` precondition with a diagnostic naming the exact failed check - triage material produced by the terminating response itself[77].
+Consumers deploy the same form at vendor scale. Apple's WebKit ships libc++ hardening at its extensive level in release builds and reports, after optimization work, that "The end to end performance cost in WebKit has been zero"[75]. Firefox 145 grew a cross-vendor build flag that enables all three vendors' hardening macros "even in non-debug builds", motivated by Mozilla's own release-mode container checks having shipped "with negligible performance impact". The flag ships, and release defaults await performance testing[76]. And the form's failure response has already been exercised in a production fire: when GCC 15's default-on libstdc++ assertions met a live bug in Fedora Rawhide, dnf5 aborted on a `string_view` precondition with a diagnostic naming the exact failed check - triage material produced by the terminating response itself[77].
-The rows span three check domains - static analysis, library preconditions, and, below, compiler-inserted core-language checking - so the unit of comparison comes first. The unit is not the domain. It is the configuration form: a named set of guarantees selected per build, the object P3589R2 and P3984R0 standardize; the decade's deployments cover that form across all three domains. Restricting the view to the core-language domain sharpens the asymmetry; it does not dissolve it. The core-language deployments in this record follow the named-guarantee pattern themselves. Android's UBSan checking ships as per-component build selections, and the response is fixed to abort[50]. Chrome's control-flow integrity is a build-enabled guarantee that kills the process[53]. Apple's `-fbounds-safety` is the newest production deployment in the lineage, a language extension "adopted on millions of lines of production C code", and its sole response is "deterministic traps"[74]. Where core-language checking reaches production, it arrives as a named, build-selected, response-fixed guarantee - not as in-source, per-assertion, handler-routed configuration.
+The rows span three check domains - static analysis, library preconditions, and, below, compiler-inserted core-language checking - so the unit of comparison comes first. The unit is not the domain. It is the configuration form: a named set of guarantees selected per build, the object P3589R2 and P3984R0 standardize. Across all three domains, the decade's deployments cover that form. Restricting the view to the core-language domain sharpens the asymmetry without dissolving it. In this record, the core-language deployments follow the named-guarantee pattern themselves. Android's UBSan checking ships as per-component build selections, and the response is fixed to abort[50]. Chrome's control-flow integrity is a build-enabled guarantee that kills the process[53]. Apple's `-fbounds-safety` is the newest production deployment in the lineage, a language extension "adopted on millions of lines of production C code", and its sole response is "deterministic traps"[74]. Where core-language checking reaches production, it arrives as a named, build-selected, response-fixed guarantee - not as in-source, per-assertion, handler-routed configuration.
-That last fact makes the section's finding independent of the unit. Choose the configuration form, the check domain, or the raw mechanism lineage; reject the discount rule below and count the kernel's reporting deployments as production. The rows move between columns. One fact does not move: no deployment, under any counting, selects semantics per assertion in source or routes a replaceable violation handler. The matches-deployed-form test compares each proposal's standardized object against that record, so its answer is the same under every unit. A reader who rejects this paper's weighing rules inherits the finding anyway.
+That last fact makes the section's finding independent of the unit. Choose the configuration form, the check domain, or the raw mechanism lineage. Reject the discount rule below and count the kernel's reporting deployments as production. The rows move between columns, but one fact does not move: no deployment, under any counting, selects semantics per assertion in source or routes a replaceable violation handler. Because the matches-deployed-form test compares each proposal's standardized object against that record, its answer is the same under every unit. A reader who rejects this paper's weighing rules inherits the finding anyway.
That the named-guarantee form ships without C++26 Contracts is stated on the public SG15 (Tooling study group) mailing list. Gabriel Dos Reis, in the October 2025 discussion of P3835:
@@ -226,23 +226,23 @@ In the same discussion, on checking shipped beyond the standard libraries:
Second, the P3100 machinery provides capabilities the deployed form does not. It supplies a single vocabulary of evaluation semantics that maps existing mechanisms - `-ftrapv`, `-fwrapv`, and the sanitizers - into one model[1]; it enumerates the cases of core-language undefined behavior systematically; and it routes a failed check through the replaceable `std::contracts` violation handler, a single customization point the model proposes for all of them. These are real capabilities the model offers, and they are properties the deployed named-guarantee sets do not provide.
-Against that, the specification record. The C++26 contract-violation runtime the P3100 model builds on ([P2900R14](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2900r14.pdf)[18]) has one compiler implementation, GCC 16.1 (April 2026), opt-in under GCC's experimental C++26 label[19]. Clang reports "No"[20]; an upstreaming of a P2900 implementation began in June 2026, gated behind `-fcontracts` and kept out of `-std=c++26` by its author's plan, with early users called "tester[s] in the early days" and the motivation stated directly: "the problems of contracts now is the lack of implementation experience and user experience"[67]. The MSVC STL states Contracts are "not yet implemented"[17]. Implicit contract assertions have, to the authors' knowledge, no implementation anywhere, and P3100R8 reports no deployment of the proposed machinery (the word "experience" does not occur in it - checked against the P3100R8 text on 2026-07-14). Labels are future tense in the proposal's own text - they "will provide the ability to choose and constrain the evaluation semantic in code"[1] - and P3400R3[2] has no compiler implementation of its core-language feature. The Profiles side now has a public, experimental implementation: the authors' own C++ Alliance Clang build, disclosed in Section 1, implements the P3589R2[3] framework attributes and an initial slice of the `std::init` profile, released as regular public builds and enforced entirely at compile time[105]; the GCC implementation remains in development. This is a partial implementation - one profile slice. [P3970R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3970r0.pdf)[26] reports that, to its authors' knowledge, a specification and an experimental Profiles implementation is being conducted in a major C++ compiler; no complete implementation is on the public record. An available compiler is not production use, so it is counted here as no deployment experience, and the same zero applies to the other side's pipeline - the in-flight Clang contracts upstreaming and any future Labels prototype - until they ship and deploy.
+Against that, the specification record. The C++26 contract-violation runtime the P3100 model builds on ([P2900R14](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2900r14.pdf)[18]) has one compiler implementation, GCC 16.1 (April 2026), opt-in under GCC's experimental C++26 label[19]. Clang reports "No"[20]. In June 2026, an upstreaming of a P2900 implementation began, gated behind `-fcontracts` and kept out of `-std=c++26` by its author's plan, with early users called "tester[s] in the early days" and the motivation stated directly: "the problems of contracts now is the lack of implementation experience and user experience"[67]. The MSVC STL states Contracts are "not yet implemented"[17]. Implicit contract assertions have, to the authors' knowledge, no implementation anywhere, and P3100R8 reports no deployment of the proposed machinery (the word "experience" does not occur in it - checked against the P3100R8 text on 2026-07-14). Labels are future tense in the proposal's own text - they "will provide the ability to choose and constrain the evaluation semantic in code"[1] - and P3400R3[2] has no compiler implementation of its core-language feature. The Profiles side now has a public, experimental implementation: the authors' own C++ Alliance Clang build, disclosed in Section 1, implements the P3589R2[3] framework attributes and an initial slice of the `std::init` profile, released as regular public builds and enforced entirely at compile time[105]. Still in development is the GCC implementation. This is a partial implementation - one profile slice. [P3970R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3970r0.pdf)[26] reports that, to its authors' knowledge, a specification and an experimental Profiles implementation is being conducted in a major C++ compiler. No complete implementation is on the public record. An available compiler is not production use, so it is counted here as no deployment experience, and the same zero applies to the other side's pipeline - the in-flight Clang contracts upstreaming and any future Labels prototype - until they ship and deploy.
-Two symmetries follow. First, "no deployment experience" applies to both proposals' specifications: what has field experience is the named-guarantee form, not either proposal's syntax. Second, both forms have a deployed lineage. The compiler-inserted check at an undefined-behavior site - the sanitizers, `-ftrapv`, `-fwrapv` - is the lineage of the P3100 model, and P3100R8 itself maps those mechanisms into its semantics[1]; the vendor-defined named guarantee set is the lineage of the Profiles model.
+Two symmetries follow. First, "no deployment experience" applies to both proposals' specifications: the field experience belongs to the named-guarantee form, and neither proposal's syntax has any. Second, both forms have a deployed lineage. The compiler-inserted check at an undefined-behavior site - the sanitizers, `-ftrapv`, `-fwrapv` - is the lineage of the P3100 model, and P3100R8 itself maps those mechanisms into its semantics[1]. The vendor-defined named guarantee set is the lineage of the Profiles model.
The two lineages do not carry the same kind of experience, and the difference motivates the discount rule this comparison applies: production deployment is the experience that counts, and a reporting mode documented as negating the mitigation counts as reporting, not defending. The rule is a corollary of the deployment criterion in the disputants' own formulations: Doumler's bar is "real deployment experience across different domains and companies" obtained by shipping "in production" (quoted below), Dos Reis's is "running products (not debug, actual retail)" (quoted above), and P3608R0's gloss is "very positive field experience reports" (Section 4). It also restates what the operators of the sanitizer family themselves say separates defending from reporting.
Kees Cook, leading kernel hardening: the sanitizers "only WARN() by default", so "system owners need to set panic_on_warn=1 too if they want to defend against attacks targeting these kinds of flaws", and his production recommendation is bounds checking with "either use panic_on_warn=1 or CONFIG_UBSAN_TRAP=y"[54]. Evgenii Stepanov, creating the one UBSan runtime "suitable for use in production": "Primary mode for this runtime, as a security hardening tool, would be abort-on-error", with "no UBSAN_OPTIONS in general", "Definitely no C++ demangling", "No stack traces" - the production variant is defined by deleting the diagnostic machinery[71]. Kostya Serebryany, co-creator of AddressSanitizer, at CppCon 2018: "Generally speaking, you cannot use ASAN in production", and "It is also not a strong security mitigation. It is easy to bypass for the attacker"[72]. Sami Tolvanen, upstreaming the kernel's control-flow integrity: the permissive reporting mode "is helpful for locating type mismatches, but should only be enabled during development"[73].
-The named-guarantee deployments run in production with measured cost: on by default for unoptimized builds in GCC 15[16], a product build setting in Xcode 16[14], default across Google server-side production at about 0.30%[15].
+In production, the named-guarantee deployments run with measured cost: on by default for unoptimized builds in GCC 15[16], a product build setting in Xcode 16[14], default across Google server-side production at about 0.30%[15].
-The sanitizer and trap-flag lineage deploys as opt-in, test-time tooling in every deployment on this record except the production instances that follow, and in those the response follows the purpose. Deployed as a security mitigation, it terminates. Android ships UBSan integer-overflow checking in production components since Android 7.0 and UBSan bounds checking in the Bluetooth stack and eleven media codecs since Android 10, aborting on failure, with diagnostics mode documented as negating the mitigation[50]. Official Chrome ships control-flow-integrity checking that kills the process on violation, with diagnostics marked "not for production use"[53]. Deployed as a debugging aid, it logs: the major distribution kernels (Ubuntu, Fedora, RHEL) ship the kernel's UBSan bounds checking in reporting mode, which prints a diagnostic and continues, while the kernel's trap mode serves builders who want the mitigation posture at the cost of all reporting[54]. The one production deployment in this lineage that both reports richly and continues execution is a sampler, and its own authors state the boundary. GWP-ASan guards a small random subset of allocations across production Android and Chrome, on Android 14 in a "recoverable" mode that delivers a full crash report and lets the app continue. Its paper states that it "is not a security mitigation tool due to its low detection probability"[70]: sampling telemetry riding on crash reporting, not a checking response. Both shapes fix the response in the build, per purpose; neither routes a replaceable violation handler.
+The sanitizer and trap-flag lineage deploys as opt-in, test-time tooling in every deployment on this record except the production instances that follow, and in those the response follows the purpose. Deployed as a security mitigation, it terminates. Android ships UBSan integer-overflow checking in production components since Android 7.0 and UBSan bounds checking in the Bluetooth stack and eleven media codecs since Android 10, aborting on failure, with diagnostics mode documented as negating the mitigation[50]. Official Chrome ships control-flow-integrity checking that kills the process on violation, with diagnostics marked "not for production use"[53]. Deployed as a debugging aid, it logs: the major distribution kernels (Ubuntu, Fedora, RHEL) ship the kernel's UBSan bounds checking in reporting mode, which prints a diagnostic and continues, while the kernel's trap mode serves builders who want the mitigation posture at the cost of all reporting[54]. In this lineage, the one production deployment that both reports richly and continues execution is a sampler, and its own authors state the boundary. GWP-ASan guards a small random subset of allocations across production Android and Chrome, on Android 14 in a "recoverable" mode that delivers a full crash report and lets the app continue. Its paper states that it "is not a security mitigation tool due to its low detection probability"[70]: sampling telemetry riding on crash reporting instead of a checking response. Per purpose, both shapes fix the response in the build. Neither routes a replaceable violation handler.
-The objects of standardization differ in the same direction. What the Profiles model standardizes - named guarantee sets selected per build - is the deployed thing itself. What the P3100 model standardizes - in-source Labels, the replaceable violation handler, implicit assertions - is the part its lineage has not deployed (the closest deployed relative, Bloomberg's in-house library-assertion family, is treated in Section 9). The one place a deployed library exposes the C++26 evaluation-semantic vocabulary, libc++'s experimental assertion semantics added in LLVM 21 (2025), selects the semantic through a vendor macro per build, not through an in-source Label per assertion, and overrides the handler at the vendor level, not the user's[13]. The first library-side adoption of the menu itself is also on the record. HPX merged contract-assertion infrastructure in July 2026 with enforce, observe, and ignore modes mapped to P2900's semantics, selected per build through a CMake option, not in source. When the review thread reached the in-source mandatory-precondition proposal P4044, the author's reply was "pre! is a nice fit with where we landed"[69].
+The objects of standardization differ in the same direction. What the Profiles model standardizes - named guarantee sets selected per build - is the deployed thing itself. What the P3100 model standardizes - in-source Labels, the replaceable violation handler, implicit assertions - is the part its lineage has not deployed (the closest deployed relative, Bloomberg's in-house library-assertion family, is treated in Section 9). The one place a deployed library exposes the C++26 evaluation-semantic vocabulary, libc++'s experimental assertion semantics added in LLVM 21 (2025), selects the semantic through a vendor macro per build rather than an in-source Label per assertion, and keeps the handler override at the vendor level, out of users' hands[13]. Also on the record is the first library-side adoption of the menu itself. HPX merged contract-assertion infrastructure in July 2026 with enforce, observe, and ignore modes mapped to P2900's semantics, selected per build through a CMake option instead of in source. When the review thread reached the in-source mandatory-precondition proposal P4044, the author's reply was "pre! is a nice fit with where we landed"[69].
-Table A (above, Section 5) records the deployment ledger for the two forms of runtime checking and the two proposals' specifications, from the vendor documentation and papers cited in this section. Neither proposal's specification has shipped; the forms differ in deployment character.
+Table A (above, Section 5) records the deployment ledger for the two forms of runtime checking and the two proposals' specifications, from the vendor documentation and papers cited in this section. Neither proposal's specification has shipped. The forms differ in deployment character.
-The proposal's authors have addressed the deployment question on the same public list, and two statements from that thread bear on the criterion directly. Timur Doumler, arguing against a Technical Specification route, describes the experience as something still to be obtained:
+On the same public list, the proposal's authors have addressed the deployment question, and two statements from that thread bear on the criterion directly. Timur Doumler, arguing against a Technical Specification route, describes the experience as something still to be obtained:
> Realistically, the only way to get that real deployment experience across different domains and companies is to put an initial feature set into the *IS* and have it ship in major compiler releases - otherwise those different domains and companies simply won't use the feature in production.[23]
@@ -250,7 +250,7 @@ Joshua Berne, defending the observe semantic, points to deployment of contract-c
> ... we've also repeatedly demonstrated that multiple different groups that have actually deployed contracts at scale in real scenarios have had the need to be able to observe contract assertions in exactly this way.[24]
-Read against this section's distinction, both statements locate the deployment on the lineage axis. Berne's evidence is for contract-checking facilities of the lineage kind - library-level checks, where the post-violation state is language-defined - not for the C++26 machinery or its Labels; Doumler's argument locates the machinery's deployment experience in the future. Neither claims field experience for the implicit-contract-assertion machinery or for Labels - the machinery the layering would make the configuration base.
+Read against this section's distinction, both statements locate the deployment on the lineage axis. Berne's evidence is for contract-checking facilities of the lineage kind - library-level checks, where the post-violation state is language-defined - not for the C++26 machinery or its Labels. Doumler's argument locates the machinery's deployment experience in the future. Neither claims field experience for the implicit-contract-assertion machinery or for Labels - the machinery the layering would make the configuration base.
The section's finding: the named-guarantee form has a decade of shipped, production-default field experience, its cost measured in recent years; both proposals' specifications have none; and the C++26 contract runtime the P3100 model builds on has a single opt-in implementation from April 2026. What EWG makes of that record against the existing-practice standard is Section 7.
@@ -266,19 +266,19 @@ On the reading that "previous work" and "an existing feature" mean the deployed,
On the reading that "previous work" means the most recently adopted work in the standard, the P3100 model builds on it: P2900 Contracts is in C++26, and P3100 extends it. This reading is available, and on P2000R5's literal sentence it is at least as direct - vendor hardening is practice, but it is not a standard feature, and P2900 is. What this reading cannot draw on is field experience: the adopted C++26 contract runtime has, as Section 6 records, a single opt-in implementation from April 2026 and no reported production deployment. Which of a deployed non-standard practice and an undeployed standard feature better satisfies "gradually building on previous work" is the kind of question the sentence does not answer by itself.
-P2000R5's sentence has a second clause - "or by providing a better alternative to an existing feature" - and it points the other way. The systematic framework of the P3100 model is the strongest candidate for that reading, and Section 4 weighs its strength under systematic coverage, where the P3100 model leads. This clause is not converted here into a separate ownership test, because whether one mechanism is a better alternative to the other is the judgment the ballot exists to make, not a record fact a comparison can settle; the deployed-practice clause, by contrast, turns on vendor documentation. The difference in treatment is disclosed here rather than left for a delegate to find.
+P2000R5's sentence has a second clause - "or by providing a better alternative to an existing feature" - and it points the other way. For that reading, the strongest candidate is the systematic framework of the P3100 model, and Section 4 weighs its strength under systematic coverage, where the P3100 model leads. This clause is not converted here into a separate ownership test, because whether one mechanism is a better alternative to the other is the judgment the ballot exists to make, not a record fact a comparison can settle. By contrast, the deployed-practice clause turns on vendor documentation. The difference in treatment is disclosed here rather than left for a delegate to find.
-The two readings are not adjudicated here; that adjudication is the ballot P4297 asks for. What the record settles is narrower and is common to both readings: one rests on a decade of deployed field experience, the other on the most recent adoption, and the two point at different owners for the configuration of runtime checking. That is why the ownership question needs a decision of its own rather than a default - the direction sentence supports both proposals, on different clauses, and only an explicit weighing of the deployment evidence chooses between them.
+The two readings are not adjudicated here. That adjudication is the ballot P4297 asks for. What the record settles is narrower and is common to both readings: one rests on a decade of deployed field experience, the other on the most recent adoption, and the two point at different owners for the configuration of runtime checking. The ownership question therefore needs a decision of its own rather than a default - the direction sentence supports both proposals, on different clauses, and only an explicit weighing of the deployment evidence chooses between them.
---
## 8. The Guarantee and the Dialect Question
-The two models assign the safety guarantee to different authors, and they expose per-configuration variation in what an expression does to different degrees. The P3100 model makes that variation configuration-selected across every checkable core-language operation, through its menu of evaluation semantics; a Profile raises the same question only where a profile author defines a non-terminating alternative meaning. This section states the assignment difference, then the variation question in two dimensions, in the proposals' own words. The first dimension is what an expression means at run time; the second is what the compiler and the `noexcept` operator may assume about it at compile time.
+The two models assign the safety guarantee to different authors, and they expose per-configuration variation in what an expression does to different degrees. Through its menu of evaluation semantics, the P3100 model makes that variation configuration-selected across every checkable core-language operation. A Profile raises the same question only where a profile author defines a non-terminating alternative meaning. This section states the assignment difference, then the variation question in two dimensions, in the proposals' own words. First comes what an expression means at run time. The second dimension is what the compiler and the `noexcept` operator may assume about it at compile time.
### The models assign the guarantee to different authors
-Under the Profiles model, a profile defines the guarantee itself. P3984R0[4] states the scope of that authorship directly: "A profile cannot change the semantics of a program beyond defining the meaning of some forms of undefined behavior." Its worked example gives the profile author the choice of meaning: "signed arithmetic overflow is UB so a profile can define it to be wraparound like unsigned arithmetic (though I wouldn't do that), to be saturated arithmetic, or to throw an exception." Under the P3100 model, a profile defines nothing; per Section 4.4 it selects a configuration preset over the proposal's evaluation semantics. The difference is who writes the guarantee: the profile author writes it, or the preset selects it from the proposal's menu.
+Under the Profiles model, a profile defines the guarantee itself. P3984R0[4] states the scope of that authorship directly: "A profile cannot change the semantics of a program beyond defining the meaning of some forms of undefined behavior." Its worked example gives the profile author the choice of meaning: "signed arithmetic overflow is UB so a profile can define it to be wraparound like unsigned arithmetic (though I wouldn't do that), to be saturated arithmetic, or to throw an exception." Under the P3100 model, a profile defines nothing. Per Section 4.4 it selects a configuration preset over the proposal's evaluation semantics. The difference is who writes the guarantee: the profile author writes it, or the preset selects it from the proposal's menu.
### The runtime meaning becomes configuration-selected
@@ -286,24 +286,24 @@ P3100R8[1] states a standard against dialects in its Section 4.3.2: "
The expected answer to this observation is that evaluation semantics select the handling of a violation, not the meaning of the expression, so a correct program means the same thing under every semantic and no dialect arises. For the overflowing case, the proposal's own mapping resists that reading: under ignore, the overflow is not handled as a violation at all but executes "well-defined replacement behaviour" - wraparound, a meaning - while under assume the identical expression is undefined and optimized on the assumption it cannot occur. Between those two, what the expression means in the case the checking exists for is different, and so is the program's standing: the overflowing execution has defined behavior under ignore and undefined behavior under assume. Which programs have defined behavior is itself selected by the configuration. And the appeal to correct programs leaves out the executions the checking exists for. Whether that satisfies Section 4.3.2's own standard is a question the wording review does not reach, because no single undefined-behavior case raises it.
-The answer has a stronger, normative form: correctness is defined by the predicate, not by the handling, so an overflowing program violates the implicit contract under every semantic - ignore does not make the program correct, it declines to check it. What that answer costs is the proposal's own mapping. P3100R8 maps `-fwrapv` as a conforming ignore "silently executing well-defined replacement behaviour", and the deployed programs built on that flag - the Linux kernel and PostgreSQL among them, quoted below - are written to wraparound semantics deliberately: their overflowing executions are the program working as designed, not bugs the chosen configuration fails to catch. The normative answer must call every such program incorrect, forfeiting the deployed lineage the mapping exists to claim. The fork is narrow:
+The answer has a stronger, normative form: correctness is defined by the predicate, not by the handling, so an overflowing program violates the implicit contract under every semantic - ignore does not make the program correct, it declines to check it. What that answer costs is the proposal's own mapping. P3100R8 maps `-fwrapv` as a conforming ignore "silently executing well-defined replacement behaviour", and the deployed programs built on that flag - the Linux kernel and PostgreSQL among them, quoted below - are written to wraparound semantics deliberately: their overflowing executions are the program working as designed rather than bugs the chosen configuration fails to catch. The normative answer must call every such program incorrect, forfeiting the deployed lineage the mapping exists to claim. The fork is narrow:
- Either ignore permits well-defined replacement behavior. Then the semantic assigns meaning, and the dialect question stands.
- Or it does not. Then the `-fwrapv` mapping fails, taking the ignore semantic's deployed lineage with it.
-One horn keeps the lineage and concedes the dialect; the other keeps the purity and forfeits the lineage. A rewording of Section 5.4 chooses a horn; it does not escape the fork.
+One horn keeps the lineage and concedes the dialect. The other keeps the purity and forfeits the lineage. Rewording Section 5.4 chooses a horn without escaping the fork.
The strongest committee form of the status-quo objection is already in print. P1407R1, responding to "Will this encourage breaking the language into dialects?": "To a certain extent, the dialects already exist. The existence of the -fwrapv and -ftrapv compiler flags testify to this."[78] The premise is correct. What answers the inference is how the deployed variation deploys: chosen once, globally, per binary. The Linux kernel pinned `-fno-strict-aliasing` in 2003 and holds the position tree-wide across two decades - "This is why we use -fwrapv, -fno-strict-aliasing etc. The standard simply is not *important*, when it is in direct conflict with reality and reliable code generation"[79]. PostgreSQL added `-fwrapv` to its configure line in 2008, after Tom Lane found GCC 4.3 "diking out a lot of security-critical overflow checks", and the flag has applied to every build since[80].
-Abseil's operating rule is categorical: "all compile options that affect the ABI of a program need to be applied to the entire build on a global basis", with `-fexceptions` and `-DNDEBUG` among its named examples[81]. The largest one-knob experiment ran on exceptions: libstdc++'s own manual states that under `-fno-exceptions` "valid C++ code with exception handling is transformed into a dialect without exception handling"[82], and P0709R3 measured the fragmentation from that single binary toggle - over half of surveyed developers under partial or total exception bans, "using a divergent language dialect"[83]. The deployed answer to existing variation is per-binary uniformity, enforced by configure lines, style rules, and link-time mismatch errors. The part with no deployed record is the part the P3100 model adds: selection per translation unit and finer, per construct, across five semantics.
+Abseil's operating rule is categorical: "all compile options that affect the ABI of a program need to be applied to the entire build on a global basis", with `-fexceptions` and `-DNDEBUG` among its named examples[81]. The largest one-knob experiment ran on exceptions: libstdc++'s own manual states that under `-fno-exceptions` "valid C++ code with exception handling is transformed into a dialect without exception handling"[82], and P0709R3 measured the fragmentation from that single binary toggle - over half of surveyed developers under partial or total exception bans, "using a divergent language dialect"[83]. Enforced by configure lines, style rules, and link-time mismatch errors, the deployed answer to existing variation is per-binary uniformity. What has no deployed record is the part the P3100 model adds: selection per translation unit and finer, per construct, across five semantics.
-The implementer record on mixing includes a relevant statement. Dionne, on translation units built with different hardening modes: the program is "technically an ODR violation" and "you may end up getting either hardening mode"; on the `-fno-exceptions` analogue: "I have seen this break in practice (this can result in e.g. libc++ calling std::abort() instead of throwing an exception that the caller intended to handle)". Since libc++ began encoding the configuration in ABI tags on its own functions, he reports no field incidents from mixed hardening modes - the mixing can be engineered safe. The bound is his own: the tags protect libc++'s own symbols through name-mangling machinery, they "do not propagate from callees to callers", user inline functions remain unprotected, and "it's not a full solution"[84] - machinery the core language, where implicit assertions would live, does not have. The status quo the objection appeals to is a record of programs refusing, per binary, the variation the objection cites.
+The implementer record on mixing includes a relevant statement. Dionne, on translation units built with different hardening modes: the program is "technically an ODR violation" and "you may end up getting either hardening mode". On the `-fno-exceptions` analogue: "I have seen this break in practice (this can result in e.g. libc++ calling std::abort() instead of throwing an exception that the caller intended to handle)". Since libc++ began encoding the configuration in ABI tags on its own functions, he reports no field incidents from mixed hardening modes - the mixing can be engineered safe. The bound is his own: the tags protect libc++'s own symbols through name-mangling machinery, they "do not propagate from callees to callers", user inline functions remain unprotected, and "it's not a full solution"[84] - machinery the core language, where implicit assertions would live, does not have. The status quo the objection appeals to is a record of programs refusing, per binary, the variation the objection cites.
### The compile-time answer becomes configuration-selected
-The question has a second dimension: the transformations the compiler may soundly apply to an expression, and the answer the `noexcept` operator gives about it, also become configuration-selected. The optimization value of undefined behavior is documented practice: Chris Lattner's account for LLVM records that undefined signed overflow licenses trip-count reasoning in loops - a wrapping definition "disables these important loop optimizations" - and that undefined null dereference "enables a broad range of optimizations"[51]. A checking semantic withdraws those licenses deliberately; that is what checking is for. The consequence for this comparison is narrower: which transformations are sound, and which expressions can throw, join the properties the configuration selects.
+In a second dimension, the transformations the compiler may soundly apply to an expression, and the answer the `noexcept` operator gives about it, also become configuration-selected. Documented practice includes the optimization value of undefined behavior: Chris Lattner's account for LLVM records that undefined signed overflow licenses trip-count reasoning in loops - a wrapping definition "disables these important loop optimizations" - and that undefined null dereference "enables a broad range of optimizations"[51]. A checking semantic withdraws those licenses deliberately, which is what checking is for. The consequence for this comparison is narrower: which transformations are sound, and which expressions can throw, join the properties the configuration selects.
-The following function appears in no proposal; it is written here to make the selection visible. Assume `g` and `h` are declared `noexcept`:
+The following function appears in no proposal. It is written here to make the selection visible. Assume `g` and `h` are declared `noexcept`:
```cpp
void f(int* p) noexcept {
@@ -317,9 +317,9 @@ void f(int* p) noexcept {
In today's C++ the dereference in the else branch is undefined on every execution that reaches it, so the compiler may delete the branch together with the test on the license of the dereference alone - locally, with no proof about callers - and know that nothing in `f` throws. Under a checking semantic of the P3100 model, the same dereference evaluates an implicit contract assertion, and the deletion license is withdrawn: absent an actual proof that no caller passes null, the check and its violation path must be generated. Because a throwing violation handler can be installed at link time, the dereference is also a potential throw site inside a `noexcept` function. The exception then meets `f`'s boundary and the program terminates, so the configuration incurs the exception scaffolding without obtaining the recovery a throwing handler exists to provide - the finding P3541R1 states directly, that the `noexcept` barrier "will cause `std::terminate()` to be called, and will compromise the recover-from-a-bug use case"[52]. Under the assume semantic, today's transformations return. Three distinct outcomes result: the branch deleted and nothing throwing, under assume as today; the branch generated and nothing throwing, under quick-enforce; the branch generated and the dereference a potential throw site, under a checking semantic with a throwing handler. Which one a given evaluation gets is selected by the same implementation-defined mechanism that selects the runtime meanings above.
-The proposal confronts the compile-time half directly. P3100R8's Section 5.5 concludes that the addition of implicit contract assertions "must not affect the result of the `noexcept` operator", because changing that result "would be a breaking change to existing code and thus cannot be seriously contemplated", and it sets out four design options that preserve the operator's value[1]. The proposal adopts the first, Option A, under which a violation handler may throw and the exception propagates out of the expression while the operator returns its prior value. As the proposal states, Option A "does not change the existing behaviour of the `noexcept` operator - and thus does not constitute a breaking change - but it changes its conceptual meaning: rather than meaning 'evaluating this expression cannot throw', it now effectively means 'evaluating this expression cannot throw unless there is a contract violation'"[1]. Option B, which forbids the throw and calls `std::terminate` instead, "precludes unwinding the stack in response to an implicit contract violation, which has important use cases"; Options C and D introduce non-throwing semantics and were not yet known when SG21 discussed the question[1].
+The proposal confronts the compile-time half directly. P3100R8's Section 5.5 concludes that the addition of implicit contract assertions "must not affect the result of the `noexcept` operator", because changing that result "would be a breaking change to existing code and thus cannot be seriously contemplated", and it sets out four design options that preserve the operator's value[1]. The proposal adopts the first, Option A, under which a violation handler may throw and the exception propagates out of the expression while the operator returns its prior value. As the proposal states, Option A "does not change the existing behaviour of the `noexcept` operator - and thus does not constitute a breaking change - but it changes its conceptual meaning: rather than meaning 'evaluating this expression cannot throw', it now effectively means 'evaluating this expression cannot throw unless there is a contract violation'"[1]. Option B, which forbids the throw and calls `std::terminate` instead, "precludes unwinding the stack in response to an implicit contract violation, which has important use cases". Options C and D introduce non-throwing semantics and were not yet known when SG21 discussed the question[1].
-The resolution was reached deliberately and is tallied in the public record: P3541R1, which first proposed Options A and B, "was discussed in SG21 and resulted in strong consensus in favour of Option A and against Option B"[1]. The recorded poll preferred "the noexcept operator to return true for such expressions, despite the fact that their evaluation can call the contract-violation handler which may throw" (SF 5, F 10, N 1, A 2, SA 1, consensus), and polled the truth-reporting option to consensus against, in the committee's public paper tracker, January 2025[85]. The proposed wording records the consequence in a note to [except.spec]: the evaluation of an expression that is not potentially-throwing "can nevertheless exit via an exception" when an implicit assertion's handler throws[1]. The question weighed in this section is the resolution's cost, not its care.
+Reached deliberately, the resolution is tallied in the public record: P3541R1, which first proposed Options A and B, "was discussed in SG21 and resulted in strong consensus in favour of Option A and against Option B"[1]. The recorded poll preferred "the noexcept operator to return true for such expressions, despite the fact that their evaluation can call the contract-violation handler which may throw" (SF 5, F 10, N 1, A 2, SA 1, consensus), and polled the truth-reporting option to consensus against, in the committee's public paper tracker, January 2025[85]. In a note to [except.spec], the proposed wording records the consequence: the evaluation of an expression that is not potentially-throwing "can nevertheless exit via an exception" when an implicit assertion's handler throws[1]. This section weighs the cost of that resolution rather than the care behind it.
The redefinition keeps the operator's answer stable by changing what the answer asserts: true no longer means the expression cannot throw, only that it cannot throw unless a contract is violated. Both properties of that arrangement were named, in advance, by the design's own architects. Berne, in the paper that restored the replaceable violation handler to the C++26 design: allowing the noexcept property "to either report an incorrect value (i.e., true for an expression that will actually throw) or vary across build modes would be a fundamental flaw in a Contracts facility for C++, opening the door to major problems being undiagnosable or even caused by the contract-checking facility"[86]. And P2969R0 - by Doumler with an author of this paper (Voutilainen) and Honermann, weighing the identical choice two years before the resolution - stated the redefinition itself: treating checks as non-throwing "would require us to change the meaning of the noexcept operator and deduced exception specifications: instead of answering the question 'can this construct throw?', they would answer the question 'can this construct throw if no contracts are violated?'"[87]. The property adopted for implicit assertions is the property the handler's architect called a fundamental flaw, in the redefined form the proposal's lead author had stated verbatim.
@@ -329,69 +329,69 @@ The proposal's side calls this scaffolding negligible - P3591R0 argues that for
The implementation therefore holds internally an answer the redefined operator no longer gives: whether the expression, implicit assertions included, can exit via an exception. A second operator that told that truth would confirm the split rather than repair it. Where the operator's answer feeds a `noexcept` specifier, the consequence is bounded by termination, as in the example above. Where the answer feeds expression-level reasoning in unguarded code - cleanup elision of the kind P3541R1's lock example shows, or algorithm selection on `noexcept(expr)` - the unannounced throw arrives where the reasoning said none could[52]. Deployed code consults the operator with measurable stakes. Giving one Bitcoin Core container class a `noexcept` move constructor and move assignment roughly doubled a vector-fill benchmark, because `std::vector` switched from copying elements to moving them[56]. ITK measured `std::vector::reserve` running "more than four times faster" from the same change[90]. And marking an `unordered_map` hasher `noexcept` was reported to lower Bitcoin Core node memory usage by roughly 9%, because libstdc++ selects its per-node layout on the hasher's noexcept-ness[91].
-The strongest committee-record defense of the redefinition is built on these same stakes. P2969R0 states the zero-overhead rationale: treating checks as potentially-throwing means "the addition of a contract check to a program can lead to a different branch being taken at compile time", an undesirable property because it "can cause 'heisenbugs' and performance degradations even if the contract check has the ignore semantic"[87]. In this comparison's terms: a truth-reporting operator would flip deployed vectors from moving to copying the moment a checking configuration made moves potentially throwing, and the redefinition is what keeps them moving. Three observations answer that defense. First, it concedes the divergence: the argument for answering true is not that the expression cannot throw but that reporting the truth would change program behavior - convenience ranked above accuracy in a correctness operator. Second, the fast path must be weighed against what it protects: vector consults the operator to keep the strong exception guarantee sound during reallocation - move only when the move cannot throw, because a throw from a half-moved buffer has no rollback. The redefinition keeps the answer stable by making it inaccurate, in exactly the configurations where a violation can throw. So the dispatch keeps selecting the no-rollback path where its premise is false. The fast path survives; the property it existed to protect does not. Third, the rationale as stated has no limiting principle: it argues that the operator should return whatever answer keeps existing code on its current codegen - a compatibility schedule, not a property report. If a boundary separates this redefinition from any other answer chosen for compatibility, P2969R0 does not state it.
+The strongest committee-record defense of the redefinition is built on these same stakes. P2969R0 states the zero-overhead rationale: treating checks as potentially-throwing means "the addition of a contract check to a program can lead to a different branch being taken at compile time", an undesirable property because it "can cause 'heisenbugs' and performance degradations even if the contract check has the ignore semantic"[87]. In this comparison's terms: a truth-reporting operator would flip deployed vectors from moving to copying the moment a checking configuration made moves potentially throwing, and the redefinition is what keeps them moving. Three observations answer that defense. First, it concedes the divergence: the argument for answering true is not that the expression cannot throw but that reporting the truth would change program behavior - convenience ranked above accuracy in a correctness operator. Second, the fast path must be weighed against what it protects: vector consults the operator to keep the strong exception guarantee sound during reallocation - move only when the move cannot throw, because a throw from a half-moved buffer has no rollback. The redefinition keeps the answer stable by making it inaccurate, in exactly the configurations where a violation can throw. So the dispatch keeps selecting the no-rollback path where its premise is false. The fast path survives, but the property it existed to protect does not. Third, the rationale as stated has no limiting principle: it argues that the operator should return whatever answer keeps existing code on its current codegen - a compatibility schedule rather than a property report. If a boundary separates this redefinition from any other answer chosen for compatibility, P2969R0 does not state it.
The alternatives that preserve the operator's unconditional meaning are also on the record. P3100R8 rejects changing the operator's result outright - having it answer that such expressions may throw - as a breaking change that "cannot be seriously contemplated"[1]. P3541R1's configurable option - which SG21 did not pursue - has the answer vary with the checking configuration, and states the consequence plainly: "a correct program can take different paths based on configuration"[52]. That is the dialect question again, now in the type system, and it is also the position a throw-defining profile occupies by default: under such a profile the truthful answer to `noexcept(a + b)` varies with the active profile.
-On this compile-time dimension the P3100 side has done the design work: it identified the interaction, weighed the options, and adopted a resolution, so this section's criticism concerns the cost of the resolution chosen, not its absence. The breadth is what separates the two models here: P3100's menu attaches the question to every checkable core-language operation, while a Profile raises it only where its author defines a non-terminating meaning. A P3984 profile that defines overflow as saturation or as a thrown exception[4] puts both the runtime meaning and `noexcept(a + b)` in front of the identical question, owes the committee the same analysis P3100R8's Section 5.5 performed, and has not supplied it. What avoids the question entirely is the terminating response: a check that traps cannot throw, and the trap-configured deployments that Section 6 records never raise it. The configurations that raise it are those in which a violation can throw - which Section 9 finds are also the contested and undeployed ones. The per-configuration-variation question therefore spans both what an expression means and what the compiler and the `noexcept` operator may assume about it, and neither proposal's wording review answers it on the other's behalf. That is the reason it belongs on a ballot of its own rather than being settled inside the wording review of either proposal.
+On this compile-time dimension the P3100 side has done the design work: it identified the interaction, weighed the options, and adopted a resolution, so the criticism here concerns the cost of the resolution chosen rather than its absence. The breadth is what separates the two models here: P3100's menu attaches the question to every checkable core-language operation, while a Profile raises it only where its author defines a non-terminating meaning. A P3984 profile that defines overflow as saturation or as a thrown exception[4] puts both the runtime meaning and `noexcept(a + b)` in front of the identical question, owes the committee the same analysis P3100R8's Section 5.5 performed, and has not supplied it. What avoids the question entirely is the terminating response: a check that traps cannot throw, and the trap-configured deployments that Section 6 records never raise it. The configurations that raise it are those in which a violation can throw - which Section 9 finds are also the contested and undeployed ones. The per-configuration-variation question therefore spans both what an expression means and what the compiler and the `noexcept` operator may assume about it, and neither proposal's wording review answers it on the other's behalf. For that reason it belongs on a ballot of its own rather than being settled inside the wording review of either proposal.
---
## 9. One Architecture for Every Facility: The Deployed Record
-The layering under comparison rests on an architectural premise: that one handler slot, one menu of evaluation semantics, and one configuration mechanism suffice as the base in whose terms every checking facility kept alongside it is specified - called here the single-architecture premise. The premise is not that the handler runs on every violation; two of the menu's semantics never invoke it. It is that the architecture as a whole is the base everything else is defined in terms of. P3100R8 describes "unified standard contract-violation handling" as a property of its design in its Section 5.2; its Section 4.4, quoted in Section 3, suggests defining a profile as a named configuration preset over that design[1]; and its Section 7.2 extends the arrangement forward, since a facility kept alongside the base must be specified in the base's terms[1]. This section applies the deployment criterion of Section 4 to the premise itself, in four parts. First, the failure responses that have shipped, with the reasons their authors state for the diversity. Second, the closest precedents the committee has itself standardized. Third, the first integration of a pre-existing checking facility into the C++26 contract-violation machinery. Fourth, what the unification claim asserts in the one place it is said to hold today.
+The layering under comparison rests on an architectural premise: that one handler slot, one menu of evaluation semantics, and one configuration mechanism suffice as the base in whose terms every checking facility kept alongside it is specified - called here the single-architecture premise. The premise is not that the handler runs on every violation: three of the menu's semantics (ignore, quick-enforce, and assume) never invoke it. It is that the architecture as a whole is the base everything else is defined in terms of. P3100R8 describes "unified standard contract-violation handling" as a property of its design in its Section 5.2; its Section 4.4, quoted in Section 3, suggests defining a profile as a named configuration preset over that design[1]; and its Section 7.2 extends the arrangement forward, since a facility kept alongside the base must be specified in the base's terms[1]. This section applies the deployment criterion of Section 4 to the premise itself, in four parts. First, the failure responses that have shipped, with the reasons their authors state for the diversity. Second, the closest precedents the committee has itself standardized. Third, the first integration of a pre-existing checking facility into the C++26 contract-violation machinery. Fourth, what the unification claim asserts in the one place it is said to hold today.
### The deployed failure responses and their stated reasons
-The oldest failure handler in this paper's record shipped as a vendor default with local replacement, specified by no standards body. When MS-DOS encountered a critical I/O error it raised interrupt 24h; COMMAND.COM supplied the default handler - the "Abort, Retry, Ignore" prompt - and any application could install its own by replacing the interrupt vector, selecting per failure among ignore, retry, abort, and, from DOS 3.0, fail[27][28]. The dialog survives in the MSVC C runtime, where Microsoft's documentation states that choosing Ignore "can result in undefined behavior since preconditions of the calling code weren't met"[29]. The exhibit is an existence proof, not a preference argument: the violation response with the longest deployment record in this comparison ran four decades as a vendor construction with local replacement and a response menu, standardized nowhere, and never as a base other checking facilities were specified in terms of.
+The oldest failure handler in this paper's record shipped as a vendor default with local replacement, specified by no standards body. When MS-DOS encountered a critical I/O error it raised interrupt 24h. COMMAND.COM supplied the default handler - the "Abort, Retry, Ignore" prompt - and any application could install its own by replacing the interrupt vector, selecting per failure among ignore, retry, abort, and, from DOS 3.0, fail[27][28]. The dialog survives in the MSVC C runtime, where Microsoft's documentation states that choosing Ignore "can result in undefined behavior since preconditions of the calling code weren't met"[29]. The exhibit is an existence proof, not a preference argument: the violation response with the longest deployment record in this comparison ran four decades as a vendor construction with local replacement and a response menu, standardized nowhere, and never as a base other checking facilities were specified in terms of.
-The sanitizers - the deployed lineage of the compiler-inserted-check form, per Section 6 - divide into combinations that ship together and combinations that cannot. UBSan combines routinely with AddressSanitizer, and the LLVM sanitizers share common reporting infrastructure. The shadow-memory sanitizers do not combine: AddressSanitizer, MemorySanitizer, and ThreadSanitizer are mutually exclusive, and their maintainers describe the exclusivity as architectural - "Instrumentations are not designed to work together and there are no plans to support it because of potential complexity of such implementation" - with the same thread dismissing a combined tool as "fantasy"[30]. Chandler Carruth, on the packaging of the runtimes in 2014: "many of the sanitizers' runtimes are really mutually exclusive and should never even be in the same runtime library"[31]. What no member of the family offers is the architecture under test here - a portable, user-replaceable violation handler spanning the family; each tool's response is its own, configured its own way.
+The sanitizers - the deployed lineage of the compiler-inserted-check form, per Section 6 - divide into combinations that ship together and combinations that cannot. UBSan combines routinely with AddressSanitizer, and the LLVM sanitizers share common reporting infrastructure. The shadow-memory sanitizers do not combine: AddressSanitizer, MemorySanitizer, and ThreadSanitizer are mutually exclusive, and their maintainers describe the exclusivity as architectural - "Instrumentations are not designed to work together and there are no plans to support it because of potential complexity of such implementation" - with the same thread dismissing a combined tool as "fantasy"[30]. Chandler Carruth, on the packaging of the runtimes in 2014: "many of the sanitizers' runtimes are really mutually exclusive and should never even be in the same runtime library"[31]. What no member of the family offers is the architecture under test here - a portable, user-replaceable violation handler spanning the family. Each tool's response is its own, configured its own way.
-The pressure toward diverse responses operates even inside one tool: reviewing an addition to UBSan's failure-response options in 2015, Richard Smith observed, "I worry that we're piling on more and more ways of responding to ubsan failures with no underlying principled design"[32]. The remark asks for the principled design the unified model now proposes. The options it worried over - trap mode for code size, a full runtime for diagnostics, user-supplied handler libraries for specialized environments - are the field's answers to constraints this section catalogues, and the pile grew after the warning, with a minimal runtime for constrained targets added in 2017. Any principled candidate would satisfy Smith's ask: a named-guarantee architecture with local response ownership answers the worry as directly as a unified handler does, and the constraints that grew the pile are absorbed by the unified model only through absence - the quick-enforce finding later in this section.
+Even inside one tool, the pressure toward diverse responses operates: reviewing an addition to UBSan's failure-response options in 2015, Richard Smith observed, "I worry that we're piling on more and more ways of responding to ubsan failures with no underlying principled design"[32]. Smith's remark asks for the principled design the unified model now proposes. The options it worried over - trap mode for code size, a full runtime for diagnostics, user-supplied handler libraries for specialized environments - are the field's answers to constraints this section catalogues, and the pile grew after the warning, with a minimal runtime for constrained targets added in 2017. Any principled candidate would satisfy Smith's ask: a named-guarantee architecture with local response ownership answers the worry as directly as a unified handler does, and the constraints that grew the pile are absorbed by the unified model only through absence - the quick-enforce finding later in this section.
-The deployed funnels mark the same boundary. glog's process-global failure function unifies checking only across the libraries that adopt glog, and Qt's installable message handler delegates reporting across every Qt module while the fatal response stays Qt's own: "The message handler should always return. For fatal messages, the application aborts immediately after handling that message."[104] Reporting is delegable; policy is not.
+The deployed funnels mark the same boundary. glog's process-global failure function unifies checking only across the libraries that adopt glog, and Qt's installable message handler delegates reporting across every Qt module while the fatal response stays Qt's own: "The message handler should always return. For fatal messages, the application aborts immediately after handling that message."[104] Reporting is delegable. Policy is not.
The three hardened standard libraries chose three different failure mechanisms, and each vendor has stated its reasons. The one customization among them - MSVC's substitutable termination function - is selected at compile time and receives no violation object[17].
-Table C (above, Section 5) records the failure mechanisms of the deployed hardened standard libraries and the GSL, from the vendor documentation and maintainer statements cited in this section. None constructs a `contract_violation` object or routes through a replaceable violation handler; the third column records what each vendor allows instead.
+Table C (above, Section 5) records the failure mechanisms of the deployed hardened standard libraries and the GSL, from the vendor documentation and maintainer statements cited in this section. None constructs a `contract_violation` object or routes through a replaceable violation handler. The third column records what each vendor allows instead.
-These are recent, argued choices, and the customization that survives at the vendor level was argued for too. When libc++'s hardening work proposed dropping its override point, Chromium objected that crash-report control in the field depended on it, and the maintainers kept it - "this is something that we need to keep"[60]. The design line they state elsewhere is "simplicity over unbounded configurability"[60]. libc++'s maintainers, on why the failure handler is not link-time replaceable: "We've been there before and we basically tried all the possible different ways of customizing this before we ended up where we are. We tried link-time overriding, but that is too heavy when you need to generate a single instruction to trap"[33]; the deployment report behind that constraint records a two percent binary-size increase from the verbose failure path as a blocker in certain environments, reduced below half a percent by the trap[34]. Microsoft's mechanism is a kernel-level fast-fail because "critical failures that may have corrupted program state and stack beyond recovery cannot be handled by the regular exception handling facility", and on a fast-fail no exception handlers run because "the program is expected to be in a corrupted state"[35]. Both halves of Microsoft's framing belong in the record: the tracked plan is to report hardened-precondition violations through C++26 contract violations once MSVC implements Contracts, and that work is unshipped. What shipped bypasses even the CRT's customizable invalid-parameter handler, on the maintainer's stated security rationale - fastfail "gives attackers fewer opportunities to exploit running code", the "new guidance from our internal teams" that displaced the configurable-handler path of the 2005 `_SECURE_SCL` era[68].
+These are recent, argued choices, and the customization that survives at the vendor level was argued for too. When libc++'s hardening work proposed dropping its override point, Chromium objected that crash-report control in the field depended on it, and the maintainers kept it - "this is something that we need to keep"[60]. The design line they state elsewhere is "simplicity over unbounded configurability"[60]. libc++'s maintainers, on why the failure handler is not link-time replaceable: "We've been there before and we basically tried all the possible different ways of customizing this before we ended up where we are. We tried link-time overriding, but that is too heavy when you need to generate a single instruction to trap"[33]. The deployment report behind that constraint records a two percent binary-size increase from the verbose failure path as a blocker in certain environments, reduced below half a percent by the trap[34]. Microsoft's mechanism is a kernel-level fast-fail because "critical failures that may have corrupted program state and stack beyond recovery cannot be handled by the regular exception handling facility", and on a fast-fail no exception handlers run because "the program is expected to be in a corrupted state"[35]. Both halves of Microsoft's framing belong in the record: the tracked plan is to report hardened-precondition violations through C++26 contract violations once MSVC implements Contracts, and that work is unshipped. What shipped bypasses even the CRT's customizable invalid-parameter handler, on the maintainer's stated security rationale - fastfail "gives attackers fewer opportunities to exploit running code", the "new guidance from our internal teams" that displaced the configurable-handler path of the 2005 `_SECURE_SCL` era[68].
-Apple's feedback paper on P2900's handler states the same constraints in general form: on constrained deployments a violation must generate "no code at all beyond the equivalent of a branch and a `__builtin_trap()`", and constructing a `std::contract_violation` object is "akin to generating an RTTI-like structure for each individual contract predicate, which doesn't scale"[37]. The same paper states that "link-time customization is basically an invitation for non-benign ODR violation bugs"[37]; link-time replacement is the customization model P2900 standardizes for the violation handler[18].
+Apple's feedback paper on P2900's handler states the same constraints in general form: on constrained deployments a violation must generate "no code at all beyond the equivalent of a branch and a `__builtin_trap()`", and constructing a `std::contract_violation` object is "akin to generating an RTTI-like structure for each individual contract predicate, which doesn't scale"[37]. The same paper states that "link-time customization is basically an invitation for non-benign ODR violation bugs"[37]. Link-time replacement is the customization model P2900 standardizes for the violation handler[18].
-Section 6 records the one deployed adoption of the C++26 vocabulary, and the adoption was deliberate: libc++'s LLVM 21 assertion semantics take their names from the standard by design, and its deployment report presents the correspondence as alignment with C++26[13][34]. The shape of the adoption is the evidence here: the semantic is selected through a vendor macro per build, and the handler override is reserved to the vendor[13]. The vocabulary unified; the handler and its configuration did not.
+Section 6 records the one deployed adoption of the C++26 vocabulary, and the adoption was deliberate: libc++'s LLVM 21 assertion semantics take their names from the standard by design, and its deployment report presents the correspondence as alignment with C++26[13][34]. The shape of the adoption is the evidence here: the semantic is selected through a vendor macro per build, and the handler override is reserved to the vendor[13]. The vocabulary unified, but the handler and its configuration did not.
-The same divergence appears wherever checking ships at scale, inside and outside C++. The requirement that the application own the response is old committee record: Electronic Arts' 2007 account of why the game industry replaced the standard `assert` states that "there is no way to override it or intercept it and redirect it to application-provided facilities", and that "assert usage is verboten because it operates outside the application's control"[61] - a demand for application ownership of one facility's response, the per-facility shape every deployed handler in this section takes. The demand recurs: a 2023 RapidJSON issue raised the same objection to terminating assertions, and the accepted remedy was the library's own customization point, `RAPIDJSON_ASSERT` - answered locally, per facility, again[99].
+Wherever checking ships at scale, inside and outside C++, the same divergence appears. The requirement that the application own the response is old committee record: Electronic Arts' 2007 account of why the game industry replaced the standard `assert` states that "there is no way to override it or intercept it and redirect it to application-provided facilities", and that "assert usage is verboten because it operates outside the application's control"[61] - a demand for application ownership of one facility's response, the per-facility shape every deployed handler in this section takes. The demand recurs: a 2023 RapidJSON issue raised the same objection to terminating assertions, and the accepted remedy was the library's own customization point, `RAPIDJSON_ASSERT` - answered locally, per facility, again[99].
LLVM routed all fatal conditions through one `report_fatal_error` channel for years and split it in 2025 into separate internal-error and usage-error functions, because one channel could not serve both a compiler bug and a bad command line[38]. Chromium maintains a family of checking mechanisms with distinct responses - CHECK, DCHECK, NOTREACHED, LOG(DFATAL), DLOG(FATAL), and ReportBadMessage - the last of which terminates the sending process rather than the receiving one, because a compromised renderer process must not be able to bring down the browser by sending a message that fails the browser's checks[39]. Rust deploys the closest thing to a standardized handler-and-menu design: a per-build choice between unwinding and aborting, and on freestanding targets one replaceable panic handler. Even there, context overrides the configured policy - a panic reaching a foreign-function boundary aborts regardless of the selected strategy[41] - and a co-lead of the Rust language design team summarizes the field: "virtually every network service I know of ships either with panic=abort or without really leveraging unwinding to recover, just to take cleanup actions and then exit"[62].
Automotive functional-safety standards state the independence constraint in primary sources. The EGAS monitoring concept standardized across German engine-control manufacturers requires that "System reactions are triggered independently of the function controller in case of fault", so that a fault in the function cannot suppress the response. ZVEI's 2025 guideline for ISO 26262 software requires the same independence at the highest integrity level on the unit[96], and a public summary of ISO 26262, whose own text is not publicly retrievable, states the same monitor-independence requirement[42]. A response policy inside the failing process receives no independence credit under any of these formulations - which cuts against rich in-process handling under either model, where a bare trap escalates the decision to an external supervisor.
-Where cross-facility unification does deploy, it sits on the other side of the trap. The unifier production systems actually share is the out-of-process crash reporter. Crashpad's design document states why: the crashed program "has often crashed because of corrupt global state - such as heap", so reports must be generated "with as little execution in the crashed process as possible", and the handler "runs in a separate process from the client"[97]; its predecessor Breakpad states the operating constraint flatly - "Use of the application heap is forbidden"[97]. Production unification of failure handling happens after the trap, outside the process: the trap-plus-external-supervisor architecture the terminating deployments in this section presuppose. Nor is the direction C++'s alone: Go's team calls the one non-terminating boundary its ecosystem deployed at scale, the HTTP server's per-request recovery, "a historical mistake", and .NET, having operated a unified catchable-exception architecture over corrupted states, withdrew it in stages until "recovery from corrupted process state exceptions is not supported"[98].
+Where cross-facility unification does deploy, it sits on the other side of the trap. The unifier production systems actually share is the out-of-process crash reporter. Crashpad's design document states why: the crashed program "has often crashed because of corrupt global state - such as heap", so reports must be generated "with as little execution in the crashed process as possible", and the handler "runs in a separate process from the client"[97]. Its predecessor Breakpad states the operating constraint flatly - "Use of the application heap is forbidden"[97]. Production unification of failure handling happens after the trap, outside the process: the trap-plus-external-supervisor architecture the terminating deployments in this section presuppose. Nor is the direction C++'s alone: Go's team calls the one non-terminating boundary its ecosystem deployed at scale, the HTTP server's per-request recovery, "a historical mistake", and .NET, having operated a unified catchable-exception architecture over corrupted states, withdrew it in stages until "recovery from corrupted process state exceptions is not supported"[98].
-The closest deployed analogue of the unified model is Bloomberg's BDE assertion family, and it is real and scoped. BDE installs a process-global, replaceable violation handler that receives a violation object, and assertion levels select checking per build[40]. The family is two-tiered, and its own public sources draw the line. `bsls_review` logs and continues: its default handler logs the violation and returns rather than aborting. The component is "designed to allow apparently working production software, which nonetheless may harbor contract violations, to increase the number of precondition checks used to catch such bugs without negatively impacting the existing behavior of the software" - library-level checks, added to legacy code during migration, where the post-violation state is language-defined[106]. `bsls_assert` terminates: Bloomberg policy holds that "tasks may not install an assertion handler that returns control to the point immediately following the detection of a failed assertion", a policy `bsls_assert` "enforces ... by terminating the task" when a handler returns[106]. The boundary between the two tiers is the defined/undefined line, and it coincides with this comparison's terminating finding rather than cutting against it. That is a deployed handler-and-menu architecture - in the library-assertion lineage rather than the compiler-inserted one - and it is the deployment experience the Berne statement quoted in Section 6 points to.
+The closest deployed analogue of the unified model is Bloomberg's BDE assertion family, and it is real and scoped. BDE installs a process-global, replaceable violation handler that receives a violation object, and assertion levels select checking per build[40]. The family is two-tiered, and its own public sources draw the line. `bsls_review` logs and continues: its default handler logs the violation and returns instead of aborting. The component is "designed to allow apparently working production software, which nonetheless may harbor contract violations, to increase the number of precondition checks used to catch such bugs without negatively impacting the existing behavior of the software" - library-level checks, added to legacy code during migration, where the post-violation state is language-defined[106]. `bsls_assert` terminates: Bloomberg policy holds that "tasks may not install an assertion handler that returns control to the point immediately following the detection of a failed assertion", a policy `bsls_assert` "enforces ... by terminating the task" when a handler returns[106]. The boundary between the two tiers is the defined/undefined line, and it coincides with this comparison's terminating finding rather than cutting against it. That is a deployed handler-and-menu architecture - in the library-assertion lineage rather than the compiler-inserted one - and it is the deployment experience the Berne statement quoted in Section 6 points to.
-Its evolution is instructive, and the primary account is Berne's own 2019 talk. The handler as program-wide continuation policy failed in production: teams "set a violation handler that didn't abort", new bugs went "only getting logged", bad data reached a client who "lost a lot of money", and the stated conclusion was that "having blanket continuation for violation handler is not a safe approach"[92]. The 3.15.0 release then forbade continuation outright: "bsls_assert failure handers [sic] must not return control to the point of the failed assertion (perhaps after having logged the event). Such attempts are now forced to abort"[57]. What that release removed was the continuation, not the hook: the handler is still invoked and still logs; it may no longer return execution to the point past the violation.
+Its evolution is instructive, and the primary account is Berne's own 2019 talk. The handler as program-wide continuation policy failed in production: teams "set a violation handler that didn't abort", new bugs went "only getting logged", bad data reached a client who "lost a lot of money", and the stated conclusion was that "having blanket continuation for violation handler is not a safe approach"[92]. Then the 3.15.0 release forbade continuation outright: "bsls_assert failure handers [sic] must not return control to the point of the failed assertion (perhaps after having logged the event). Such attempts are now forced to abort"[57]. What that release removed was the continuation, not the hook: the handler is still invoked and still logs. It may no longer return execution to the point past the violation.
The handler as per-check policy engine was built and abandoned: a configurable "smart" violation handler "did all sorts of great stuff but this required a lot of configuration", left "no way to indicate just in the code" that one assertion's treatment had changed, and "was rarely used ... never really took traction"[92] - the spoken twin of P2811R4's report that building review-mode behavior inside a handler "proved unsustainable and fruitless", where once the continuation policy could be specified on the annotation itself, a review implementation "became trivial to produce"[58]. And enforcement earned its caution operationally: one added check in the string destructor, "completely innocuous" to its authors, hit "hundreds of applications" and was pulled[92].
What that record is, stated in its strongest form, is design provenance. The C++26 architecture is built from BDE's lessons: the no-return rule became enforce's termination, bsls_review's staged log-then-promote migration - library-level checks, where the post-violation state is language-defined - became the observe semantic, and the in-place recategorization of individual checks, macro to macro at the check site, is creditable lineage for the Labels direction. Bloomberg has also rebased bsls_assert's enforced macro onto `contract_assert` under an experimental implementation and built BDE plus four large internal libraries on the result[93]. Deployment-derived design is how good facilities get built, and nothing here discounts it as design input. What it is not is deployment of the premise under comparison: the distance between "the design learned from deployment" and "the base has been deployed" is the deployment criterion's entire content. The lessons were learned inside one in-house family serving its own assertions - policy per check, a reporting handler, one facility - and the learning institution's own trajectory moved policy out of the handler and into the check site.
-Two boundary facts complete the scoping. The violation object BDE's handler receives carries the failed check's level - metadata classifying the check itself, whose nearest standardized analogue on the violation object, the `detection_mode` category enumerators, P3100R8 withdrew in favor of unimplemented Labels (Section 10)[40][1]. And the scope is one institution's assertion ecosystem. Public code search finds no installation of the BDE violation handler outside BDE itself, its forks, and its vendored copies. That search ran on 2026-07-11, and the indexes do not reach private or enterprise code. What BDE is not, and what nothing on the record is, is a base in whose terms other checking facilities are specified. The distance between a deployed in-house handler-and-menu family and a standardized base in whose terms every facility is defined is the distance the premise asserts and the record has not crossed.
+Two boundary facts complete the scoping. The violation object BDE's handler receives carries the failed check's level - metadata classifying the check itself, whose nearest standardized analogue on the violation object, the `detection_mode` category enumerators, P3100R8 withdrew in favor of unimplemented Labels (Section 10)[40][1]. And the scope is one institution's assertion ecosystem. Public code search finds no installation of the BDE violation handler outside BDE itself, its forks, and its vendored copies. That search ran on 2026-07-11, and the indexes do not reach private or enterprise code. What BDE is not, and what nothing on the record is, is a base in whose terms other checking facilities are specified. Between a deployed in-house handler-and-menu family and a standardized base in whose terms every facility is defined lies the distance the premise asserts and the record has not crossed.
-Replaceable violation handlers are in fact common in user space. Their record sharpens the scope finding; it does not blunt it. Boost.Assert has exposed a user-defined, process-global `boost::assertion_failed` for two decades - the same shape as the C++26 handler, replaced at link time by the application - and the policies deployed projects install in it differ: QuantLib throws, OSRM throws specifically to guarantee stack unwinding, userver logs and aborts with a stack trace, RethinkDB routes into its own fatal-error machinery[59]. The canonical use of such handlers includes throwing - the maintainer of libassert steers assertion-testing through a throwing handler[59]. And when the GSL deleted its response configuration - the throwing and unenforced modes, removed in 3.0.0[36] - users from safety-critical, application-monitoring, and interactive environments spent years on the record objecting that the termination decision was not the library's to make. What no deployed handler spans is facilities: each serves exactly one assertion family's checks, and one process routinely runs multiple policies side by side - the same program can throw from `boost::assertion_failed` while its C `assert` aborts and its hardened library traps. The deployed record is per-facility handlers under application ownership; expressing that policy matrix through one cross-facility handler would need exactly the per-check category metadata whose standardized form was withdrawn in favor of unimplemented Labels (Section 10). The record of handler customization is therefore an argument for facility-scoped response ownership, not for a single base every facility routes through.
+Replaceable violation handlers are in fact common in user space, and their record sharpens the scope finding instead of blunting it. Boost.Assert has exposed a user-defined, process-global `boost::assertion_failed` for two decades - the same shape as the C++26 handler, replaced at link time by the application - and the policies deployed projects install in it differ: QuantLib throws, OSRM throws specifically to guarantee stack unwinding, userver logs and aborts with a stack trace, RethinkDB routes into its own fatal-error machinery[59]. The canonical use of such handlers includes throwing - the maintainer of libassert steers assertion-testing through a throwing handler[59]. And when the GSL deleted its response configuration - the throwing and unenforced modes, removed in 3.0.0[36] - users from safety-critical, application-monitoring, and interactive environments spent years on the record objecting that the termination decision was not the library's to make. What no deployed handler spans is facilities: each serves exactly one assertion family's checks, and one process routinely runs multiple policies side by side - the same program can throw from `boost::assertion_failed` while its C `assert` aborts and its hardened library traps. The deployed record is per-facility handlers under application ownership. Expressing that policy matrix through one cross-facility handler would need exactly the per-check category metadata whose standardized form was withdrawn in favor of unimplemented Labels (Section 10). The record of handler customization is therefore an argument for facility-scoped response ownership rather than for a single base every facility routes through.
### The committee's own precedents
-The committee's own record contains both surviving and removed process-global handlers, and the difference between them is the instructive part. `std::set_terminate` customizes how an already-chosen termination happens, and `std::set_new_handler` runs a resource-exhaustion protocol - free memory and retry, throw, or terminate; both date from C++98 and remain in the language. The one that adjudicated a violation of a language-level annotation through a replaceable global function - `std::set_unexpected`, the handler for dynamic-exception-specification violations - was deprecated in C++11 and removed in C++17 with the feature it served[44]. The removal had more causes than the handler: the specifications were enforced at run time rather than compile time, composed poorly, imposed cost, and were superseded by `noexcept`[44]. What the handler contributed is stated in Herb Sutter's assessment: "A global handler is highly unlikely to be smart enough to Do the Right Thing for any given particular case, and the result is to go to terminate(), go directly to terminate(), do not pass catch, do not collect $200"[43]. The precedent is therefore narrow, and it is the relevant one: the surviving global handlers own single-purpose protocols; the one asked to respond usefully to a class of violations on behalf of the whole program was, on Sutter's assessment, unlikely to manage it, and maximal extensibility - any function could be installed - did not save the feature it served. The precedent's reach also tracks the machinery's observability. In configurations where the handler only reports on the way to a fixed termination, the adjudicating architecture is absent and the precedent does not apply. In configurations where the handler adjudicates the program-wide response - the throwing and continuing ones - the precedent applies, and those are the same configurations this section finds contested everywhere else.
+The committee's own record contains both surviving and removed process-global handlers, and the difference between them is the instructive part. `std::set_terminate` customizes how an already-chosen termination happens, and `std::set_new_handler` runs a resource-exhaustion protocol - free memory and retry, throw, or terminate. Both date from C++98 and remain in the language. The one that adjudicated a violation of a language-level annotation through a replaceable global function - `std::set_unexpected`, the handler for dynamic-exception-specification violations - was deprecated in C++11 and removed in C++17 with the feature it served[44]. Beyond the handler, the removal had more causes: the specifications were enforced at run time rather than compile time, composed poorly, imposed cost, and were superseded by `noexcept`[44]. What the handler contributed is stated in Herb Sutter's assessment: "A global handler is highly unlikely to be smart enough to Do the Right Thing for any given particular case, and the result is to go to terminate(), go directly to terminate(), do not pass catch, do not collect $200"[43]. The precedent is therefore narrow, and it is the relevant one: the surviving global handlers own single-purpose protocols. On Sutter's assessment, the one asked to respond usefully to a class of violations on behalf of the whole program was unlikely to manage it, and maximal extensibility - any function could be installed - did not save the feature it served. The precedent's reach also tracks the machinery's observability. In configurations where the handler only reports on the way to a fixed termination, the adjudicating architecture is absent and the precedent does not apply. In configurations where the handler adjudicates the program-wide response - the throwing and continuing ones - the precedent applies, and those are the same configurations this section finds contested everywhere else.
-The C committee's record contains the same precedent, run to the same end. Annex K's bounds-checking interfaces route every constraint violation through one process-global runtime-constraint handler, and N1967, the field-experience paper behind the annex's proposed removal, states its findings in the shape this section has been cataloguing: "virtually every function in the Bounds checking library relies on a single process-global runtime-constraint handler", so "the APIs are ill-suited for multi-threaded components"; and the replaceability is itself the security concern, a user-installed handler that recovers or defers termination "increases the window of opportunity for an attacker to gain control of the vulnerable program"[94]. The committee record thus holds two standardized process-global handlers charged with adjudicating a violation class program-wide, in two languages, both condemned by their committees' own review. The platform layer moved the same direction: glibc removed its writable global malloc hooks, the removal having "eliminated a key exploit primitive from the library", and Microsoft's CRT added a thread-local variant of its invalid-parameter handler - one global slot does not compose, even within a single facility[95].
+The C committee's record contains the same precedent, run to the same end. Annex K's bounds-checking interfaces route every constraint violation through one process-global runtime-constraint handler, and N1967, the field-experience paper behind the annex's proposed removal, states its findings in the shape this section has been cataloguing: "virtually every function in the Bounds checking library relies on a single process-global runtime-constraint handler", so "the APIs are ill-suited for multi-threaded components". And the replaceability is itself the security concern, a user-installed handler that recovers or defers termination "increases the window of opportunity for an attacker to gain control of the vulnerable program"[94]. The committee record thus holds two standardized process-global handlers charged with adjudicating a violation class program-wide, in two languages, both condemned by their committees' own review. The platform layer moved the same direction: glibc removed its writable global malloc hooks, the removal having "eliminated a key exploit primitive from the library", and Microsoft's CRT added a thread-local variant of its invalid-parameter handler - one global slot does not compose, even within a single facility[95].
### The first integration departs from the unified semantics
-The first integration of a pre-existing checking facility into the C++26 contract-violation machinery is on the record, and it does not use the unified semantics. P3290R4[45] (Berne, Doumler, Lakos) proposes a library API for invoking contract-violation handling directly and an opt-in mode in which the C `assert` macro reports its failures through the contract-violation handler; its abstract states why an integration layer is needed at all: pre-existing facilities "occasionally have fundamentally different semantics and provide completely different control mechanisms for their behavior". The integration departs from the semantics of `contract_assert` on three axes: the `assert` predicate is evaluated as an ordinary expression, without the const-ification applied inside contract-assertion predicates; an exception escaping the predicate propagates unchanged rather than being translated into a contract violation; and termination keeps the C facility's abort-on-failure behavior - the proposal describes invoking the handler "before aborting". One API variant goes further, terminating when an exception escapes the violation handler rather than letting it unwind as the enforce semantic does[45].
+The first integration of a pre-existing checking facility into the C++26 contract-violation machinery is on the record, and it does not use the unified semantics. P3290R4[45] (Berne, Doumler, Lakos) proposes a library API for invoking contract-violation handling directly and an opt-in mode in which the C `assert` macro reports its failures through the contract-violation handler. Its abstract states why an integration layer is needed at all: pre-existing facilities "occasionally have fundamentally different semantics and provide completely different control mechanisms for their behavior". On three axes, the integration departs from the semantics of `contract_assert`: the `assert` predicate is evaluated as an ordinary expression, without the const-ification applied inside contract-assertion predicates; an exception escaping the predicate propagates unchanged rather than being translated into a contract violation; and termination keeps the C facility's abort-on-failure behavior - the proposal describes invoking the handler "before aborting". One API variant goes further, terminating when an exception escapes the violation handler rather than letting it unwind as the enforce semantic does[45].
-That last departure sits inside the one thing the integration claims to unify. The defense available for the first two - deliberate preservation of the C facility's documented evaluation semantics, with only the handling channel unified - does not reach a variant whose divergence is in the handling. An exception escaping the violation handler terminates under the integration where the enforce semantic unwinds, so the unified channel itself behaves differently depending on which facility's check invoked it. P3912R0 states the general form of the divergence: always-enforced checks "represent a fundamentally different feature from build-time configurable contract assertions. They target different use cases, lead to different deployment scenarios, and follow different adoption trajectories"[46]. P3100R8's Section 7.2, quoted in Section 3, names "an incoherent and messy design" as the failure condition when two mechanisms coexist without one being specified in the other's terms; the first integration exhibits that divergence before either proposal has shipped.
+That last departure sits inside the one thing the integration claims to unify. Available for the first two - deliberate preservation of the C facility's documented evaluation semantics, with only the handling channel unified - the defense does not reach a variant whose divergence is in the handling. An exception escaping the violation handler terminates under the integration where the enforce semantic unwinds, so the unified channel itself behaves differently depending on which facility's check invoked it. P3912R0 states the general form of the divergence: always-enforced checks "represent a fundamentally different feature from build-time configurable contract assertions. They target different use cases, lead to different deployment scenarios, and follow different adoption trajectories"[46]. P3100R8's Section 7.2, quoted in Section 3, names "an incoherent and messy design" as the failure condition when two mechanisms coexist without one being specified in the other's terms. The first integration exhibits that divergence before either proposal has shipped.
### Where the unification is said to hold, it holds by absence
@@ -402,7 +402,7 @@ if (!cond)
__builtin_trap(); // or abort(), or __fastfail()
```
-Nothing in it is a contract assertion, and nothing in it changes if a specification calls it one. Read the vendor statements against that equivalence. libc++'s deployment report states that "the trapping mechanism used in libc++ hardening is precisely the quick-enforce evaluation semantic"[34]; the MSVC STL documents that "as C++26 Contracts are not yet implemented, this defaults to calling __fastfail() for hardened precondition violations"[17]. Both statements are accurate. Both describe implementations containing no contract machinery, because for these predicates, under quick-enforce, conformance requires none. P3878R0 reaches the same conclusion from the implementer's side, describing what a hardened implementation that must always terminate is left to do: "not use contracts the language facility in its code, and just terminate directly, without invoking any violation handler"[47]. Where the unification is claimed to hold, conformance to it is satisfied by absence.
+Nothing in it is a contract assertion, and nothing in it changes if a specification calls it one. Read the vendor statements against that equivalence. libc++'s deployment report states that "the trapping mechanism used in libc++ hardening is precisely the quick-enforce evaluation semantic"[34]. The MSVC STL documents that "as C++26 Contracts are not yet implemented, this defaults to calling __fastfail() for hardened precondition violations"[17]. Both statements are accurate, and both describe implementations containing no contract machinery, because for these predicates, under quick-enforce, conformance requires none. P3878R0 reaches the same conclusion from the implementer's side, describing what a hardened implementation that must always terminate is left to do: "not use contracts the language facility in its code, and just terminate directly, without invoking any violation handler"[47]. Where the unification is claimed to hold, conformance to it is satisfied by absence.
The confinement is general, and it covers both integrations on the record. The two semantic features that would distinguish the machinery even without a handler - const-ification, and the translation of predicate exceptions into violations - are exercised by neither: hardening's predicates, outside the two span-constructor exceptions noted above, never reach them, and the C `assert` integration omits both by design[45]. Across the two integrations, the unified semantics have never been exercised by a facility joining the framework: the integration that would have exercised them departed from them, and the deployment said to demonstrate them almost never reaches them.
@@ -410,17 +410,17 @@ The equivalence is confined to quick-enforce, and the confinement is what matter
But the configurations in which the unified machinery becomes observable are the contested ones. A checking but non-terminating semantic on a hardened precondition is the possibility P3878R0 identifies as defeating a hardened implementation's purpose[47]. And whether the violation handler is replaceable at all is implementation-defined: P3846R0 lists it among five deliberately implementation-defined properties, replaceability being "viewed by some platforms as a necessary feature for even the most basic viability of the proposal and by other platforms as a security risk"[49]. That accommodation of the constraint Apple's paper states has a consequence: the one customization point credited in Section 6 is itself only conditionally present. For the terminating configurations that production hardening deploys today, a profile defined as a named preset over evaluation semantics[1] and a profile that defines the violation response directly, as P3984R0 does[4], are observably identical.
-The first field migration onto the machinery itself - to the authors' knowledge the one sustained public account, run on an experimental implementation - points the same way: ScyllaDB selected enforce, the handler-running terminating semantic, and pinned it per assertion through a vendor attribute, "Scylla is always enforced. Always.", foreclosing the per-build menu[63]. The pinning is de-configuration, not configuration - a per-assertion guarantee, chosen by the code's owner, that no build may override - and it predates the migration: ScyllaDB's tree-wide `SCYLLA_ASSERT` macro "is always defined and is not conditional on NDEBUG"[100]. The engineer who ran the migration states the design misfit on the public reflector: "the person who write the contract is not the one who selects the semantics for the application. Is this aspect of contracts aligned with hardened libraries needs? The discussion seems to reveal that not."[101] Redpanda reached the same endpoint independently, replacing build-conditional asserts after "at least 2 difficult-to-analyze bugs" were introduced because checks were "compiled out due to our use of -DNDEBUG"[100]. Where configurability itself was the bug vector, the fix in both organizations was removing the menu, not enriching it. The implementer statement of the general form is John Spicer's, from the SG21 reflector: the key issue "is how you apply various 'checking modes' to different components (e.g., libraries)", and "this is a problem that needs to be solved in order for contracts to be viable in the real world"[102] - named, scoped, component-attached guarantees. The in-source pinning ScyllaDB reached for is the capability Labels propose and have not shipped.
+The first field migration onto the machinery itself - to the authors' knowledge the one sustained public account, run on an experimental implementation - points the same way: ScyllaDB selected enforce, the handler-running terminating semantic, and pinned it per assertion through a vendor attribute, "Scylla is always enforced. Always.", foreclosing the per-build menu[63]. The pinning is de-configuration, not configuration - a per-assertion guarantee, chosen by the code's owner, that no build may override - and it predates the migration: ScyllaDB's tree-wide `SCYLLA_ASSERT` macro "is always defined and is not conditional on NDEBUG"[100]. The engineer who ran the migration states the design misfit on the public reflector: "the person who write the contract is not the one who selects the semantics for the application. Is this aspect of contracts aligned with hardened libraries needs? The discussion seems to reveal that not."[101] Redpanda reached the same endpoint independently, replacing build-conditional asserts after "at least 2 difficult-to-analyze bugs" were introduced because checks were "compiled out due to our use of -DNDEBUG"[100]. Where configurability itself was the bug vector, the fix in both organizations was to remove the menu rather than enrich it. The implementer statement of the general form is John Spicer's, from the SG21 reflector: the key issue "is how you apply various 'checking modes' to different components (e.g., libraries)", and "this is a problem that needs to be solved in order for contracts to be viable in the real world"[102] - named, scoped, component-attached guarantees. The in-source pinning ScyllaDB reached for is the capability Labels propose and have not shipped.
-The same standard applies on the Profiles side: P3984R0's non-terminating definitions - overflow as saturation, or as a thrown exception[4] - are just as undeployed as the machinery this section examines, and Section 6's matches-deployed-form finding covers the framework's named-set shape, not those definitions. What deploys today fixes its response in the build - terminating in the mitigations, logging in the kernel's diagnostics - and gives the violating case no defined alternative meaning under either model's vocabulary. The layering's distinct content appears only in the contested configurations, and Section 8 records the meaning question those configurations raise.
+The same standard applies on the Profiles side: P3984R0's non-terminating definitions - overflow as saturation, or as a thrown exception[4] - are just as undeployed as the machinery this section examines, and Section 6's matches-deployed-form finding covers the framework's named-set shape without reaching those definitions. What deploys today fixes its response in the build - terminating in the mitigations, logging in the kernel's diagnostics - and gives the violating case no defined alternative meaning under either model's vocabulary. The layering's distinct content appears only in the contested configurations, and Section 8 records the meaning question those configurations raise.
-The section's finding, in four parts, one per subsection. First, deployed failure responses are diverse for stated engineering reasons: single-instruction code generation, distrust of in-process handlers in corrupted states, process topology, mechanism independence - and the closest deployed relative, BDE's in-house handler-and-menu family, serves its own assertions rather than other facilities. Second, the C++ committee's one global handler charged with adjudicating a violation class for the whole program was removed with the feature it served, while the single-purpose handlers survive; the C committee's equivalent was condemned by its own field-experience review. Third, the first pre-existing facility integrated into the contract-violation machinery departed from the unified semantics on three axes. Fourth, the deployment claimed for the unified model conforms because, for hardening's predicates, quick-enforce requires none of the model's machinery. No deployment of the single-architecture premise - the base every facility is specified in terms of - exists on the record. On the deployment criterion, the premise the layering presupposes is untested where it is not already contradicted.
+The section's finding, in four parts, one per subsection. First, deployed failure responses are diverse for stated engineering reasons: single-instruction code generation, distrust of in-process handlers in corrupted states, process topology, mechanism independence - and the closest deployed relative, BDE's in-house handler-and-menu family, serves its own assertions rather than other facilities. Second, the C++ committee's one global handler charged with adjudicating a violation class for the whole program was removed with the feature it served, while the single-purpose handlers survive. The C committee's equivalent was condemned by its own field-experience review. Third, the first pre-existing facility integrated into the contract-violation machinery departed from the unified semantics on three axes. Fourth, the deployment claimed for the unified model conforms because, for hardening's predicates, quick-enforce requires none of the model's machinery. No deployment of the single-architecture premise - the base every facility is specified in terms of - exists on the record. On the deployment criterion, the premise the layering presupposes is untested where it is not already contradicted.
---
## 10. What Configuration Ownership Costs in Practice
-The layering is not only a question of order on a diagram; it has already had a concrete consequence in the wording of a companion paper. When one feature owns the configuration mechanism, a change to that mechanism can strand another paper's wording through independent revision. That has happened once.
+The layering is not only a question of order on a diagram. It has already had a concrete consequence in the wording of a companion paper. When one feature owns the configuration mechanism, a change to that mechanism can strand another paper's wording through independent revision. That has happened once.
[P3081R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3081r2.pdf)[9] (Sutter, February 2025, the latest revision) proposes wording that adds three enumerators to the `detection_mode` enumeration - `detection_mode::type`, `detection_mode::bounds`, and `detection_mode::lifetime` - each defined so that "the contract assertion was evaluated as part of" the corresponding profile, and its mechanism passes "the detection_mode value corresponding to P" on a failed check. Those values were to be produced by P3100's machinery: [P3543R0](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3543r0.pdf)[10] (Gill, Jabot, Lakos, Berne, and Doumler) states that P3081's runtime checks "are already preconditions introduced as implicit preconditions into the language itself by [P3100]."
@@ -428,23 +428,23 @@ P3100R8[1] then withdrew that producer. Its Section 5.6:
> ... unlike earlier revisions of this paper and unlike [P3081R1], which adopted its library API from those earlier revisions, we no longer propose to add new enumerators to the enumeration detection_mode to encode the category of error (Initialization, Bounds, and so on); instead, this encoding can be accomplished more effectively and flexibly via Labels (see Section 7.1).
-The two papers are now inconsistent in the record: P3081R2's proposed wording still adds the `detection_mode` enumerators, while P3100R8 proposes none and routes category encoding through Labels instead. No later P3081 revision has reconciled the two. This is not a feature breaking another feature; both are unadopted proposals, and the change has a legitimate design rationale. It is coordination cost: when the P3100 proposal moved category encoding to Labels, P3081R2's enumerators lost the mechanism that would have produced them, and the dependency sat unreconciled through the next revision cycle. That is the cost P3100R8's own Section 7.2 anticipates when it states that, if both features are kept, one must be specified in terms of the other. Configuration ownership decides which paper absorbs that cost when either side revises.
+The two papers are now inconsistent in the record: P3081R2's proposed wording still adds the `detection_mode` enumerators, while P3100R8 proposes none and routes category encoding through Labels instead. No later P3081 revision has reconciled the two. None of this is a feature breaking another feature. Both are unadopted proposals, and the change has a legitimate design rationale. It is coordination cost: when the P3100 proposal moved category encoding to Labels, P3081R2's enumerators lost the mechanism that would have produced them, and the dependency sat unreconciled through the next revision cycle. P3100R8's own Section 7.2 anticipates that cost when it states that, if both features are kept, one must be specified in terms of the other. Configuration ownership decides which paper absorbs that cost when either side revises.
-The episode is also evidence on the base question itself, all of it stated here. First, a Profiles-side paper adopted the P3100 arrangement, taking the contract machinery as the producer of its library API; the episode shows the cost even a willing adopter pays when the base revises underneath it - and the framework papers this comparison examines, P3589R2[3] and P3984R0[4], do not adopt that arrangement.
+The episode is also evidence on the base question itself, all of it stated here. First, a Profiles-side paper adopted the P3100 arrangement, taking the contract machinery as the producer of its library API. The episode shows the cost even a willing adopter pays when the base revises underneath it - and the framework papers this comparison examines, P3589R2[3] and P3984R0[4], do not adopt that arrangement.
Second, the episode is an inconsistency inside the Profiles corpus too: P3081 adopted the arrangement, P3589R2 and P3984R0 arrange the pieces the other way, and by Section 7.2's own standard the Profiles papers are currently unspecified in each other's terms. The exposure itself is not one side's property - whichever feature is made the base, a revision of the base can strand any paper specified in its terms. What the record adds is that the cost is no longer hypothetical: it has been paid once, by a willing adopter, without a published reconciliation, and the ownership decision assigns who absorbs it next time.
-Third, the exhibit is time-stamped, not time-decaying: a later P3081 revision that drops the enumerators would absorb the base's change, and the episode stays on the record. Whether reconciling borrowed wording is the borrower's job or the lender's relocates the cost without disputing it; the finding is the cost's existence, not an assignment of blame for the delay.
+Third, the exhibit is time-stamped, not time-decaying: a later P3081 revision that drops the enumerators would absorb the base's change, and the episode stays on the record. Whether reconciling borrowed wording is the borrower's job or the lender's relocates the cost without disputing it. The finding concerns the cost's existence, and it assigns no blame for the delay.
---
## 11. Objections
-Each heading below states an objection in its strongest form; each response draws only on evidence already presented.
+Each heading below states an objection in its strongest form. Each response draws only on evidence already presented.
### "The two features are complementary, not competing, so there is nothing to own"
-Complementarity is not symmetric here, and the proposal says so. P3100R8 Section 7.2 states that for granular in-source control "we need to agree whether this happens" through Labels or through the Profiles framework, and that "If we want to have both, we need to specify one in terms of the other to avoid an incoherent and messy design"[1]. That is the proposal itself stating that one feature must be defined in the other's terms. A divided-territory version of the objection - each feature primary in its own sphere - collapses at the collision points, as Section 3's partition analysis records. Section 10 shows the cost of leaving the question unsettled: one paper's wording has already been stranded by the other's revision. Complementary features that must be specified one in terms of the other still have an ownership question, and it is the one compared here.
+Complementarity is not symmetric here, and the proposal says so. P3100R8 Section 7.2 states that for granular in-source control "we need to agree whether this happens" through Labels or through the Profiles framework, and that "If we want to have both, we need to specify one in terms of the other to avoid an incoherent and messy design"[1]. There the proposal itself states that one feature must be defined in the other's terms. A divided-territory version of the objection - each feature primary in its own sphere - collapses at the collision points, as Section 3's partition analysis records. Section 10 shows the cost of leaving the question unsettled: one paper's wording has already been stranded by the other's revision. Complementary features that must be specified one in terms of the other still have an ownership question, and it is the one compared here.
### "The Profiles framework is not implemented either, so the deployment criterion is neutral"
@@ -452,17 +452,17 @@ Correct about the specifications, and Section 6 states it: neither P3589's frame
### "The decade you count is library hardening and static analysis; deployed runtime checking of core-language UB is our lineage, the sanitizers and trap flags"
-The strongest form of the deployment objection, and its factual half is stated in Section 6: the compiler-inserted check at an undefined-behavior site is the P3100 model's lineage, and P3100R8 maps those mechanisms into its semantics. What the objection does not supply is equivalence of experience. The sanitizer and trap-flag lineage deploys as opt-in, test-time tooling outside its production instances, and those instances fix a handler-free response in the build - terminating where deployed as mitigation (Android's UBSan checks, Chrome's control-flow integrity, Apple's `-fbounds-safety`), logging where deployed as diagnostics (distribution-kernel UBSan reporting)[50][53][54][74]. The named-guarantee lineage deploys in production with measured cost, at operating-system-vendor and hyperscaler scale. And the direction of standardization differs: the P3100 model does not propose to standardize `-fwrapv` and the sanitizers as they deploy today - it proposes Labels, implicit assertions, and the replaceable handler, none of which its lineage has deployed - while the Profiles model proposes to standardize named per-build guarantee sets, which is what its lineage deploys. As for the aggregation half - the charge that the decade's rows are static analysis and library preconditions rather than core-language checking - Section 6 tags the rows by domain and states the unit of comparison: the ledger is organized by configuration form, not check domain. Restricting the view to core-language checking sharpens the finding, because the core-language deployments on the record are themselves named-guarantee deployments - per-build, response-fixed, the newest of them trap-only by design. Table A carries both halves.
+The strongest form of the deployment objection, and its factual half is stated in Section 6: the compiler-inserted check at an undefined-behavior site is the P3100 model's lineage, and P3100R8 maps those mechanisms into its semantics. What the objection does not supply is equivalence of experience. The sanitizer and trap-flag lineage deploys as opt-in, test-time tooling outside its production instances, and those instances fix a handler-free response in the build - terminating where deployed as mitigation (Android's UBSan checks, Chrome's control-flow integrity, Apple's `-fbounds-safety`), logging where deployed as diagnostics (distribution-kernel UBSan reporting)[50][53][54][74]. The named-guarantee lineage deploys in production with measured cost, at operating-system-vendor and hyperscaler scale. And the direction of standardization differs: the P3100 model does not propose to standardize `-fwrapv` and the sanitizers as they deploy today - it proposes Labels, implicit assertions, and the replaceable handler, none of which its lineage has deployed - while the Profiles model proposes to standardize named per-build guarantee sets, which is what its lineage deploys. As for the aggregation half - the charge that the decade's rows are static analysis and library preconditions rather than core-language checking - Section 6 tags the rows by domain and states the unit of comparison: the ledger is organized by configuration form rather than check domain. Restricting the view to core-language checking strengthens the finding, because the core-language deployments on the record are themselves named-guarantee deployments - per-build, response-fixed, the newest of them trap-only by design. Table A carries both halves.
### "No feature can have deployment experience before it ships in the IS, so the criterion structurally privileges incumbency"
-This is the normative force of the Doumler statement quoted in Section 6, and it is a fair description of how new core-language features arrive: constexpr, concepts, and coroutines shipped on design and implementation experience, not production deployment. The criterion as applied here does not demand pre-adoption deployment of anyone's syntax. It weighs the deployed forms, which both sides have, and asks which proposal's standardized object matches its deployed form - a question that is answerable today and that the ballot proposed in P4297 would put to the room with this evidence in front of it. A criterion both sides can satisfy in the same way is not incumbency protection; the asymmetry is in the record, not the rule. The finding also survives the objector's own unit: as Section 6 states, under form, domain, lineage, or a no-discount counting, no deployment on the record selects semantics per assertion in source or routes a replaceable handler.
+This is the normative force of the Doumler statement quoted in Section 6, and it is a fair description of how new core-language features arrive: constexpr, concepts, and coroutines shipped on design and implementation experience, without production deployment behind them. The criterion as applied here does not demand pre-adoption deployment of anyone's syntax. It weighs the deployed forms, which both sides have, and asks which proposal's standardized object matches its deployed form - a question that is answerable today and that the ballot proposed in P4297 would put to the room with this evidence in front of it. A criterion both sides can satisfy in the same way is not incumbency protection. The asymmetry is in the record, not the rule. As Section 6 states, the finding also survives the objector's own unit: under form, domain, lineage, or a no-discount counting, no deployment on the record selects semantics per assertion in source or routes a replaceable handler.
-The criterion's two applications obey one separating principle: deployment evidence transfers across spellings of a deployed form; it does not transfer to architectures that have never existed anywhere. A proposal's syntax needs no pre-adoption deployment when it standardizes a form the field already runs - the spelling is new, the thing is not. The single-architecture premise is not a spelling of anything deployed, so there is no deployed referent for evidence to transfer from; that is Section 9's finding, not a stricter rule for premises. The sharpened form of this objection - that the criterion so applied would have rejected P2900, constexpr, and concepts - dissolves on the same distinction: those adoptions added new capability with no incumbent deployed form on either side, so there was no displacement question to answer; here a deployed form exists and displacement is the question. The P2900 precedent, read closely, runs the other way: that minimum-viable-product scope was limited to explicit assertions at API boundaries, with BDE-class design experience behind it (Section 9); P3100 enlarges the scope to every checkable core-language operation plus the base role over other facilities - a broader claim on a thinner record. Finally, the structural variant - only a standard can create a cross-facility base, so demanding a deployed one demands the impossible - is an argument about sequencing, not default ownership: adopt the checking without the base role, and assign basehood when a record exists. Impossibility of prior evidence argues for deferring the assignment, not for making it by default.
+The criterion's two applications obey one separating principle: deployment evidence transfers across spellings of a deployed form, but not to architectures that have never existed anywhere. When it standardizes a form the field already runs, a proposal's syntax needs no pre-adoption deployment - the spelling is new, the thing is not. The single-architecture premise is not a spelling of anything deployed, so there is no deployed referent for evidence to transfer from. Section 9 reaches that finding without applying a stricter rule to premises. The sharpened form of this objection - that the criterion so applied would have rejected P2900, constexpr, and concepts - dissolves on the same distinction: those adoptions added new capability with no incumbent deployed form on either side, so there was no displacement question to answer. Here a deployed form exists and displacement is the question. The P2900 precedent, read closely, runs the other way: that minimum-viable-product scope was limited to explicit assertions at API boundaries, with BDE-class design experience behind it (Section 9). P3100 enlarges the scope to every checkable core-language operation plus the base role over other facilities - a broader claim on a thinner record. Finally, the structural variant - only a standard can create a cross-facility base, so demanding a deployed one demands the impossible - is an argument about sequencing rather than default ownership: adopt the checking without the base role, and assign basehood when a record exists. Impossibility of prior evidence argues for deferring the assignment instead of making it by default.
### "The discount rule and the matches-deployed-form test are the authors' inventions, carrying no provenance"
-The two weighing rules that produce Section 6's finding deserve the same provenance audit as the criteria, and Section 6 supplies it. The discount rule is a corollary of the deployment criterion in the disputants' own formulations - Doumler's production-use bar, Dos Reis's "actual retail" - and it restates what the lineage's own operators say separates defending from reporting: Cook's panic-or-trap production recommendation, Stepanov's production runtime defined by deleting diagnostics, Serebryany's "you cannot use ASAN in production", Tolvanen's development-only permissive mode. A rule that repeats what the record's operators practice is sourced to the record, not invented over it. The matches-deployed-form test is the existing-practice criterion applied to the ownership question: P2000R5's sentence asks what builds on previous work, and asking whether each proposal's standardized object is the deployed thing or the undeployed part of its lineage is that question, phrased so vendor documentation can answer it. A reader who rejects either rule still holds Table A's rows, which stand independently of the weighing; the re-weighing invitation in Section 12 covers that reader by name.
+The two weighing rules that produce Section 6's finding deserve the same provenance audit as the criteria, and Section 6 supplies it. The discount rule is a corollary of the deployment criterion in the disputants' own formulations - Doumler's production-use bar, Dos Reis's "actual retail" - and it restates what the lineage's own operators say separates defending from reporting: Cook's panic-or-trap production recommendation, Stepanov's production runtime defined by deleting diagnostics, Serebryany's "you cannot use ASAN in production", Tolvanen's development-only permissive mode. Because it repeats what the record's operators practice, the discount rule is sourced to the record rather than invented over it. The matches-deployed-form test is the existing-practice criterion applied to the ownership question: P2000R5's sentence asks what builds on previous work, and asking whether each proposal's standardized object is the deployed thing or the undeployed part of its lineage is that question, phrased so vendor documentation can answer it. Rejecting either rule, a reader still holds Table A's rows, which stand independently of the weighing. The re-weighing invitation in Section 12 covers that reader by name.
### "Weigh the criteria by their provenance, and the one polled criterion decides for P3100"
@@ -470,17 +470,17 @@ The weighting move is legitimate, and Section 4 accepts its premise: the criteri
### "The parts are deployed; the systematization is the contribution, so deployment of the parts is deployment of the whole"
-The parts and the organizing work earn credit here: the enumeration of the undefined-behavior cases (Section 4) and the vocabulary that maps deployed mechanisms into one model (Section 6) are real contributions, stated as such. The objection fails at the step from parts to whole: the parts ship without the elements the whole adds. The sanitizers, trap flags, and hardened libraries deploy no violation object, no replaceable cross-facility handler, no in-source selection among evaluation semantics (the deployed in-source control is binary suppression, per-site check-or-not attributes), and no translation of predicate exceptions into violations - those are the whole's additions, and Section 6 finds each of them undeployed. The one deployed adoption of the model's vocabulary makes the distinction concrete: libc++ took the names without the machinery (Section 6). The organizing work could have been standardized over the deployed forms as they deploy; what is proposed instead is the layer no part of the lineage includes, and naming deployed parts does not lend them the whole's deployment record.
+The parts and the organizing work earn credit here: the enumeration of the undefined-behavior cases (Section 4) and the vocabulary that maps deployed mechanisms into one model (Section 6) are real contributions, stated as such. At the step from parts to whole, the objection fails: the parts ship without the elements the whole adds. The sanitizers, trap flags, and hardened libraries deploy no violation object, no replaceable cross-facility handler, no in-source selection among evaluation semantics (the deployed in-source control is binary suppression, per-site check-or-not attributes), and no translation of predicate exceptions into violations - those are the whole's additions, and Section 6 finds each of them undeployed. Making the distinction concrete, the one deployed adoption of the model's vocabulary is libc++, which took the names without the machinery (Section 6). The organizing work could have been standardized over the deployed forms as they deploy. What is proposed instead is the layer no part of the lineage includes, and naming deployed parts does not lend them the whole's deployment record.
### "Quick-enforce accommodating the trap constraint is a feature of the architecture, not a weakness"
-Accepted - and the feature has a cost the objection does not name. Accommodation by quick-enforce is accommodation by absence: Section 9 shows that for hardening's predicates a conforming quick-enforce evaluation contains none of the machinery, so where the architecture accommodates the deployed constraint, specifying a profile in its terms adds nothing observable - a preset selecting quick-enforce and a profile defining termination directly are the same profile. Feature and vacuity are one fact seen from two sides: a feature that works by containing nothing cannot also be the thing other facilities are specified in terms of. The ownership claim must then be earned entirely by the configurations in which the machinery is present, and those are the contested ones: the non-terminating semantics P3878R0 finds defeat a hardened implementation, the replaceable handler Apple's feedback paper treats as a security risk[37], and the noexcept interaction of Section 8. Where the accommodation operates, the two models are observably identical; the base question can only be decided where they differ, and where they differ is where the objections sit.
+Accepted - and the feature has a cost the objection does not name. Accommodation by quick-enforce is accommodation by absence: Section 9 shows that for hardening's predicates a conforming quick-enforce evaluation contains none of the machinery, so where the architecture accommodates the deployed constraint, specifying a profile in its terms adds nothing observable - a preset selecting quick-enforce and a profile defining termination directly are the same profile. Feature and vacuity are one fact seen from two sides: a feature that works by containing nothing cannot also be the thing other facilities are specified in terms of. The ownership claim must then be earned entirely by the configurations in which the machinery is present, and those are the contested ones: the non-terminating semantics P3878R0 finds defeat a hardened implementation, the replaceable handler Apple's feedback paper treats as a security risk[37], and the noexcept interaction of Section 8. Where the accommodation operates, the two models are observably identical. The base question can only be decided where they differ, and where they differ is where the objections sit.
-The zero-overhead restatement of this objection - the design achieves its stated goal of costing nothing, and calling that vacuity renames an achievement - changes neither half: the achievement is real, and an architecture whose presence is unobservable in the deployed configurations still cannot ground an ownership claim there. Nor does the vocabulary version - libc++ adopting the standard's semantic names is standardization working - survive the adopters' own account, which Section 6 cites and the sources state. The semantics "closely mimic C++26 Contracts evaluation semantics"; their selection is a configure-time knob whose default mapping is that "production-capable modes map to quick-enforce (i.e., trap)"; and the handler override had already been withdrawn from users a year and a half earlier, the maintainers writing "we feel that this should primarily be controlled by vendors, not users"[103]. Names adopted, menu vendor-held, handler withheld: vocabulary standardization without basehood, in the adopters' own words.
+The zero-overhead restatement of this objection - the design achieves its stated goal of costing nothing, and calling that vacuity renames an achievement - changes neither half: the achievement is real, and an architecture whose presence is unobservable in the deployed configurations still cannot ground an ownership claim there. Nor does the vocabulary version - libc++ adopting the standard's semantic names is standardization working - survive the adopters' own account, which Section 6 cites and the sources state. The semantics "closely mimic C++26 Contracts evaluation semantics". Their selection is a configure-time knob whose default mapping is that "production-capable modes map to quick-enforce (i.e., trap)". Already a year and a half earlier, the handler override had been withdrawn from users, the maintainers writing "we feel that this should primarily be controlled by vendors, not users"[103]. Names adopted, menu vendor-held, handler withheld: vocabulary standardization without basehood, in the adopters' own words.
### "The contract-phrased specification offers option value: capability can grow later without respecification"
-The strongest analytical form of the previous objection, and its premise is true: wording phrased as contract assertions can grow enforce-with-handler reporting, per-assertion Labels, or violation telemetry without anyone rewriting the hardening wording, while a bare trap specified as a bare trap grows nothing. Four findings weigh the option. First, the capability it would unlock - handler-running, non-terminating checking - is what production deployments avoid and hardening implementers reject: the one migration's engineer states that builder-selected semantics do not fit hardened libraries' needs, Redpanda pinned always-on after configurability itself shipped bugs, and P3878R0 finds the non-terminating semantics defeat a hardened implementation's purpose (Section 9). Second, holding the option is not free: Section 8's overheads - the tracking obligation, the exception scaffolding, the redefined operator - are incurred in every configuration in which a violation can throw, whether or not the capability is ever used. Third, the option is severable from ownership: hardening was adopted contract-phrased while the base role stayed unresolved (Section 9), so the committee demonstrably can hold the option without assigning the base. Fourth, the record already shows what happens when the wording actually grows: it has grown once - the C `assert` integration - and that one growth required three departures from the unified semantics, one inside the handling channel itself (Section 9). That is an argument for keeping the wording flexible - not for assigning the base by default.
+The strongest analytical form of the previous objection, and its premise is true: wording phrased as contract assertions can grow enforce-with-handler reporting, per-assertion Labels, or violation telemetry without anyone rewriting the hardening wording, while a bare trap specified as a bare trap grows nothing. Four findings weigh the option. First, the capability it would unlock - handler-running, non-terminating checking - is what production deployments avoid and hardening implementers reject: the one migration's engineer states that builder-selected semantics do not fit hardened libraries' needs, Redpanda pinned always-on after configurability itself shipped bugs, and P3878R0 finds the non-terminating semantics defeat a hardened implementation's purpose (Section 9). Second, holding the option is not free: Section 8's overheads - the tracking obligation, the exception scaffolding, the redefined operator - are incurred in every configuration in which a violation can throw, whether or not the capability is ever used. Third, the option is severable from ownership: hardening was adopted contract-phrased while the base role stayed unresolved (Section 9), so the committee demonstrably can hold the option without assigning the base. Fourth, the record already shows what happens when the wording actually grows: it has grown once - the C `assert` integration - and that one growth required three departures from the unified semantics, one inside the handling channel itself (Section 9). Together the four argue for keeping the wording flexible rather than for assigning the base by default.
### "SG21 settled the noexcept interaction deliberately; re-opening it through an EWG paper is venue-shopping"
@@ -488,7 +488,7 @@ The premise is accurate and Section 8 credits it: the resolution was reached aft
### "A correct program never reaches a checking point, so the configuration-selected variation is hypothetical"
-Two findings already in the body answer this. First, the compile-time costs are borne by violation-free executions: within any configuration in which a violation can throw, the branch-deletion license is withdrawn and the exception scaffolding is generated whether or not any violation occurs (Section 8). A variation in what the compiler may do with correct code, and in what `noexcept` tells correct code, is not hypothetical in the executions the objection appeals to. Second, the premise concedes the dialect finding rather than answering it: the variation it calls hypothetical is the fate of the violating executions - the executions the checking exists for - and whether those have defined replacement behavior or undefined behavior optimized against is what the configuration selects (Section 8). A facility whose configured meanings differ only in the violating cases is not dialect-free; the variation sits where the checking is load-bearing.
+Two findings already in the body answer this. First, the compile-time costs are borne by violation-free executions: within any configuration in which a violation can throw, the branch-deletion license is withdrawn and the exception scaffolding is generated whether or not any violation occurs (Section 8). A variation in what the compiler may do with correct code, and in what `noexcept` tells correct code, is not hypothetical in the executions the objection appeals to. Second, the premise concedes the dialect finding rather than answering it: the variation it calls hypothetical is the fate of the violating executions - the executions the checking exists for - and whether those have defined replacement behavior or undefined behavior optimized against is what the configuration selects (Section 8). A facility whose configured meanings differ only in the violating cases is not dialect-free. The variation sits where the checking is load-bearing.
### "The diversity of deployed failure responses is history, not design; the unified handler is the improvement"
@@ -496,11 +496,11 @@ The direction of the record is the opposite: the diversity is recent, argued, an
### "The unified handler is designed to be extensible; new facilities extend it rather than diverge from it"
-The extension points are vocabulary - enumerators on the violation object, Labels when they exist[2] - and the recorded divergences are not vocabulary. A check that must compile to one instruction[33], a failure path that must invoke no in-process handler[35], a response that must terminate a different process than the detecting one[39], and a mechanism that must stay independent of what it monitors[42] are constraints on the response architecture, and no enumerator or Label reaches them. The proposal accommodates the first two through quick-enforce, which conforms by using none of the machinery (Section 9). The extension record where it has been exercised: the `detection_mode` enumerators for profile categories were withdrawn by the P3100 proposal's own revision, stranding P3081R2's wording (Section 10)[1][9], and the C `assert` integration arrived with the const-ification, exception-translation, and termination departures Section 8 records[45]. Extensibility of the handler was the one property `std::set_unexpected` possessed in full, and the feature it served was removed regardless[43][44]. The forward-looking form of this objection - choose the architecture that enables the most future work - presupposes the architecture's fitness for facilities that do not yet exist, and the direction paper's sentence asks for building on previous work, not predicted future work[5]. The claim of being "designed to be extensible" is the class of claim the deployment criterion exists to weigh.
+The extension points are vocabulary - enumerators on the violation object, Labels when they exist[2] - and the recorded divergences are not vocabulary. A check that must compile to one instruction[33], a failure path that must invoke no in-process handler[35], a response that must terminate a different process than the detecting one[39], and a mechanism that must stay independent of what it monitors[42] are constraints on the response architecture, and no enumerator or Label reaches them. Through quick-enforce, which conforms by using none of the machinery (Section 9), the proposal accommodates the first two. The extension record where it has been exercised: the `detection_mode` enumerators for profile categories were withdrawn by the P3100 proposal's own revision, stranding P3081R2's wording (Section 10)[1][9], and the C `assert` integration arrived with the const-ification, exception-translation, and termination departures Section 8 records[45]. Extensibility of the handler was the one property `std::set_unexpected` possessed in full, and the feature it served was removed regardless[43][44]. The forward-looking form of this objection - choose the architecture that enables the most future work - presupposes the architecture's fitness for facilities that do not yet exist, and the direction paper's sentence asks for building on previous work, which predicted future work is not[5]. The claim of being "designed to be extensible" is the class of claim the deployment criterion exists to weigh.
### "This is Profiles advocacy wearing the costume of a comparison"
-The authors' preference is disclosed on page one, and the reader should discount for it. The criteria in Section 4 carry their provenance inline - an advisory Direction Group paper, a polled Hagenberg mandate, a standard proposed by this paper's own authors and not yet taken, and the disputants' own texts - so the reader can weigh each criterion by its source. The deployment facts in Section 6 are vendor documentation. Where the criteria admit two readings, Section 7 states both.
+On page one, the authors' preference is disclosed, and the reader should discount for it. The criteria in Section 4 carry their provenance inline - an advisory Direction Group paper, a polled Hagenberg mandate, a standard proposed by this paper's own authors and not yet taken, and the disputants' own texts - so the reader can weigh each criterion by its source. The deployment facts in Section 6 are vendor documentation. Where the criteria admit two readings, Section 7 states both.
### "P3100 builds on P2900, the most recently adopted work, which is exactly what the direction paper asks"
@@ -512,13 +512,13 @@ That reading is real and Section 7 states it, including the respect in which it
The comparison above rests on one premise from the proposal's own text: kept together, one of these two features is specified in the other's terms. The body measured the two candidate owners criterion by criterion, and the findings are at different resolutions, which the reader deserves stated plainly rather than averaged.
-On deployment and field experience, the record separates the two. Both forms have deployed lineage, and the difference is in kind: the named-guarantee form runs in production across three vendors' libraries with measured cost - on by default in GCC 15 unoptimized builds and Xcode 16, opt-in in others - while the inserted-check form is opt-in test-time tooling outside its enumerated production instances. Both proposals' specifications are unshipped, and what the Profiles model standardizes matches its deployed form while what the P3100 model standardizes is the undeployed part of its lineage. On systematic coverage, the P3100 model leads, though the lead does not resolve ownership: its enumeration of the undefined-behavior cases has no equivalent on the Profiles side and serves every safety effort, yet both candidate owners consume that enumeration identically. On existing practice, P2000R5's sentence supports both proposals on different clauses, and the two readings name different owners. On the guarantee and dialects, the models assign the guarantee to different authors, and the per-configuration-variation question spans the expression's runtime meaning and the compile-time properties the configuration selects. Under P3100's menu it attaches to every checkable operation, where the proposal's own resolution leaves the `noexcept` operator answering true for expressions that can throw; a Profile raises it only where its author defines an undeployed non-terminating meaning. On the single-architecture premise, deployed failure responses are diverse for stated engineering reasons. The standardized global handlers charged with adjudicating a violation class program-wide were removed with their feature in C++ and condemned by field-experience review in C; the first integration into the contract-violation machinery departed from the unified semantics; and the deployment claimed for the model conforms by containing none of its machinery. P3984R0's undeployed semantic definitions are held to the same standard. On coordination, ownership left unsettled has already cost one companion paper its wording mechanism through independent revision.
+On deployment and field experience, the record separates the two. Both forms have deployed lineage, and the difference is in kind: the named-guarantee form runs in production across three vendors' libraries with measured cost - on by default in GCC 15 unoptimized builds and Xcode 16, opt-in in others - while the inserted-check form is opt-in test-time tooling outside its enumerated production instances. Both proposals' specifications are unshipped, and what the Profiles model standardizes matches its deployed form while what the P3100 model standardizes is the undeployed part of its lineage. On systematic coverage, the P3100 model leads, though the lead does not resolve ownership: its enumeration of the undefined-behavior cases has no equivalent on the Profiles side and serves every safety effort, yet both candidate owners consume that enumeration identically. On existing practice, P2000R5's sentence supports both proposals on different clauses, and the two readings name different owners. On the guarantee and dialects, the models assign the guarantee to different authors, and the per-configuration-variation question spans the expression's runtime meaning and the compile-time properties the configuration selects. Under P3100's menu it attaches to every checkable operation, where the proposal's own resolution leaves the `noexcept` operator answering true for expressions that can throw. A Profile raises it only where its author defines an undeployed non-terminating meaning. On the single-architecture premise, deployed failure responses are diverse for stated engineering reasons. The standardized global handlers charged with adjudicating a violation class program-wide were removed with their feature in C++ and condemned by field-experience review in C. The first integration into the contract-violation machinery departed from the unified semantics, and the deployment claimed for the model conforms by containing none of its machinery. P3984R0's undeployed semantic definitions are held to the same standard. On coordination, ownership left unsettled has already cost one companion paper its wording mechanism through independent revision.
The choice of owner is a decision for EWG, taken explicitly, with this record in front of it - the decision P4297 proposes to schedule by name. Until it is taken, the relationship is an open design question: approvals of individual undefined-behavior wording cases neither settle it nor foreclose it, and the two proposals continue to assert incompatible arrangements of the same pieces in parallel.
-The findings are falsifiable, and the falsifiers are deployment events, not shipping events, per the discount rule of Section 6. The deployment finding moves the day a Labels implementation reaches production deployment, a replaceable cross-facility violation handler ships in a production configuration, or the observe semantic of the unified model's compiler-inserted implicit assertions runs in production at scale (distinct from a library-assertion family such as BDE's `bsls_review`, whose observe-style continuation is treated in Section 9 and is design lineage, not deployment of the machinery under comparison). The single-architecture finding of Section 9 moves the day a checking facility outside the contract family ships specified in the unified machinery's terms without departing from it. And the finding cuts the other way on the same rule: a vendor withdrawing hardening, or field failures of the named-guarantee form, would weaken the record this paper assembles. Any of these events belongs in a revision of this comparison, whichever side it favors.
+Per the discount rule of Section 6, the findings are falsifiable, and the falsifiers are deployment events, not shipping events. The deployment finding moves the day a Labels implementation reaches production deployment, a replaceable cross-facility violation handler ships in a production configuration, or the observe semantic of the unified model's compiler-inserted implicit assertions runs in production at scale (distinct from a library-assertion family such as BDE's `bsls_review`, whose observe-style continuation is treated in Section 9 and is design lineage rather than deployment of the machinery under comparison). The single-architecture finding of Section 9 moves the day a checking facility outside the contract family ships specified in the unified machinery's terms without departing from it. And the finding cuts the other way on the same rule: a vendor withdrawing hardening, or field failures of the named-guarantee form, would weaken the record this paper assembles. Any of these events belongs in a revision of this comparison, whichever side it favors.
-Whoever writes the dedicated ballot proposal builds on the comparison assembled here. If the committee adopts the evidence standard P4297's Poll 3 proposes, this paper is the record that standard asks for; if it prefers another standard, the ledger in Section 6 is organized to be re-weighed under it.
+Whoever writes the dedicated ballot proposal builds on the comparison assembled here. If the committee adopts the evidence standard P4297's Poll 3 proposes, this paper is the record that standard asks for. If it prefers another standard, the ledger in Section 6 is organized to be re-weighed under it.
---
diff --git a/source/2026-07-july/d4310-terminating-response.md b/source/2026-07-july/d4310-terminating-response.md
index 847b1a8..1b98479 100644
--- a/source/2026-07-july/d4310-terminating-response.md
+++ b/source/2026-07-july/d4310-terminating-response.md
@@ -1,6 +1,6 @@
---
title: "Hasta la Vista, Undefined Behavior: Why Implicit Contract Violations Should Terminate"
-document: D4310R0
+document: P4310R0
date: 2026-07-13
intent: info
audience: EWG
@@ -15,7 +15,11 @@ reply-to:
For a detected core-language violation, the terminating response - invoke the handler, then terminate - is the default the evidence supports.
-The proposal to treat runtime-checkable core-language undefined behaviour as checked assertions that invoke a violation handler raises the question of whether, after the handler runs, execution continues past the violation or the program terminates. Separating the handler from the continuation past the violation isolates the only contested part, since the handler, a hook that logs the violation, is preserved by every response, so a terminating response loses no telemetry. No implementation yet answers the question, so the comparison reasons from deployed analogues: every hardened implementation surveyed makes termination or trapping its production default, and the continue modes that ship, such as UBSan's recover mode and Bloomberg's own log-and-continue facility, are documented as testing or adoption aids, the latter confined to library-level checks rather than to core-language undefined behaviour. Continuing past a state the language leaves undefined runs against the decision C++26 already adopted for standard-library hardening, and is the execution on undefined or corrupted state that the security literature treats as the more dangerous failure. Where the continuation is a handler whose exception escapes the checked expression, it also forces exception-handling machinery around every checked operation, a cost the reference implementers decline to incur and one that fall-through continuation does not carry. The terminating response adds no new semantic, reusing the C++26 enforce semantic and the existing termination rule, and it leaves the meaning of noexcept unchanged. This default holds across both classes of check, while a narrower finding, that a continuing semantic should not be a portable guarantee every implementation carries, is scoped only to the class whose continuation is undefined. For the class that continues into a defined result, such as a signed overflow specified to wrap, the continuation question is left open. The analysis does not withdraw the option a power user may need: a continuing response remains available, and the deployed precedents give it a defensible shape, an explicit, non-portable opt-in bounded to an adoption period rather than a default. Because the finding concerns the response itself, it holds whether the Contracts facility or the Profiles framework owns the configuration of the checks, and the paper places the record for the committee's use without a request.
+The proposal to treat runtime-checkable core-language undefined behaviour as checked assertions that invoke a violation handler raises one question: after the handler runs, does execution continue past the violation, or does the program terminate? Separating the handler from the continuation past the violation isolates the only contested part. The handler, a hook that logs the violation, is preserved by every response, so a terminating response loses no telemetry.
+
+No implementation yet answers the question, so the comparison reasons from deployed analogues. Termination or trapping is the production default of every hardened implementation surveyed. The continue modes that ship, such as UBSan's recover mode and Bloomberg's own log-and-continue facility, are documented as testing or adoption aids, and the latter is confined to library-level checks rather than to core-language undefined behaviour. Continuing past a state the language leaves undefined runs against the decision C++26 already adopted for standard-library hardening. It is also the execution on undefined or corrupted state that the security literature treats as the more dangerous failure. Where the continuation is a handler whose exception escapes the checked expression, it forces exception-handling machinery around every checked operation, a cost the reference implementers decline to incur and one that fall-through continuation does not carry.
+
+Reusing the C++26 enforce semantic and the existing termination rule, the terminating response adds no new semantic, and it leaves the meaning of noexcept unchanged. This default holds across both classes of check. A narrower finding, that a continuing semantic should not be a portable guarantee every implementation carries, is scoped only to the class whose continuation is undefined. For the class that continues into a defined result, such as a signed overflow specified to wrap, the continuation question is left open. The analysis does not withdraw the option a power user may need: a continuing response remains available. The deployed precedents give it a defensible shape: an explicit, non-portable opt-in bounded to an adoption period rather than a default. Because the finding concerns the response itself, it holds whether the Contracts facility or the Profiles framework owns the configuration of the checks. The paper places the record for the committee's use without a request.
---
@@ -31,17 +35,17 @@ The proposal to treat runtime-checkable core-language undefined behaviour as che
The authors provide information and serve at the pleasure of the committee.
-Vinnie Falco is the founder of the C++ Alliance, which maintains a Clang fork for Profiles work, and prefers the family of responses in which no exception escapes an implicit contract assertion; that is a stake in the outcome. Ville Voutilainen is a longtime WG21 participant, a co-author of the C++26 Contracts facility (P2900R14) and lead author of P3878R1, the adopted decision this paper reuses in Sections 5, 7, and 9. The reader should weigh what follows accordingly.
+Vinnie Falco is the founder of the C++ Alliance, which maintains a Clang fork for Profiles work, and prefers the family of responses in which no exception escapes an implicit contract assertion. That is a stake in the outcome. Ville Voutilainen is a longtime WG21 participant, a co-author of the C++26 Contracts facility (P2900R14) and lead author of P3878R1, the adopted decision this paper reuses in Sections 5, 7, and 9. The reader should weigh what follows accordingly.
The intent of this paper is `info`. It argues a position, that a terminating response is the one the evidence supports for implicit core-language assertions, but it proposes no wording and requests no poll.
This paper changes nothing in ratified C++26. C++26 Contracts (P2900R14[1]) are treated as fixed: the four evaluation semantics, the single violation handler, and the deliberate allowance that a handler may throw from an explicit contract assertion all stand unchanged. The question here belongs to the open C++29 work on implicit assertions (P3100R8[2]), and the paper addresses only that.
-One limitation is disclosed up front: no compiler yet implements implicit contract assertions with any semantic, so the paper reasons from deployed analogues, not from a conforming implementation of the feature itself. As of the July 2026 mailing, P3100R8[2] reports no implementation or deployment experience with the proposed implicit assertions, and the GCC, Clang, and MSVC C++26 status pages list none.
+Up front, one limitation is disclosed: no compiler yet implements implicit contract assertions with any semantic, so the paper reasons from deployed analogues. As of the July 2026 mailing, P3100R8[2] reports no implementation or deployment experience with the proposed implicit assertions, and the GCC, Clang, and MSVC C++26 status pages list none.
-This paper is one of a set in the July 2026 mailing on runtime-checking configuration. P4306R0[3] compares the configuration-ownership models on the public record, and P4297R0[4] asks EWG to decide the ownership relationship by an explicit poll. This paper is scoped to the response question and cross-references those rather than repeating them.
+In the July 2026 mailing, this paper is one of a set on runtime-checking configuration. P4306R0[3] compares the configuration-ownership models on the public record, and P4297R0[4] asks EWG to decide the ownership relationship by an explicit poll. This paper is scoped to the response question and cross-references those rather than repeating them.
-This paper was prepared with the assistance of generative tools; the authors are responsible for its content.
+This paper was prepared with the assistance of generative tools. The authors are responsible for its content.
This paper asks for nothing.
@@ -49,7 +53,7 @@ This paper asks for nothing.
## 2. Introduction
-C++26 Contracts (P2900R14[1]) define the evaluation semantics and the single violation handler this paper takes as fixed. P3100R8[2] proposes to extend that machinery to the runtime-checkable cases of core-language undefined behaviour, and P3878R1, adopted into C++26, already settled the parallel question for standard-library hardening. Two companions cover the neighbouring ground: P4306R0[3] compares the configuration-ownership models, and P4297R0[4] asks EWG to decide the ownership relationship. The question none of them resolves is the one taken up here: after the violation handler runs on a detected core-language violation, does execution continue past the violation or does the program terminate?
+C++26 Contracts (P2900R14[1]) define the evaluation semantics and the single violation handler this paper takes as fixed. P3100R8[2] proposes to extend that machinery to the runtime-checkable cases of core-language undefined behaviour, and P3878R1, adopted into C++26, already settled the parallel question for standard-library hardening. Two companions cover the neighbouring ground: P4306R0[3] compares the configuration-ownership models, and P4297R0[4] asks EWG to decide the ownership relationship. None of them resolves what this paper takes up: after the violation handler runs on a detected core-language violation, does execution continue past the violation or does the program terminate?
The contributions are:
@@ -57,14 +61,14 @@ The contributions are:
2. A survey of deployed hardened implementations, finding that every one terminates or traps on a detected core-language violation and none makes continuation its production default (Section 4).
3. Two further findings against a continuing default: it carries an exception-handling cost the reference implementers decline to incur, and it runs against P3878R1, the decision C++26 already adopted for the adjacent case (Section 5).
4. A terminating response expressed by reusing the C++26 `enforce` semantic and the existing termination rule, adding no new semantic and leaving the meaning of `noexcept` unchanged (Section 7).
-5. The shape a continuing response takes if the committee retains one: an opt-in, non-portable facility bounded to an adoption period, not a default (Section 8).
+5. The shape a continuing response takes if the committee retains one: an opt-in, non-portable facility bounded to an adoption period (Section 8).
6. A demonstration that the finding is independent of the configuration question, holding whether the Contracts facility or the Profiles framework owns the selection (Section 10).
The analysis rests on three assumptions, each stated where it is used and gathered here for the reader who reads only the surface:
- No compiler yet implements implicit contract assertions with any semantic, so the comparison reasons from deployed analogues rather than from a conforming implementation.
-- The strong finding covers the class of core-language checks whose continuation is undefined; the class whose continuation is into a defined result (Section 6) is treated separately, and the continuation question there is left open.
-- C++26 as ratified is fixed; the question belongs to the open C++29 work on implicit assertions.
+- The strong finding covers the class of core-language checks whose continuation is undefined. The class whose continuation is into a defined result (Section 6) is treated separately, and the continuation question there is left open.
+- C++26 as ratified is fixed. What remains open belongs to the C++29 work on implicit assertions.
The recurring terms carry one meaning throughout:
@@ -83,19 +87,19 @@ The recurring terms carry one meaning throughout:
## 3. Two questions inside the one word 'observe'
-This section separates the parts of the `observe` semantic, because the stated semantic treats as one decision what is really two. A reader who knows the C++26 Contracts model can skip to the last paragraph.
+Because the stated semantic treats two decisions as one, this section separates the parts of the `observe` semantic. A reader who knows the C++26 Contracts model can skip to the last paragraph.
-P3100R8[2] ("A framework for systematically addressing undefined behaviour in the C++ Standard") proposes to guard the 77 runtime-checkable cases of core-language undefined behaviour with implicit contract assertions, checks the language itself inserts at each point of undefined behaviour, configured through the same evaluation semantics C++26 Contracts provide for explicit assertions. The question this paper examines arises from that extension.
+P3100R8[2] ("A framework for systematically addressing undefined behaviour in the C++ Standard") proposes to guard the 77 runtime-checkable cases of core-language undefined behaviour with implicit contract assertions, checks the language itself inserts at each point of undefined behaviour, configured through the same evaluation semantics C++26 Contracts provide for explicit assertions.
C++26 Contracts (P2900R14[1], `[basic.contract.eval]`) define four evaluation semantics for a contract assertion. Under `ignore`, the assertion has no effect. Under `observe`, the contract-violation handler is invoked and, if it returns normally, control continues past the point of evaluation. Under `enforce`, the handler is invoked and the program is then contract-terminated. Under `quick-enforce`, the program is contract-terminated without invoking the handler. The handler is a single, program-wide function, `::handle_contract_violation`, and P3100R8[2] Section 5.6 proposes to keep it single for implicit assertions rather than introducing a second one.
P3100R8[2] proposes to respecify the runtime-checkable cases of core-language undefined behaviour as implicit contract assertions evaluated with five semantics: the four from C++26 plus a fifth, `assume`, which preserves today's undefined behaviour as an escape hatch. That extension raises a question: on a detected core-language violation, such as a signed-integer overflow or an out-of-bounds access, what happens after the check fails?
-The word `observe` bundles two things that can be separated. The first is the handler invocation (termed "hook" henceforth): the handler is invoked, and it logs the violation, giving a deployment one place to record and report it. The second is the continue-past-violation response (termed "continuation" henceforth): after the handler returns, execution proceeds past the violation. The hook is uncontested and is preserved by every response this paper discusses, `enforce` included. The continuation is the contested part. The single difference between `enforce` and `observe` is what happens on a normal return from the handler: `enforce` terminates, `observe` continues. The sections that follow credit the hook and examine only the continuation.
+The word `observe` bundles two things that can be separated, the first being the handler invocation (termed "hook" henceforth): the handler is invoked, and it logs the violation, giving a deployment one place to record and report it. The second is the continue-past-violation response (termed "continuation" henceforth): after the handler returns, execution proceeds past the violation. While the hook is uncontested and is preserved by every response this paper discusses, `enforce` included, the continuation is the contested part. The single difference between `enforce` and `observe` is what happens on a normal return from the handler: `enforce` terminates, `observe` continues. What follows credits the hook and examines only the continuation.
-Scope: this paper concerns implicit assertions on core-language undefined behaviour, where a detected violation means the program has already entered a state the language does not define. Explicit, author-written contract assertions, where a precondition can encode a recoverable condition and continuation can be meaningful, are outside this scope. Whether core-language checks are best specified as implicit contract assertions or as profile-governed checks is the architecture question P4297R0[4] addresses; the terminology here follows P3100R8, because the response question arises within its proposal.
+Scope: this paper concerns implicit assertions on core-language undefined behaviour, where a detected violation means the program has already entered a state the language does not define. Explicit, author-written contract assertions, where a precondition can encode a recoverable condition and continuation can be meaningful, are outside this scope. Whether core-language checks are best specified as implicit contract assertions or as profile-governed checks is the architecture question P4297R0[4] addresses. The terminology here follows P3100R8, because the response question arises within its proposal.
-The terminating response preserves the hook. Under `enforce`, the handler is invoked and logs the violation before the program terminates. Every telemetry need the handler serves - recording the violation site, its kind, the predicate text - survives the terminating response unchanged. What `enforce` removes is the continuation alone: execution past a state the language does not define. The deployer's ability to observe a violation is not at stake; only the program's ability to keep running after one is.
+The terminating response preserves the hook. Under `enforce`, the handler is invoked and logs the violation before the program terminates. Every telemetry need the handler serves - recording the violation site, its kind, the predicate text - survives the terminating response unchanged. What `enforce` removes is the continuation alone: execution past a state the language does not define. The deployer's ability to observe a violation is not at stake, only the program's ability to keep running after one is.
---
@@ -103,9 +107,9 @@ The terminating response preserves the hook. Under `enforce`, the handler is inv
This section reports what deployed hardening does on a detected core-language violation. The pattern is uniform.
-The survey states its population and selection rule up front. The population is the implementations that detect a core-language violation in production; the selection rule is every such implementation the authors could identify, recorded in its default or production configuration. That frame deliberately excludes the availability-first domains - long-running services and fault-tolerant systems that might prefer bounded degradation to a hard stop - which are not sampled in Table 1 and are engaged on their own terms in Section 4.1. Table 1 is therefore evidence about the sampled population; the excluded population is met separately, not by silence.
+Up front, the survey states its population and selection rule. The population is the implementations that detect a core-language violation in production, and the selection rule is every such implementation the authors could identify, recorded in its default or production configuration. That frame deliberately excludes the availability-first domains - long-running services and fault-tolerant systems that might prefer bounded degradation to a hard stop - which are not sampled in Table 1 and are engaged on their own terms in Section 4.1. Table 1 is therefore evidence about the sampled population.
-Table 1. Response to a detected violation in deployed hardened implementations, in their production configurations. Every entry terminates or traps; none makes continuation its production default.
+Table 1. Response to a detected violation in deployed hardened implementations, in their production configurations. Every entry terminates or traps. None makes continuation its production default.
| Implementation | Response on violation | Source |
|---|---|---|
@@ -119,41 +123,41 @@ Table 1. Response to a detected violation in deployed hardened implementations,
| UBSan (production guidance) | trap (`-fsanitize-trap`); recover is "meant for testing purposes" | [11] |
| Abseil `CHECK`, Folly `XCHECK`, WebKit `RELEASE_ASSERT` | terminate | [12] |
-The survey covers standard-library hardening modes, production sanitizer configurations, and critical-assertion facilities. libc++ `observe` and Bloomberg `bsls_review` also ship a non-default continue mode documented as adoption-only; Table 1 records the default response, and those modes are examined in Section 8.
+The survey covers standard-library hardening modes, production sanitizer configurations, and critical-assertion facilities. libc++ `observe` and Bloomberg `bsls_review` also ship a non-default continue mode documented as adoption-only. Table 1 records the default response, and those modes are examined in Section 8.
-Every surveyed implementation that detected a core-language violation and chose a response chose termination. Zero chose continuation as a production default. The absence of a conforming implementation of implicit contract assertions is symmetrical - no compiler has one with any semantic. The deployment analogues are not symmetrical: the terminating response has nine deployed analogues that selected it; the continuing response has none as a production default. The precedent is asymmetrical.
+Every surveyed implementation that detected a core-language violation and chose a response chose termination. Zero chose continuation as a production default. The absence of a conforming implementation of implicit contract assertions is symmetrical - no compiler has one with any semantic. But the deployment analogues are not: the terminating response has nine deployed analogues that selected it, and the continuing response has none as a production default. The precedent is asymmetrical.
-The implementations that log before terminating - libc++ debug mode, glibc `_FORTIFY_SOURCE`, Android IntSan in its production configuration - perform exactly the operation `enforce` specifies: invoke a reporting facility, then terminate. The handler is not absent from the survey; it is present in every entry that reports before it stops.
+The implementations that log before terminating - libc++ debug mode, glibc `_FORTIFY_SOURCE`, Android IntSan in its production configuration - perform exactly the operation `enforce` specifies: invoke a reporting facility, then terminate. The handler is present in every entry that reports before it stops.
-Bloomberg draws the same line in its own contract-checking machinery, and draws it at the library level. Its `bsls_assert` facility terminates by default, its default handler aborting rather than returning, which is the terminating response described here. Its companion `bsls_review` logs and continues, but Bloomberg's own documentation frames that continuation as an adoption aid for tightening checks on working code rather than a permanent mode, and confines it to library-level checks, whose violation leaves the program in a state the library does not define but the language still does, not to core-language undefined behaviour.[13] The commit history records the same reasoning on the terminating side: one commit message states it directly, that a build "with a continuing handler, could cause execution to continue past that point," that "execution path is library undefined behavior and the program would be out of contract anyway," and the change makes the program "always terminate."[14] A deployer of a log-and-continue facility describes continuation past a detected violation as the defect and termination as the fix.
+Bloomberg draws the same line in its own contract-checking machinery, and draws it at the library level. Its `bsls_assert` facility terminates by default, its default handler aborting rather than returning, which is the terminating response described here. Its companion `bsls_review` logs and continues, but Bloomberg's own documentation frames that continuation as an adoption aid for tightening checks on working code rather than a permanent mode, and confines it to library-level checks, whose violation leaves the program in a state the library does not define but the language still does, not to core-language undefined behaviour.[13] On the terminating side, the commit history records the same reasoning: one commit message states it directly, that a build "with a continuing handler, could cause execution to continue past that point," that "execution path is library undefined behavior and the program would be out of contract anyway," and the change makes the program "always terminate."[14] A deployer of a log-and-continue facility describes continuation past a detected violation as the defect and termination as the fix.
-The deployment record therefore establishes one fact: on a detected core-language violation, the terminating response is the one in production use, and the continuing response is not.
+The deployment record therefore establishes one fact: on a detected core-language violation, the terminating response is the one in production use.
### 4.1 The availability-first case
The population Table 1 excludes is where the case for continuation is strongest, and it deserves its strongest form. Stroustrup's P2698R0[15] states it: unconditional termination is "a serious problem" for the systems that are not permitted to stop - long-running services, and the fault-tolerant and safety-critical domains where a crash is itself the failure. If any population would rationally continue past a violation it is this one, and it is exactly the population the survey does not sample.
-Met on its own terms, though, the availability-first domain reaches the same place for the undefined-continuation subset. Its canonical architecture does not keep a faulty unit running in place; it terminates the unit and recovers from a known-good state. Erlang/OTP, built for telecom availability on the Ericsson AXD301 switch, is the model: its "let it crash" discipline lets a process that detects a fault die and a supervisor restart it, and the high availability it reaches comes from that terminate-and-restart, not from executing past the fault.[16] Functional-safety practice draws the line the same way: on a detected fault a system transitions to a safe state - a reset, a failover, a deliberately entered degraded mode - rather than continue on a state its own model no longer defines. Availability in these domains is a property of the recovery boundary, not of in-process continuation past a violation.
+Met on its own terms, though, the availability-first domain reaches the same place for the undefined-continuation subset. Its canonical architecture does not keep a faulty unit running in place. It terminates the unit and recovers from a known-good state. Erlang/OTP, built for telecom availability on the Ericsson AXD301 switch, is the model: its "let it crash" discipline lets a process that detects a fault die and a supervisor restart it, and the high availability it reaches comes from that terminate-and-restart, not from executing past the fault.[16] Functional-safety practice draws the line the same way: on a detected fault a system transitions to a safe state - a reset, a failover, a deliberately entered degraded mode - rather than continue on a state its own model no longer defines. In these domains availability is a property of the recovery boundary.
-That is the terminating response at the unit level, and the hook it depends on is the one preserved here: the handler runs and logs before the unit stops, so the supervisor and the operator learn what failed. The subset the objection does not reach is the defined-replacement class of Section 6, where continuation yields a specified result and the question is left open. A team that has weighed this and still wants to continue in-process past an undefined-state violation is served by the explicit, non-portable opt-in of Section 8, not by making continuation the default.
+Terminate-and-restart is the terminating response at the unit level, and the hook it depends on is the one preserved here: the handler runs and logs before the unit stops, so the supervisor and the operator learn what failed. The subset the objection does not reach is the defined-replacement class of Section 6, where continuation yields a specified result and the question is left open. A team that has weighed this and still wants to continue in-process past an undefined-state violation is served by the explicit, non-portable opt-in of Section 8.
---
## 5. The cost, and the rule it already breaks
-This section adds two findings to the deployment record: the continuation carries a cost the reference implementers decline to incur, and it runs against a decision the committee has already adopted for C++26.
+To the deployment record, this section adds two findings: the continuation carries a cost the reference implementers decline to incur, and it runs against a decision the committee has already adopted for C++26.
-The cost of continuing is not a matter of a branch. Turning a core-language operation into a checked operation that can invoke a handler and continue requires exception-handling machinery around the check: because whether the program's handler is `noexcept` is a link-time decision, P2900R14[1] Section 3.6.6 notes that "the compiler ... has to generate the correct instructions for exception handling around every contract assertion." The implementers who ship hardening declined this. P3191R0[17], from the libc++ team, sets the production requirement that a contract violation "should generate no code at all beyond the equivalent of a branch and a `__builtin_trap()`," with "no exception-handling code being generated around contract predicates," and describes the handler-and-object path as "a lot of code and data being generated for a single assertion." The committee's own response to this cost was to add the `quick-enforce` semantic, which skips the handler entirely, recorded in P3198R0[18]. The isolated cost of the continuation over a trap has not been published as a measured figure; what the record shows is that the reference implementers decline the continuation path in production and the committee added a semantic to avoid its overhead.
+The cost of continuing is not a matter of a branch. Turning a core-language operation into a checked operation that can invoke a handler and continue requires exception-handling machinery around the check: because whether the program's handler is `noexcept` is a link-time decision, P2900R14[1] Section 3.6.6 notes that "the compiler ... has to generate the correct instructions for exception handling around every contract assertion." The implementers who ship hardening declined this. P3191R0[17], from the libc++ team, sets the production requirement that a contract violation "should generate no code at all beyond the equivalent of a branch and a `__builtin_trap()`," with "no exception-handling code being generated around contract predicates," and describes the handler-and-object path as "a lot of code and data being generated for a single assertion." The committee's own response to this cost was to add the `quick-enforce` semantic, which skips the handler entirely, recorded in P3198R0[18]. The isolated cost of the continuation over a trap has not been published as a measured figure. What the record shows is that the reference implementers decline the continuation path in production and the committee added a semantic to avoid its overhead.
-The committee has also already decided this question for the adjacent case. P3878R1[19], adopted into C++26, established that a standard-library hardened precondition may not be evaluated with a non-terminating semantic, on the reasoning that continuing past such a check "can result in violations of hardened preconditions being undefined behaviour, rather than guaranteed to be diagnosed, which defeats the purpose of using a hardened implementation." For the core-language checks whose continuation is likewise undefined, a detected null dereference or out-of-bounds access, the same reasoning applies one level down; it does not reach the class in Section 6, where continuation is into a defined result. One disclosure belongs here: the lead author of P3878R1 is a co-author of this paper and its companions, though the decision was the whole committee's, and the argument stands on the deployment record and the security literature that follow even if the precedent is set aside.
+For the adjacent case, the committee has also already decided this question. P3878R1[19], adopted into C++26, established that a standard-library hardened precondition may not be evaluated with a non-terminating semantic, on the reasoning that continuing past such a check "can result in violations of hardened preconditions being undefined behaviour, rather than guaranteed to be diagnosed, which defeats the purpose of using a hardened implementation." For the core-language checks whose continuation is likewise undefined, a detected null dereference or out-of-bounds access, the same reasoning applies one level down. It does not reach the class in Section 6, where continuation is into a defined result. One disclosure belongs here: the lead author of P3878R1 is a co-author of this paper and its companions, though the decision was the whole committee's, and the argument stands on the deployment record and the security literature that follow even if the precedent is set aside.
On this premise, the present analysis and the Contracts proposal agree, though they reach a different conclusion about the default. Doumler and Berne write in P3097R2[20] that once a program
> is found to be in a possibly corrupted state, executing any user-defined code could result in a vulnerability.
-They keep the `observe` semantic available nonetheless; the same hazard is the reason a corrupted-state continuation should not be the default. The agreement is on the danger; the resolution is where the two diverge.
+They keep the `observe` semantic available nonetheless. The same hazard is the reason a corrupted-state continuation should not be the default. The agreement is on the danger, and the resolution is where the two diverge.
-The security literature is consistent with it. Microsoft's fail-fast documentation states that on a detected corruption "no exception handlers are invoked because the program is expected to be in a corrupted state."[21] The glibc maintainers removed even the backtrace from the heap-corruption path, on the reasoning that "doing more work at this point risks ... enabling code execution exploits."[22] The CERT C++ secure-coding rule ERR56-CPP states that "a violated invariant leaves the program in a state where graceful continued execution is likely to introduce security vulnerabilities."[23] Work on exception unwinding as an exploit surface (CHOP, NDSS 2023[24]) shows that running the unwinder over corrupted state can defeat shadow stacks. No published incident names a C++ contract-violation handler, because C++26 Contracts are not yet deployed; the evidence here is transfer from mechanisms that faced the identical choice and chose to terminate. This security argument is strongest where continuation runs on corrupted or undefined state; for the defined-replacement class of Section 6, it does not apply. For the checks whose continuation is undefined but whose violation is not memory corruption, the transfer is from the principle rather than from the mechanism: the state is undefined, and executing further on undefined state is what the fail-stop doctrine treats as the hazard.
+The security literature is consistent with it. Microsoft's fail-fast documentation states that on a detected corruption "no exception handlers are invoked because the program is expected to be in a corrupted state."[21] The glibc maintainers removed even the backtrace from the heap-corruption path, on the reasoning that "doing more work at this point risks ... enabling code execution exploits."[22] The CERT C++ secure-coding rule ERR56-CPP states that "a violated invariant leaves the program in a state where graceful continued execution is likely to introduce security vulnerabilities."[23] Work on exception unwinding as an exploit surface (CHOP, NDSS 2023[24]) shows that running the unwinder over corrupted state can defeat shadow stacks. Because C++26 Contracts are not yet deployed, no published incident names a C++ contract-violation handler. The evidence here is transfer from mechanisms that faced the identical choice and chose to terminate. Where continuation runs on corrupted or undefined state, this security argument is strongest. For the defined-replacement class of Section 6, it does not apply. For the checks whose continuation is undefined but whose violation is not memory corruption, the transfer is from the principle rather than from the mechanism: the state is undefined, and executing further on undefined state is what the fail-stop doctrine treats as the hazard.
---
@@ -163,19 +167,19 @@ One class of core-language checks continues into defined behaviour, and the obje
Not every core-language check continues into undefined behaviour. P3100R8[2] gives a defined replacement to cases such as signed-integer overflow, which can be specified to produce a wrapped result, so that continuing after the check yields a defined value rather than undefined behaviour. For that class, the objection in Section 5 does not apply, because continuation is into defined behaviour, and `observe` there is coherent.
-What the concession does not supply is a deployed user. The field's response to signed overflow is either `-fwrapv`, which defines wraparound with no handler and no log, or `-ftrapv`, which terminates. P3100R8[2] Section 5.4 maps the first to the `ignore` semantic and the second to `quick-enforce`; neither is the log-and-continue that `observe` would add. So even in the class where continuation is defined, the deployed responses are silent replacement and termination, and no surveyed deployment logs and continues by default. The question the evidence leaves standing is who requires that response; no surveyed deployment answers it. Where a deployer selects a continuing semantic for this defined class, that is a defensible choice; the finding here is limited to the class whose continuation is undefined.
+What the concession does not supply is a deployed user. The field's response to signed overflow is either `-fwrapv`, which defines wraparound with no handler and no log, or `-ftrapv`, which terminates. P3100R8[2] Section 5.4 maps the first to the `ignore` semantic and the second to `quick-enforce`. Neither is the log-and-continue that `observe` would add. So even in the class where continuation is defined, the deployed responses are silent replacement and termination, and no surveyed deployment logs and continues by default. The question the evidence leaves standing is who requires that response, and no surveyed deployment answers it. Where a deployer selects a continuing semantic for this defined class, that is a defensible choice. The finding here is limited to the class whose continuation is undefined.
-A second constraint applies to the defined-replacement class regardless of the safety objection: the cost. If any implicit assertion can be evaluated with a continuing semantic, the exception-handling machinery the reference implementers decline in Section 5 must be generated around every checked operation, because whether the deployer selects `observe` or a terminating semantic is a build-time or link-time decision unknown to the compiler at code-generation time. This makes the cost a property of the specification rather than of any deployer's choice: an implementation that offers `observe` must emit the machinery whether or not a given build selects it. The cost is also class-agnostic: it applies to a signed-overflow check that continues into a defined wrapped result just as it applies to an out-of-bounds check that continues into undefined behaviour. The implementers' objection in P3191R0[17] - "no exception-handling code being generated around contract predicates" - does not distinguish between the two classes, and the generated code cannot.
+Regardless of the safety objection, a second constraint applies to the defined-replacement class: the cost. If any implicit assertion can be evaluated with a continuing semantic, the exception-handling machinery the reference implementers decline in Section 5 must be generated around every checked operation, because whether the deployer selects `observe` or a terminating semantic is a build-time or link-time decision unknown to the compiler at code-generation time. This makes the cost a property of the specification rather than of any deployer's choice: an implementation that offers `observe` must emit the machinery whether or not a given build selects it. The cost is also class-agnostic: it applies to a signed-overflow check that continues into a defined wrapped result just as it applies to an out-of-bounds check that continues into undefined behaviour. In P3191R0[17], the implementers' objection - "no exception-handling code being generated around contract predicates" - does not distinguish between the two classes, and the generated code cannot.
---
## 7. A terminating response
-This section states the response the evidence supports and shows it in code, reusing the C++26 semantics without adding to them. It separates two claims the evidence supports to different degrees. The first is the default: a terminating response, invoke the handler then terminate, is what the deployment record and the committee's own recommendations support. The second is narrower, and the evidence supports it less strongly: whether a continuing response should remain available as a portable guarantee for the class of checks whose continuation is undefined. The default holds whichever way the second question is resolved.
+This section states the response the evidence supports and shows it in code, reusing the C++26 semantics without adding to them. It separates two claims the evidence supports to different degrees. The first is the default: a terminating response, invoke the handler then terminate, is what the deployment record and the committee's own recommendations support. The second is narrower, and the evidence supports it less strongly: whether a continuing response should remain available as a portable guarantee for the class of checks whose continuation is undefined. Whichever way the second question is resolved, the default holds.
-The response is to invoke the handler for its telemetry and then terminate, and to prevent a handler throw from escaping the checked expression. Both halves already exist in C++26. The first is the `enforce` semantic: the handler is invoked and, on a normal return, the program is contract-terminated (P2900R14[1], `[basic.contract.eval]`). The second is the existing rule that an escaping exception at a non-throwing boundary results in termination; applied to an implicit assertion, a handler throw contract-terminates rather than propagating. Expressed as a restriction on P3100R8's proposed implicit assertions, implicit core-language assertions would exclude the observe semantic, and a handler throw from one contract-terminates. Under either architecture the restriction reaches the same checks: whether these implicit checks are configured through Contracts Labels or governed by a profile, the class it covers is the same, implicit checks on core-language undefined behaviour whose continuation is undefined. This adds no new semantic; it reuses `enforce` and the existing termination rule. This is the response the C assert integration already takes: P3290R4[25] Section 2.2 specifies that `assert` invokes the handler nonthrowing and then terminates. On 2026-07-08, SG22 (C/C++ Liaison) polled whether `assert` should let exceptions thrown from contract-violation handlers propagate; both bodies reached consensus against, WG21 by 1-0-2-7-2 and WG14 by 0-0-0-5-2 (SF-F-N-A-SA).[26]
+The response is to invoke the handler for its telemetry and then terminate, and to prevent a handler throw from escaping the checked expression. In C++26, both halves already exist. The first is the `enforce` semantic: the handler is invoked and, on a normal return, the program is contract-terminated (P2900R14[1], `[basic.contract.eval]`). The second is the existing rule that an escaping exception at a non-throwing boundary results in termination. Applied to an implicit assertion, a handler throw contract-terminates rather than propagating. Expressed as a restriction on P3100R8's proposed implicit assertions, implicit core-language assertions would exclude the observe semantic, and a handler throw from one contract-terminates. Under either architecture the restriction reaches the same checks: whether these implicit checks are configured through Contracts Labels or governed by a profile, the class it covers is the same, implicit checks on core-language undefined behaviour whose continuation is undefined. This adds no new semantic. It reuses `enforce` and the existing termination rule. This is the response the C assert integration already takes: P3290R4[25] Section 2.2 specifies that `assert` invokes the handler nonthrowing and then terminates. On 2026-07-08, SG22 (C/C++ Liaison) polled whether `assert` should let exceptions thrown from contract-violation handlers propagate. Both bodies reached consensus against, WG21 by 1-0-2-7-2 and WG14 by 0-0-0-5-2 (SF-F-N-A-SA).[26]
-The default claim is not a new idea. The co-authors of P3100R8[2] and P2900R14[1] recommend the same default. Berne and Lakos, in P3558R1[27], recommend
+The default claim is not a new idea: the co-authors of P3100R8[2] and P2900R14[1] recommend the same default. Berne and Lakos, in P3558R1[27], recommend
> a default evaluation semantic, when nothing else is specified, of `enforce` for all core-language preconditions.
@@ -185,7 +189,7 @@ The enforce default supported here is the one these authors already recommend. T
Both recommendations state the terminating response as the default, and the default claim rests on the deployment record of Section 4 independently of the narrower question below.
-The narrower claim concerns availability, not the default. Excluding the continuing semantic, removing it as a portable guarantee every implementation must carry, rests on the implementer evidence, the cost, and the committee's adopted decision for the adjacent case, and reaches only the class whose continuation is undefined. For the defined-replacement class of Section 6, where continuation yields a specified result, the question is open and the committee may reach a different answer. If a continuing response is retained, its shape is the opt-in, non-portable facility of Section 8, not a default.
+The narrower claim concerns availability, not the default. Excluding the continuing semantic, removing it as a portable guarantee every implementation must carry, rests on the implementer evidence, the cost, and the committee's adopted decision for the adjacent case, and reaches only the class whose continuation is undefined. For the defined-replacement class of Section 6, where continuation yields a specified result, the question is open and the committee may reach a different answer. If a continuing response is retained, it takes the shape of the opt-in, non-portable facility of Section 8.
Consider a detected overflow inside a function marked non-throwing, adapted from P3100R8[2] Section 5.5:
@@ -197,13 +201,13 @@ Under a throwing response, a detected overflow in `x + 1` invokes a handler that
P3100R8 reports that SG21 reached strong consensus for Option A and against the non-throwing Option B, but that consensus was taken on P3541R1[29], the Contracts paper that first proposed the two options. Extending the throwing choice to implicit core-language assertions has not been polled by EWG, which P3100R8 notes "is, of course, entitled to making a different design choice than SG21 did".
-The `noexcept` operator has been part of the function type since P0012R1[30] in C++17; the throwing response keeps its value at `true` while changing what that `true` guarantees. The terminating response leaves the operator alone. Under it, the handler for a violation in `x + 1` logs and the program terminates; `noexcept(x + 1)` remains `true` and remains honest, because nothing escapes. The security concern this raises is not hypothetical: N3103[31], from 2010, records that a `noexcept` violation allowed to continue "can be exploited by a malicious user to bypass security restrictions," and recommends immediate termination.
+Since P0012R1[30] in C++17, the `noexcept` operator has been part of the function type. The throwing response keeps its value at `true` while changing what that `true` guarantees. The terminating response leaves the operator alone. Under it, the handler for a violation in `x + 1` logs and the program terminates. `noexcept(x + 1)` remains `true` and remains honest, because nothing escapes. The security concern this raises is not hypothetical: N3103[31], from 2010, records that a `noexcept` violation allowed to continue "can be exploited by a malicious user to bypass security restrictions," and recommends immediate termination.
There is a second reason to contain the throw, visible without leaving the standard library. Turning a detected violation into a thrown exception unwinds the stack through code that did not anticipate a throw at that point, running destructors on objects whose invariants are momentarily broken, so a frequently benign overflow becomes a double-free or a half-destroyed object. The standard library already does not throw at these moments: `std::vector` reallocation uses `move_if_noexcept` so that a throwing move cannot corrupt the container mid-operation. Bloomberg's test infrastructure records the same collision from the other side: a commit notes that when a destructor "becomes implicitly `noexcept`, so throwing the test exception type out of the assert handler triggers a call to `terminate`," and the workaround is a non-throwing, terminating handler.[32] The terminating response is the one that does not manufacture this defect.
-The underlying problem is general, and it runs in four linked steps. First, the exception-safety model of C++ rests on knowing which operations can throw; code is written to maintain its invariants across those operations and only those. Second, a throwing implicit handler turns every core-language expression into a potential throw point, and no existing code was written to be exception-safe at those points. Third, the result is not a recoverable exception but an unwinding through code that cannot maintain its invariants along the way. Fourth, that unwinding over broken invariants is the condition the CHOP work[24] shows turns stack unwinding into a security vulnerability. The chain resolves the same way each time: writing exception-safe code is possible when the set of throwing operations is known, and effectively impossible when any expression can throw.
+The underlying problem is general, and it runs in four linked steps. First, the exception-safety model of C++ rests on knowing which operations can throw. Code is written to maintain its invariants across those operations and only those. Second, a throwing implicit handler turns every core-language expression into a potential throw point, and no existing code was written to be exception-safe at those points. Third, the result is not a recoverable exception but an unwinding through code that cannot maintain its invariants along the way. Fourth, that unwinding over broken invariants is the condition the CHOP work[24] shows turns stack unwinding into a security vulnerability. The chain resolves the same way each time: writing exception-safe code is possible when the set of throwing operations is known, and effectively impossible when any expression can throw.
-The terminating response leaves build-time configurability intact. Under P3100R8's proposal, a deployer still selects among `enforce` (invoke the handler, then terminate), `quick-enforce` (trap without the handler), and `ignore` (no check) for an implicit core-language assertion, and keeps full control of the handler body. The same three choices remain under a Profiles-first architecture, where a profile selects the evaluation semantic for the checks it governs. What the finding narrows is the menu for one class of assertion, not the principle that the evaluation semantic is a build-time choice.
+The terminating response leaves build-time configurability intact. Under P3100R8's proposal, a deployer still selects among `enforce` (invoke the handler, then terminate), `quick-enforce` (trap without the handler), and `ignore` (no check) for an implicit core-language assertion, and keeps full control of the handler body. The same three choices remain under a Profiles-first architecture, where a profile selects the evaluation semantic for the checks it governs. For one class of assertion, the finding narrows the menu and leaves untouched the principle that the evaluation semantic is a build-time choice.
The bifurcation this draws, implicit core-language assertions terminate while explicit contracts may still throw, is deliberate and defensible. It is the same line P3878R1[19] drew for hardening, and it rests on the difference the scope in Section 3 named: an author-written precondition can encode a recoverable condition, whereas a detected core-language violation means the program is already in a state the language does not define. This is also the answer to the objection that a bug is a bug and the semantics should be uniform: the committee has already treated the two differently, one level up.
@@ -213,15 +217,15 @@ The bifurcation this draws, implicit core-language assertions terminate while ex
This section addresses the case in which the committee concludes a continuing response must be available to someone. Where it is available, the deployed precedents share one shape: an opt-in, non-portable facility, bounded to an adoption period rather than a default or a portable guarantee.
-The case for a continuing response deserves its strongest statement, and two forms of it are real. The first is availability: a long-running service or a fault-tolerant embedded system may prefer bounded degradation to a hard stop, so that for such a system a violation that terminates is itself the failure. The second is migration: a large codebase that adds a new check needs a way to find the violations it surfaces before it enforces them, so that turning the check on does not stop a program that works today. Both are legitimate.
+The case for a continuing response deserves its strongest statement, and two forms of it are real. Availability is the first: a long-running service or a fault-tolerant embedded system may prefer bounded degradation to a hard stop, so that for such a system a violation that terminates is itself the failure. The second is migration: a large codebase that adds a new check needs a way to find the violations it surfaces before it enforces them, so that turning the check on does not stop a program that works today. Both are legitimate.
-The answer distinguishes them. The migration need is met by the hook without the continuation: the terminating response already invokes the handler and logs, so a team sees every violation before it enforces and moves from find to fix to enforce without ever running past a live violation. The availability need is real where continuation is into a defined result, the class of Section 6, and there the objection does not apply. Where continuation is into undefined behaviour, keeping the program running is not availability but execution on a corrupted state, which the security literature in Section 5 identifies as the more dangerous failure. What remains, a team that has weighed this and still chooses to continue past an undefined-state violation, is served by the facility below, not by a default.
+The answer distinguishes them. The migration need is met by the hook without the continuation: the terminating response already invokes the handler and logs, so a team sees every violation before it enforces and moves from find to fix to enforce without ever running past a live violation. Where continuation is into a defined result, the class of Section 6, the availability need is real, and there the objection does not apply. Where continuation is into undefined behaviour, keeping the program running is not availability but execution on a corrupted state, which the security literature in Section 5 identifies as the more dangerous failure. What remains, a team that has weighed this and still chooses to continue past an undefined-state violation, is served by the facility below.
-A continuing response has a defensible shape, and the field already uses it. It is the shape of an explicit, non-default opt-in that its own documentation labels as undefined behaviour and disclaims. The libc++ `observe` semantic is documented in these terms: "Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant to make adopting hardening easier but should not be used outside of the adoption period."[5] Bloomberg's `bsls_review` is the same idea deployed: an explicit, temporary downgrade from `assert` to log-and-continue while a newly tightened check is rolled out, on library-level checks rather than core-language undefined behaviour.[33][13] The .NET platform offers the closest full-lifecycle precedent: it once let managed code opt into catching corrupted-state exceptions, then discouraged it with an analyzer whose guidance is "the safest option is to allow the process to crash," and ultimately made the opt-in inert.[34]
+A continuing response has a defensible shape, and the field already uses it. It is the shape of an explicit, non-default opt-in that its own documentation labels as undefined behaviour and disclaims. The libc++ `observe` semantic is documented in these terms: "Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant to make adopting hardening easier but should not be used outside of the adoption period."[5] Bloomberg's `bsls_review` is the same idea deployed: an explicit, temporary downgrade from `assert` to log-and-continue while a newly tightened check is rolled out, on library-level checks rather than core-language undefined behaviour.[33][13] The .NET platform is the closest full-lifecycle precedent: it once let managed code opt into catching corrupted-state exceptions, then discouraged it with an analyzer whose guidance is "the safest option is to allow the process to crash," and ultimately made the opt-in inert.[34]
-These precedents share three properties, and a continuing facility for core-language checks would need all three. It is opt-in, so the default remains the terminating response. It is non-portable and implementation-defined, so it does not become a guarantee every implementation must carry, which is what would re-import the cost in Section 5. And it is marked and disclaimed at the point of use, so that continuing past a detected violation is an affirmative choice recorded in the source, owned by whoever makes it, rather than a behaviour hidden in a default. A facility with those three properties answers the migration case that motivates `observe`, because the transitional need, to see violations before enforcing them, is met by the hook, which the terminating response already provides, and continuing during a rollout is a per-project, non-portable concern that a build already expresses today.
+These precedents share three properties, and a continuing facility for core-language checks would need all three. It is opt-in, so the default remains the terminating response. It is non-portable and implementation-defined, so it does not become a guarantee every implementation must carry, which is what would re-import the cost in Section 5. And it is marked and disclaimed at the point of use, so that continuing past a detected violation is an affirmative choice recorded in the source, owned by whoever makes it, rather than a behaviour hidden in a default. A facility with those three properties answers the migration case that motivates `observe`, because the transitional need, to see violations before enforcing them, is met by the hook, which the terminating response already provides. Continuing during a rollout is a per-project, non-portable concern that a build already expresses today.
-Whether such a facility should be built is a separate question; what matters is the shape: not the default, and not a portable semantic every implementation must support.
+Whether such a facility should be built is a separate question from its shape: an explicit opt-in outside the portable semantics, never the default.
---
@@ -231,7 +235,7 @@ This analysis has problems, and they are worth stating. It reasons from analogy
### The first problem: the security literature does not apply to a correctness tool
-Contracts are a correctness tool for finding bugs, not a security mechanism. Citing fail-fast policies, CERT rules, and exploit research imports a category that does not belong. The category distinction is correct: contracts are not a security feature. The literature is cited for its subject, not its category. Doumler and Berne write, in P3097R2[20], that once a program "is found to be in a possibly corrupted state, executing any user-defined code could result in a vulnerability." The hazard of continuing past a detected violation is documented by the authors of the feature under examination. Whether a correctness tool should draw conclusions from security literature is a judgment the committee makes; the evidence from that literature is placed here so the committee can weigh it or set it aside.
+Contracts are a correctness tool for finding bugs. Citing fail-fast policies, CERT rules, and exploit research imports a category that does not belong. The category distinction is correct, and the literature is cited for its subject, not its category. Doumler and Berne write, in P3097R2[20], that once a program "is found to be in a possibly corrupted state, executing any user-defined code could result in a vulnerability." The hazard of continuing past a detected violation is documented by the authors of the feature under examination. Whether a correctness tool should draw conclusions from security literature is a judgment the committee makes. The evidence from that literature is placed here so the committee can weigh it or set it aside.
### The second problem: restricting the semantic limits deployer choice
@@ -239,7 +243,7 @@ The standard should offer all four semantics and let each deployment decide. Res
### The third problem: the migration story requires seeing all violations before enforcing
-A large codebase that turns on a new check needs to find every violation it surfaces before it enforces. If the first violation terminates the program, the team sees one signal per deployment. Under the terminating response, the handler fires, logs the violation, and the program terminates. The next deployment, with the first violation fixed, reveals the second. The hardened implementations in Table 1 rolled out checks across codebases measured in hundreds of millions of lines - Google's production fleet, libc++ across Apple's platforms, glibc across every Linux distribution - with the terminating response and without a log-and-continue semantic. The rare violation that only production inputs trigger is handled the way large deployments handle any risky change: a staged rollout surfaces it in a canary population first, where termination stops only the canary and the logged violation identifies the site to fix before the check reaches the full fleet.
+A large codebase that turns on a new check needs to find every violation it surfaces before it enforces. If the first violation terminates the program, the team sees one signal per deployment. Under the terminating response, the handler fires, logs the violation, and the program terminates. With the first violation fixed, the next deployment reveals the second. Across codebases measured in hundreds of millions of lines - Google's production fleet, libc++ across Apple's platforms, glibc across every Linux distribution - the hardened implementations in Table 1 rolled out checks with the terminating response and without a log-and-continue semantic. The rare violation that only production inputs trigger is handled the way large deployments handle any risky change: a staged rollout surfaces it in a canary population first. There termination stops only the canary, and the logged violation identifies the site to fix before the check reaches the full fleet.
### The fourth problem: Bloomberg's `bsls_review` is the deployed counter-example
@@ -247,13 +251,13 @@ Bloomberg maintains `bsls_review`, a companion to `bsls_assert` that logs and co
### The fifth problem: the proposed restriction paternalizes the deployer
-Restricting `observe` for implicit assertions tells every deployment that the committee knows their codebase better than they do; a team that has evaluated the trade-offs and chosen log-and-continue at scale, even for years, is making an informed engineering decision, not requesting guardianship. But P3878R1[19] already makes this restriction for library hardening, on the reasoning that continuing past a diagnosed violation defeats the purpose of diagnosing it; the paternalism charge applies to that adopted C++26 decision equally, or the principle permits the same restriction one level down.
+Restricting `observe` for implicit assertions tells every deployment that the committee knows their codebase better than they do. A team that has evaluated the trade-offs and chosen log-and-continue at scale, even for years, is making an informed engineering decision, not requesting guardianship. But P3878R1[19] already makes this restriction for library hardening, on the reasoning that continuing past a diagnosed violation defeats the purpose of diagnosing it. The paternalism charge applies to that adopted C++26 decision equally, or the principle permits the same restriction one level down.
For the class it covers, the restriction also removes no coherent choice. The axiom that makes runtime-checkable undefined behaviour detectable at all, that undefined behaviour carries no specification of what follows, is the axiom that makes its continuation unspecifiable: the handler returns, and what executes next depends on a program state that has no defined meaning. By the standard that a component's test suite is its specification, there is nothing to specify past the violation, because a detected core-language violation falls outside every contract the tests express. Undefined behaviour cannot be documented, and its continuation cannot be specified either.
-This unspecifiability argument reaches only the class whose continuation is undefined. For the defined-replacement class of Section 6, where continuing yields a specified result such as a wrapped value, `observe` is coherent; the objection to it there is the cost in Section 6, and the argument here does not apply.
+This unspecifiability argument reaches only the class whose continuation is undefined. For the defined-replacement class of Section 6, where continuing yields a specified result such as a wrapped value, `observe` is coherent. The objection to it there is the cost in Section 6, and the argument here does not apply.
-In its throwing form the continuation also inverts a separation the language keeps elsewhere: the evaluation semantic is a deployment property chosen at build or link time, yet a throwing handler leaves `noexcept` reporting `true` while changing what that `true` guarantees (Section 7), letting a deployment decision govern the meaning of a type-system property, the separation the polymorphic-allocator model was built to preserve.
+In its throwing form the continuation also inverts a separation the language keeps elsewhere: the evaluation semantic is a deployment property chosen at build or link time, yet a throwing handler leaves `noexcept` reporting `true` while changing what that `true` guarantees (Section 7). That lets a deployment decision govern the meaning of a type-system property, the separation the polymorphic-allocator model was built to preserve.
---
@@ -263,7 +267,7 @@ The response question and the configuration question are independent, and a boun
The first is what the response to a detected core-language violation should be. The second is who configures that response: whether the selection of a semantic for a core-language check is expressed through the Contracts configuration facility (P3400R3[35]) or through the Profiles framework (P3589R2[36]). Routing core-language checks through the contract-violation handler is the layering that P4297R0[4] examines and would put to an explicit poll.
-The layering is described here as the arrangement P3100R8 proposes; it is not resolved. The two questions can be answered independently, and the finding that the response should terminate holds regardless of which facility owns the selection. Under a Profiles-first architecture the finding says the same thing: a profile that covers core-language undefined behaviour defaults to a terminating response for the class whose continuation is undefined, and the deployer's ability to observe a violation is preserved by the handler invocation that precedes termination. The comparison of the ownership models is in P4306R0[3].
+The layering is described here as the arrangement P3100R8 proposes. It is not resolved. The two questions can be answered independently, and the finding that the response should terminate holds regardless of which facility owns the selection. Under a Profiles-first architecture the finding says the same thing: a profile that covers core-language undefined behaviour defaults to a terminating response for the class whose continuation is undefined. The deployer's ability to observe a violation is preserved by the handler invocation that precedes termination. The comparison of the ownership models is in P4306R0[3].
---
@@ -271,7 +275,7 @@ The layering is described here as the arrangement P3100R8 proposes; it is not re
Of the responses to a detected core-language violation, one is in production use across every hardened implementation surveyed here, and it is the terminating response: invoke the handler, log, and terminate. The continuing response is not in production use for core-language undefined behaviour, carries a cost the reference implementers decline to incur, and runs against P3878R1[19], the decision C++26 already adopted for the adjacent case. Where continuation is defined, the record still shows no deployment that logs and continues.
-The finding of this paper is that the terminating response is the one the evidence supports as the default, and that it can be had by reusing the C++26 `enforce` semantic and the existing termination rule, without a new semantic and without changing the meaning of `noexcept`. That default holds across both classes of check. The narrower finding, that a continuing response should not be a portable guarantee every implementation carries, is scoped to the class whose continuation is undefined; for the defined-replacement class of Section 6 the question is left open. If a continuing response is to exist for the undefined class, it belongs as an explicit, per-project opt-in outside the portable feature, not as a default. Whether to build such a facility is a question for the committee, not this paper. The record is placed here for the committee's use; the paper makes no request.
+The finding of this paper is that the terminating response is the one the evidence supports as the default, and that it can be had by reusing the C++26 `enforce` semantic and the existing termination rule, without a new semantic and without changing the meaning of `noexcept`. Across both classes of check, that default holds. The narrower finding, that a continuing response should not be a portable guarantee every implementation carries, is scoped to the class whose continuation is undefined. For the defined-replacement class of Section 6 the question is left open. If a continuing response is to exist for the undefined class, it belongs as an explicit, per-project opt-in outside the portable feature. Whether to build such a facility is a question for the committee, not this paper. The record is placed here for the committee's use. The paper makes no request.
---
@@ -305,7 +309,7 @@ The authors of P2900R14[1] and P3100R8[2], whose careful s
[11] [Clang UBSan](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) - "UndefinedBehaviorSanitizer" (LLVM Project, 2025).
-[12] [P3911R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3911r2.html) - "Make Contracts Reliably Non-Ignorable" (Darius Neă&tcommaaccent;u, Andrei Alexandrescu, Lucian Radu Teodorescu, Radu Nichita, Herb Sutter, 2026).
+[12] [P3911R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3911r2.html) - "Make Contracts Reliably Non-Ignorable" (Darius Neățu, Andrei Alexandrescu, Lucian Radu Teodorescu, Radu Nichita, Herb Sutter, 2026).
[13] [bsls_review](https://github.com/bloomberg/bde/blob/main/groups/bsl/bsls/bsls_review.h) - "bsls_review: Provide assertion macros to safely identify contract violations" (Bloomberg BDE, 2019).