Browse Source

Establish toolchain and language versioning (#4105)

Proposal for how Carbon version numbers work:

- A single version across language, standard library, compiler, linker,
etc.
-   Semantic Versioning (SemVer) based
- Details of how SemVer criteria for major, minor, and patch should
apply to
    Carbon
- Details of how we will operate before 1.0 and how this connects to
Carbon's
    milestones
- Directional guidance for future work including post-1.0 versions, LTS
    versions, and standardization

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Chandler Carruth 1 năm trước cách đây
mục cha
commit
2fcff24100
2 tập tin đã thay đổi với 575 bổ sung0 xóa
  1. 270 0
      docs/project/versioning.md
  2. 305 0
      proposals/p4105.md

+ 270 - 0
docs/project/versioning.md

@@ -0,0 +1,270 @@
+# Toolchain and language versioning
+
+<!--
+Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+Exceptions. See /LICENSE for license information.
+SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+-->
+
+[Pull request](https://github.com/carbon-language/carbon-lang/pull/4105)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Overview](#overview)
+-   [Major version increments](#major-version-increments)
+    -   [Breaking changes](#breaking-changes)
+    -   [Exclusions to what constitutes a breaking change](#exclusions-to-what-constitutes-a-breaking-change)
+-   [Minor version increments](#minor-version-increments)
+-   [Patch version increments](#patch-version-increments)
+    -   [Examples:](#examples)
+-   [Pre-release versions](#pre-release-versions)
+    -   [Release qualification pre-releases: `MAJOR.MINOR.PATCH-rc.N`](#release-qualification-pre-releases-majorminorpatch-rcn)
+    -   [Incremental development versions: `MAJOR.MINOR.PATCH-0.{nightly,dev}.N`](#incremental-development-versions-majorminorpatch-0nightlydevn)
+        -   [Nightly pre-release versions](#nightly-pre-release-versions)
+        -   [Development pre-release versions](#development-pre-release-versions)
+-   [Relevant proposal](#relevant-proposal)
+
+<!-- tocstop -->
+
+## Overview
+
+Carbon uses a single versioning scheme across both the language itself and
+toolchain, including the standard library, compiler, linker, and all development
+tools released by the main Carbon project.
+
+The scheme conforms to and is closely based on Semantic Versioning
+(https://semver.org/ -- version 2.0.0):
+
+-   Carbon versions: `MAJOR.MINOR.PATCH`
+-   Releases with backwards incompatible changes, including a deprecation that
+    might trigger a build-breaking warning, increment `MAJOR` after reaching the
+    `1.0` milestone, and increment `MINOR` before then.
+-   Releases with only backwards compatible changes are not expected to happen.
+-   Releases containing only bug fixes increment `PATCH`.
+-   Pre-release suffixes:
+    -   `MAJOR.MINOR.PATCH-rc.N`: The N-th potentially viable candidate for a
+        release.
+    -   `MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD`: A nightly incremental
+        development build on a particular day during development of that
+        version.
+    -   `MAJOR.MINOR.PATCH-0.dev`: An interactive, incremental development build
+        on a particular day by some developer during development of that
+        version.
+
+See the sections below for the details of each aspect of these versions.
+
+## Major version increments
+
+Aligned with SemVer, the major version must increment for any _breaking change_
+to the language or any part of the toolchain.
+
+The first increment from 0 to 1 is expected to be based on achieving a desired
+milestone of feature completeness and quality to declare the language to have
+reached a stable version.
+
+Subsequent increments are expected to be done with a time-based release
+strategy. Features (or breaking changes) ready to ship will do so, and others
+will wait for the next major release. The exact cadence used is future work and
+should be determined based on discussions with Carbon's users in the ramp up to
+and after reaching the 1.0 milestone.
+
+However, just because we increment the major version for a major release and
+_can_ make breaking changes doesn't mean we _will_ or _should_. Breaking
+language changes are extraordinarily expensive for users due to the inherent
+scale of churn they impose. It is tempting to try to make non-breaking releases
+instead, but our experience with C++ language, compiler, and standard library
+updates is that truly making no breaking changes is extremely difficult and
+overly constraining. We expect most releases, especially in the early phases of
+the language to involve _some_ amount of breaking change and will simply work to
+make these as cheap to upgrade through and minimal as we can.
+
+At some future point, it is possible that Carbon will become so stable that it
+makes sense to consider using minor version increments for some releases. If and
+when this happens, we should revisit our versioning and release policies to
+establish a predictable and unsurprising structure.
+
+### Breaking changes
+
+Beyond traditional breaking API changes in either standard library APIs or tool
+APIs, Carbon also includes breaking changes in the language or toolchain.
+Language and toolchain breaking changes are any that cause correct, functioning,
+and non-reflective code to become invalid, rejected, incorrect, or silently
+change behavior.
+
+### Exclusions to what constitutes a breaking change
+
+Carbon excludes "reflective code" which is in some way detecting the Carbon
+version, or the presence or absence of features and as a consequence can be
+"broken" by detecting changes that are correctly designed to otherwise be
+non-breaking. We don't want adding features to be considered a breaking change
+and so exclude code that specifically detects such additions.
+
+Carbon also excludes breaking changes to incorrect code unless it was accepted
+and functioning in some useful, and typically widespread, way despite its bugs.
+
+## Minor version increments
+
+Currently, Carbon plans to primarily use the minor version increments with a 0
+major version to track our progress towards our 1.0 milestone of a feature
+complete initial language. As a consequence we have defined 0.1 and 0.2
+milestones and may define more steps as needed.
+
+Beyond this and in a post-1.0 language world, we expect most significant
+features to also accompany some small and manageable breaking changes from
+deprecations. We may choose to revisit this in the future, but our current plan
+is not to make minor version releases post-1.0 and instead focus on our
+commitment to making those updates both easy and scalable for language users.
+
+## Patch version increments
+
+The patch version will increment when the change is fundamentally a bug fix to a
+previously released version. We expect the vast majority of these to be strictly
+backwards compatible bug fixes.
+
+Patch releases are expected to be driven by demand, and not necessarily present
+if unnecessary. However, the exact schedule and process will be determined as
+part of getting ready for the 1.0 milestone. Before that milestone we don't
+commit to any particular process or cadence for patch releases as no release
+before that point should be considered stable.
+
+Note that we still consider restoring the _intended_ "public API" of a release
+to be a bug fix. When these bug fixes theoretically break new code in a way that
+would typically require a major version increment, they may be made with merely
+a patch version increment when they are in fact restoring our intended behavior
+for that release. However, we take the SemVer guarantees very seriously as these
+fixes can still be disruptive and so we work to hold a high bar for them:
+
+-   They must be in some way fixing a _regressions_ for users from a previous
+    release, not merely a missing feature.
+    -   Can even be a regression in the overall cohesion or reliability of the
+        language or tools, which a bug in a new feature might erode.
+    -   Key is that we motivate any patch fix through the lens of a regression
+        fix and stabilization rather than fixing forward.
+-   The scope of disruption from the fix is demonstrably small, due to some
+    combination of:
+    -   The short time duration of the release containing the regression.
+    -   The narrow scope of code constructs potentially impacted.
+-   The impact of the regression is large and cannot be easily worked around,
+    for example:
+    -   Undermining a core priority of the Carbon Language for a significant set
+        of users.
+    -   Making the engineering cost of adopting the release uneconomical for any
+        significant body of users.
+
+### Examples:
+
+-   We add a new feature that includes a bug which creates unsoundness and
+    allows incorrect code to be compiled that will crash or exhibit UB when
+    executed.
+    -   While this is a new feature and not a bug in an existing feature, it
+        would be a _serious_ regression to the reliability of the language as a
+        whole and the ability of users to reason about the correctness of
+        programs.
+    -   This would be a good candidate for a patch release to address unless it
+        is found very late (months) after the release _and_ the only ways to
+        address would have similarly bad effects on code written since the
+        initial release.
+    -   Even that level of user disruption could potentially be overcome if for
+        example the bug led to security vulnerabilities.
+-   We add a narrowly used new feature that includes a bug where some code
+    patterns that _should_ work with the feature are rejected at compile time or
+    crash reliably.
+    -   Unlikely this is worth a patch release to make an invasive change given
+        the narrow use case.
+    -   A good candidate to introduce a warning or error on using the feature in
+        the way that might lead to a crash, and possibly on using the feature at
+        all.
+-   We add a compiler opt-in feature behind a flag that doesn't work reliably.
+    -   Good candidate to have the flag disabled or trigger a warning message.
+    -   Not a good candidate to try to fix the feature forward.
+-   We add a compiler opt-out feature that doesn't work reliably.
+    -   What to do likely depends on the scope of users impacted. If _very_ few
+        users impacted, possibly just document how to opt-out.
+    -   If enough are impacted to be a nuisance and a regression in experience
+        in general, likely worth attempting a patch release that narrowly fixes
+        or mitigates the issue.
+
+## Pre-release versions
+
+Beyond the major, minor, and patch versions of an actual release, SemVer
+provides a foundation for pre-release version management. However, it is a very
+open-ended foundation with a wide range of possibilities and no particular
+semantic model provided. Some of this is to support the wide variety of
+different needs across different projects. It also reflects the fundamentally
+less crisp and well defined criteria needed for pre-releases.
+
+That said, Carbon should try to have a small and well articulated scheme of
+pre-release versions to help communicate what these releases do and don't
+constitute and how they should be interpreted. These are selected to provide a
+framework that allows pre-release versions to order in a reasonably cohesive way
+when compared using SemVer.
+
+In descending order, Carbon pre-releases may use:
+
+-   `MAJOR.MINOR.PATCH-rc.N`
+-   `MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD`
+-   `MAJOR.MINOR.PATCH-0.dev`
+
+We expand on each of these below to provide criteria and details.
+
+### Release qualification pre-releases: `MAJOR.MINOR.PATCH-rc.N`
+
+We create release candidate or "rc" pre-releases when we believe that version to
+be complete and ready to release and want to collect feedback. There should not
+be interesting or significant gaps, even known ones, from the intended release.
+The expectation should always be that unless some feedback arrives to the
+contrary, the release candidate could simply become the release.
+
+For each pre-release category, we always suffix with a sequential count `N` of
+the pre-releases at that version. We must start with a `.0` in order to have
+subsequent iterations of the same version and category of pre-release to sort
+after the first.
+
+### Incremental development versions: `MAJOR.MINOR.PATCH-0.{nightly,dev}.N`
+
+These are versions that are not in any way associated with the actual expected
+release, but are periodically produced as an incremental tracking of development
+progress. Because they are not expected to be part of qualifying a specific
+release, they're not defined by any particular criteria of completeness or
+readiness. In practice, these will occur at every stage between one release and
+the next.
+
+#### Nightly pre-release versions
+
+These are automated incremental development versions built each night when the
+automated testing passes. There is _no_ attempt to provide any higher quality
+bar or refinement than whatever was in the tree at the time the automation runs,
+and whatever automated tests are present pass.
+
+It is important to emphasize that the primary use case of these pre-release
+versions is not to evaluate a potential release but for the developers and
+contributors to Carbon itself to track incremental development progress. That
+development-oriented goal drives how they are built and what they do and don't
+provide.
+
+Mechanically, we prefix the `nightly` pre-release version component with a `0`
+component to ensure these versions sort before any and all release qualification
+pre-release versions. We also add a date-derived suffix to provide a rough
+chronological ordering of nightly builds with otherwise identical versions.
+
+#### Development pre-release versions
+
+During development, interactive builds of Carbon need to be versioned in an
+unambiguous way, and we do that with the `dev` pre-release version. Much like
+nightly versions, these are only produced as artifacts of development activities
+and are never part of any actual release process. These versions are further not
+built expected to be automated or necessarily repeatable. They may contain
+in-flight edits and all manner of other variations.
+
+Mechanically, we prefix the `dev` pre-release version component with `0` in the
+same way as `nightly` is prefixed to ensure effective ordering. We don't add any
+additional information to keep the mechanics of development builds simple -- for
+example, there is no easy way to extract the date of the build. The exact
+timestamp of the build may be available but doesn't participate for simplicity
+and minimizing cache impact.
+
+## Relevant proposal
+
+-   [Proposal p4105](/proposals/p4105.md)

+ 305 - 0
proposals/p4105.md

@@ -0,0 +1,305 @@
+# Establish toolchain and language versioning
+
+<!--
+Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+Exceptions. See /LICENSE for license information.
+SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+-->
+
+[Pull request](https://github.com/carbon-language/carbon-lang/pull/4105)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Abstract](#abstract)
+-   [Problem](#problem)
+-   [Background](#background)
+-   [Proposal](#proposal)
+-   [Details](#details)
+-   [Directional sketch for the future](#directional-sketch-for-the-future)
+    -   [Language evolution and breaking changes](#language-evolution-and-breaking-changes)
+    -   [Long-Term Stable (LTS) versions and standardization](#long-term-stable-lts-versions-and-standardization)
+-   [Rationale](#rationale)
+-   [Alternatives considered](#alternatives-considered)
+    -   [Do nothing, or just talk about a minimal nightly version.](#do-nothing-or-just-talk-about-a-minimal-nightly-version)
+    -   [Make no breaking changes past 1.0.](#make-no-breaking-changes-past-10)
+    -   [Version different parts of the language separately.](#version-different-parts-of-the-language-separately)
+    -   [Use a custom versioning scheme rather than SemVer.](#use-a-custom-versioning-scheme-rather-than-semver)
+    -   [Include more pre-release variations](#include-more-pre-release-variations)
+
+<!-- tocstop -->
+
+## Abstract
+
+Proposal for how Carbon version numbers work:
+
+-   A single version across language, standard library, compiler, linker, etc.
+-   Semantic Versioning (SemVer) based
+-   Details of how SemVer criteria for major, minor, and patch should apply to
+    Carbon
+-   Details of how we will operate before 1.0 and how this connects to Carbon's
+    milestones
+-   Directional guidance for future work including post-1.0 versions, LTS
+    versions, and standardization
+
+## Problem
+
+We need a versioning scheme for Carbon both for the language and the reference
+toolchain implementing that language. This is important even before we reach any
+specific milestone, as we want to define the schema and implement it _before_ it
+becomes useful for marking specific milestones.
+
+## Background
+
+-   [Semantic Versioning](https://semver.org/)
+-   [Rust Editions](https://doc.rust-lang.org/edition-guide/editions/)
+
+## Proposal
+
+First, Carbon should have a single versioning scheme across both the language
+itself and toolchain, including the standard library, compiler, linker, and all
+development tools released by the main Carbon project.
+
+Second, the Carbon versioning scheme should conform to and be closely based on
+Semantic Versioning (SemVer), which is the de-facto standard for versioning
+schemes in software today. Beyond that, it needs to clarify how the standards
+laid out in SemVer map into a programming language context as programming
+languages and standard libraries have an extraordinarily broad and tightly
+coupled "API" to their users -- all of the source code written in the language.
+Carbon needs to provide extra clarity around what constitutes our "public API"
+for SemVer purposes and the criteria for changes.
+
+Third, SemVer provides a schema for pre-release versions, but is largely
+open-ended on their semantics. Carbon should have a specific set of well defined
+pre-release versions with clearly communicated purpose, nature, and meaning to
+avoid confusion.
+
+Fourth, language versioning is an especially important area for the long-term
+evolution and so Carbon should have some directional guidance around the future
+work expected in the versioning front. This should speak to specific use cases
+and needs that may be left seemingly unaddressed otherwise.
+
+Summarizing the proposed outcome of these together:
+
+-   Carbon versions: `MAJOR.MINOR.PATCH`
+-   `MAJOR` increments on backwards incompatible changes, including a
+    deprecation that might trigger a build-breaking warning.
+    -   Doesn't make it free to make such changes. Each change must pay for its
+        adoption and churn cost. But when a change is needed and well justified,
+        this signifies its introduction.
+    -   Used to establish our milestones for the language.
+    -   Some explicit carve-outs of things designated to not be in the "public
+        API" of the language.
+-   `MINOR` increments only expected during early development with a major
+    version of `0`.
+    -   If Carbon some day stabilizes sufficiently to motivate it, we may
+        revisit this and begin to use the minor version number to signal
+        backwards compatible releases.
+-   `PATCH` increments represent bug fixes only.
+    -   Goal is always fully backwards compatible.
+    -   When fixing the bug makes code written against the release with the bug
+        break, may be unavoidable as the intent was never the buggy behavior.
+        But this is rare and we hold a very high bar for such bug fixes due to
+        their disruptive nature.
+-   Pre-release suffixes:
+    -   `MAJOR.MINOR.PATCH-rc.N`: The N-th potentially viable candidate for a
+        release.
+    -   `MAJOR.MINOR.PATCH-0.nightly.YYYY.MM.DD`: A nightly incremental
+        development build on a particular day during development of that
+        version.
+    -   `MAJOR.MINOR.PATCH-0.dev`: An interactive, incremental development build
+        on a particular day by some developer during development of that
+        version.
+
+## Details
+
+See the added [versioning document](/docs/project/versioning.md).
+
+## Directional sketch for the future
+
+The mechanics outlined above provide a good basis for the initial versions of
+the language (up to 1.0) and any necessary mechanics and tooling around those
+versions. However, beyond 1.0 we expect the needs of the language and project to
+expand and more detailed versioning and evolution tools to become critical. We
+lay out directional sketches here for where Carbon should go in the future to
+address these needs, but these are just directional guidance and will need their
+own carefully considered proposals when the time comes.
+
+### Language evolution and breaking changes
+
+We don't expect a simple version number to be sufficient long-term for the
+evolution needs of the Carbon language. We should plan to at least map these
+major versions into Rust-edition-like controls within source code itself to
+allow incremental adoption across a codebase of fixes for breaking changes or
+adoption of new language features with a single toolchain version. That is, some
+code will want to compile using previous major version semantics even with the
+new compiler.
+
+The approach taken in Rust and proposed for C++ to address this are "editions"
+that source code opts into in order to allow the compiler to support a mixture
+of code in a codebase during incremental adoption. Carbon will need at least
+something equivalent to this, and may want to explore a more fine-grained system
+of opting into specific functionality sets similar to how pragma-based extension
+usage or Circle works.
+
+Regardless of the specifics, a key is that breaking changes are not forcibly
+coupled in their roll-out to updates to the Carbon toolchain. Each step needs to
+be incrementally tackled.
+
+### Long-Term Stable (LTS) versions and standardization
+
+SemVer alone isn't sufficient to address some user needs for language stability.
+It is enough to _detect_ the issues when they arise, but Carbon should also plan
+for how to _address_ these issues.
+
+The suggested direction here is towards designated LTS versions based on a
+particular level of completeness and quality and the user demand. These versions
+will likely need even longer time horizons of support than Linux distro LTS
+releases. The direction should be to embrace this and the potential for
+multi-decade support windows to support users' needs. As the windows of LTSes
+expand, their frequency should reduce to avoid supporting an unsustainable
+diversity of versions.
+
+Exactly how a version is designated as LTS is left to the future work here, but
+it should not be expected to change the schema and structure of the versioning,
+just the support policy applied to the specific release version in question.
+
+Some users may even require standardization of a programming language to make it
+usable in their environment. Carbon should again embrace this need and see the
+standardization as an analogous process to promoting a normal release into an
+LTS. Some relevant and effective LTS should be selected and taken through
+whatever process is identified to create a standard reflecting that LTS version
+of Carbon. Updates to the standard should in turn track as updates to a newer
+LTS. The specifics of how to do this are left to the future work, and they may
+change exactly how this works.
+
+Note that the goal of this future direction isn't to constrain how Carbon can
+arrive effectively at either an LTS release or a standard. Instead, the goal is
+to make it clear that we _should_ be open and planning to achieve these in order
+to meet the needs of candidate Carbon users.
+
+## Rationale
+
+-   [Language tools and ecosystem](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/project/goals.md#language-tools-and-ecosystem)
+    -   Carbon needs a coherent versioning scheme across the language itself as
+        well as its ecosystem. Especially as the language is developing rapidly,
+        being able to sync across all of these with a single, simple versioning
+        scheme is especially important to have the tooling and ecosystem agree
+        about features of the language.
+-   [Software and language evolution](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/project/goals.md#software-and-language-evolution)
+    -   Users of Carbon need a clear model for understanding the language's
+        evolution, tracking it, and responding to significant aspects of it.
+    -   The versioning scheme needs to support a wide variety of versions built
+        in the process of evolving the language without creating confusion.
+
+## Alternatives considered
+
+### Do nothing, or just talk about a minimal nightly version.
+
+Advantages:
+
+-   Carbon is at a very early stage and is a long way from needing release
+    candidates for stable releases or incrementing its major version numbers.
+-   No need to imagine distant future scenarios.
+
+Disadvantages:
+
+-   We already discuss version numbers in various places in the Carbon project,
+    including our [milestones](/docs/project/milestones.md) and
+    [roadmap](/docs/project/roadmap.md).
+-   Establishing how the Carbon project will communicate its updates with
+    version number changes in advance of those updates makes that communication
+    more effective.
+-   Lets us telegraph our intentions and how we are thinking about releasing and
+    cadence to the community and get earlier feedback.
+
+A key to adopting the more detailed versioning plan is that we can change any
+and all of this if and when we need to. This does not lock Carbon into using
+this exact versioning scheme. We will listen to any feedback from potential
+users and can adapt our approach if needed.
+
+### Make no breaking changes past 1.0.
+
+Advantages:
+
+-   Stable languages have the lowest churn costs for users, and are easier to
+    learn at scale.
+
+Disadvantages:
+
+-   This would be in direct opposition to our language goal of supporting
+    software and language evolution.
+    -   This relieves pressure on adding things to the language by avoiding an
+        unreasonably high bar. The pressure is still large due to the very real
+        churn costs, but we avoid amplifying that further with an absolute
+        restriction on fixing issues.
+    -   We expect Carbon to be a reasonably complex language in order to succeed
+        at its goals, ranging from C++ interop to incremental memory safety.
+        This complexity inherently comes with an increased risk and importance
+        of being able to improve and fix issues.
+
+### Version different parts of the language separately.
+
+Advantages:
+
+-   There will be eventually be many differences between changes to the
+    toolchain and changes to the language itself. We might be able to capitalize
+    on those to have a better cadence or versioning scheme for these
+    independently.
+
+Disadvantages:
+
+-   We would have to carefully define and maintain a compatibility matrix
+    between the different components. Increasingly in modern languages and
+    development, the compiler, language, standard library, and tooling are all
+    deeply interdependent.
+-   Experience rolling out major updates to Clang and GCC in large codebases and
+    software ecosystems show even compiler-only or toolchain-only changes easily
+    become as disruptive as smaller updates to the C++ language itself have been
+    over the years. As a consequence, while it is tempting to hope for a sharp
+    difference here we don't in practice anticipate one.
+
+### Use a custom versioning scheme rather than SemVer.
+
+Advantages:
+
+-   We don't actually use all parts of SemVer, which results in awkward unused
+    component of our version number.
+-   SemVer doesn't actually provide an opinionated versioning scheme, merely a
+    relaxed schema that many versioning schemes can fit into.
+
+Disadvantages:
+
+-   Fitting into SemVer ends up needing only very cosmetic changes to a scheme
+    that is meaningful for Carbon. And we can easily specify the open-ended
+    parts of the scheme.
+-   Allows us to easily fit into scripts and people's understanding using SemVer
+    as a baseline model.
+-   Avoids confusion when people from outside the community first encounter
+    Carbon versions as their most likely intuition about the meaning of various
+    aspects of the number will be a reasonable starting point.
+
+### Include more pre-release variations
+
+Initially there was a discussion of potentially defining `alpha` and `beta`
+pre-release versions along with release candidate versions, nightly, and
+development versions. The specific idea was to document versioning we could use
+for longer-lived releases we want to make when not yet ready to call it a
+release candidate.
+
+Advantages:
+
+-   If we end up wanting longer-lived releases prior to arriving at a numbered
+    milestone such as `0.1`, this would provide a ready-made solution.
+-   Specifically, communicating the option for this early might help others
+    avoid being confused by what exactly the state of such a pre-release would
+    be.
+
+Disadvantages:
+
+-   There's no real indication we would ever want to make such a release. It
+    seems easy to imagine the combination of nightly builds and pre-releases
+    completely covering all of the use cases we end up with in practice.
+-   Keeping the infrastructure and documentation for such improbable use cases
+    is drag and friction that doesn't buy us enough to be worthwhile.