We propose a principle that it's always possible to inline the import of
a library from within the same package without changing the meaning of
or diagnostics applied to the code. This is similar to the textual
inlining of an `#include` statement in C++, but is slightly less
general. Cross-package imports place the imported names inside the name
scope of the package, so inlining those necessarily changes the paths
for name lookup.
---------
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
Debian packages github.com/libunwind/libunwind as `libunwind-dev`, and
packages LLVM libunwind as `libunwind-N-dev`, with no meta-package to
install the latest version of LLVM libunwind. The libunwind-dev is not
built as PIC, so doesn't work in our build setup. So a specific version
of LLVM libunwind must be installed.
This proposal removes the `:!` syntax for generics and templates in
favor of keywords (`generic`, `template`, `runtime`) and contextual
defaults for phase. It also replaces `:?` with `fwd` and introduces
`exttype` for extended types.
Assisted-by: Antigravity with Gemini, and Claude
---------
Co-authored-by: Geoff Romer <gromer@google.com>
Our development instructions now recommend installing a number of
binaries through `cargo`. Updating these binaries has to be done by
hand. So we can provide a script that users can use to update them
easily and regularly.
Rumdl already appears to have _significantly_ fewer bugs than prettier,
and a solid LSP for editor integration.
The tool is: https://github.com/rvben/rumdl/
I've separated out the change across three commits for easier review.
The configuration tries to match the existing formatting, the changes to
the all the files are to correct issues found by the new tool.
Assisted-by: Antigravity with Gemini
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
My understanding is that `auto` is encouraged even when there's no
applicable naming convention for the variable, and that suffixes like
`_id` are encouraged where applicable, even if the type is explicit, so
there's really no connection between the two policies.
This provides a native harness with several advantages over
`pre-commit`:
- Faster when initializing the cache
- Smaller cache sizes: under 43mb compared to over 62mb
- Better integration with `uv` for Python usage
Steps for migrating for existing contributors:
1. Install `prek` following instructions in the updated docs.
2. Replace hooks in an existing checkout with a special flag:
```sh
prek install --overwrite
```
The `--overwrite` flag is what removes the old hooks.
If you used the pre-push variant:
```sh
prek install --hook-type pre-push --overwrite
```
3. Optional cleanups:
```sh
rm -rf ~/.cache/pre-commit # reclaim the old hook-environment cache
pipx uninstall pre-commit # if installed via pipx; or `brew uninstall
pre-commit`
```
Assisted-by: Antigravity with Gemini
We've talked about adding the title to the filename several times over
the years and it seems really valuable. This requires us to compute a
"slug" for the title spelling that can be part of the filename.
Beyond that, we crossed 7000 recently, and so it seems likely that we
will need to add digits sooner rather than later here, so this goes
ahead and moves us to 6 digits so we don't have to adjust again for a
reasonable length of time.
To implement this and ensure we can sustain it going forward this adds a
tool to our pre-commit that validates (and corrects if needed) the
filename.
In order to update everything and keep links working, there are a _lot_
of changes, but the most interesting for direct review are in
`proposals/scripts`.
Assisted-by: Antigravity with Gemini
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This removes the need to install any specific version of Python or
figure out how to configure it by instead asking users to install `uv`
and letting it manage Python. Among other advantages, `uv` is designed
to be fast enough to embed directly into our scripts.
We were already using this in `bench_runner.py` so that the script could
import non standard library dependencies. Moving to it for the rest of
our Python unifies the approach and will also enable dependencies
whenever needed.
I've left `github_tools` alone as it has special handling with its own
Bazel setup.
I've updated the contributing tools to explain the approach here.
`@` refers to the current workspace's working copy, but if we want the
command to respect the working copies of other workspaces, we should use
`working_copies()` instead; see
https://docs.jj-vcs.dev/latest/revsets/#functions .
Also remove `all() &` while here, since it is always redundant.
Assisted-by: Google Antigravity
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
jj moved the repo config outside the repo. The config.toml might exist
as a symlink in older repos (probably migration), but not clean repos.
So, overall, just switching the advice setup to make it a bit more
robust with config locations.
Also adding "trunk" to the repo config.
Assisted-by: Google Antigravity with Gemini
This gives a setup where `jj b a` / `jj bookmark advance` can reliably
be used to advance a bookmark for a github pull request, without
advancing other bookmarks such as `trunk` or pointing the bookmark at an
empty commit.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Also increases the default optimization to `-Og` which is likely to give
faster turn-around time which is what we want to optimize for here. This
should also _substantially_ shrink binary sizes, etc.
ASan is still available via `--config=asan`, and is added to the CI
infrastructure. However, my current thought is to only run it after push
rather than in PRs and in the merge queue.
In addition to the general updates, this switches to a required python
3.10 for pre-commit (3.9 is losing support from black).
Note endpoints for build actions are expanding significantly: see
https://app.stepsecurity.io/github/carbon-language/carbon-lang/actions/runs/22779388360?tab=recommendations&jobId=66080970460
for example, I think just the sources are being increased as a
side-effect of updates (and possibly also things not performing as well
as they should have before).
Similarly allowing sudo in pre-commit because it was actually causing
errors in part of build setup, which used sudo to remove files.
Assisted-by: Google Antigravity with Gemini
Giving both of these their own sections under optional tools because I'm
mainly doing this to share example configs.
Assisted-by: Google Antigravity with Gemini
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Adding the note about recursion because it occasionally comes up, and
I'm thinking it'd be helpful to document why we prefer iterative
algorithms.
Also moves a few long style points to headers so that they're easier to
link (I wasn't sure it makes sense to do to all of "syntax and
formatting", but either way what's remaining is shorter if that _is_
linked for reference).
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
Require language design proposals to either update the design documents
to
reflect the proposed changes, or add "TODO" comments to mark where those
changes
will be needed, with links back to the proposal. This is intended to
ensure that
the design documentation accurately informs readers about the current
language
design, without excessively burdening the proposal process.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
I wasn't sure exactly in what way it was problematic, so I was a bit
vague in the justification (though justifications aren't generally
needed/provided here anyway - so I'm not sure it'd be net helpful to add
one anyway).
Carbon is accelerating and adjusting its safety strategy, specifically
to flesh out its memory safety strategy and reflect simplifying
developments in the safety space.
This proposal replaces the previous directional safety strategy with a
new concrete and updated framework for the safety design. It includes a
specific framework for memory safety, simplified build modes, specific
"safety modes", and terminology.
This proposal also provides a _directional_ suggestion for temporal and
data-race safety specifically.
In addition to fully building out the above directional component, there
are several other aspects of our safety design that will follow in
subsequent proposals. The hope is to establish the initial framework
here.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
Co-authored-by: Mike Forster <michael@forster.pro>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
The command is:
```
dump <context> [<ID>|<TYPE><ID>|<TYPE> <ID>|-- <ID>]
TYPE can be "inst", "entity_name", etc.
```
This saves a lot of typing of `SemIR::MakeInstId()` in a debugger, and
allows copy-pasting ids from dump output, as they take the form
`inst33`, etc.
This proposal codifies our preference for designs that support
"progressive
disclosure", meaning that programmers can ignore a given language
concept (or
even be unaware of it) until it is directly relevant to the task they're
doing.
This script runs benchmarks written using Google Benchmark repeatedly,
and collects the results from JSON to render them nicely and provide
statistical information across the runs.
Because this runs the binaries repeatedly, this can help account for
run-to-run variations that are pervasive in many of Carbon's benchmarks,
such as ASLR and other process-specific differences.
It's most basic mode runs a benchmark multiple times and shows both
median and confidence intervals.
It also supports two comparison modes:
1) Regular expressions can be provided that describe collections of
related benchmarks where one is the "main" benchmark and the others
are comparable. For example, Carbon's data structure vs. data
structures from LLVM or Abseil. These will be rendered with the main
benchmark first, followed by a comparison relative to a "baseline" of
each comparable benchmark.
2) A baseline benchmark binary, and potentially different command line
flags, can be provided to run two benchmark binaries and compute
a comparison for each benchmark within them.
Across all of these, the script works to present the best text UI it can
in the console. I may have gotten a bit obsessed with rendering the
benchmark results in a way that is really pretty. There are lots of
fancy color coding and progress bars, etc., when run in in the terminal.
For the basic mode without any comparisons, the results look like:
```
Computing statistically significant deltas only wherethe P-value < 𝛂 of 0.05
Metric key:
BenchmarkName... <median> ± <% at 95th conf>
Benchmark ┃ CPU Time ┃ bytes_per_second
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━
BM_LatencyHash<RandValues<uint8_t>, CarbonHashBench>. │ 3.051 ns ± 2.721% │ 327.8 M ± 2.765%
BM_LatencyHash<RandValues<uint8_t>, AbseilHashBench>. │ 3.395 ns ± 4.377% │ 294.6 M ± 4.572%
BM_LatencyHash<RandValues<uint8_t>, LLVMHashBench>... │ 6.125 ns ± 2.662% │ 163.3 M ± 2.726%
BM_LatencyHash<RandValues<uint16_t>, CarbonHashBench> │ 3.105 ns ± 3.947% │ 644.1 M ± 4.109%
BM_LatencyHash<RandValues<uint16_t>, AbseilHashBench> │ 3.433 ns ± 4.308% │ 582.6 M ± 4.502%
BM_LatencyHash<RandValues<uint16_t>, LLVMHashBench>.. │ 6.127 ns ± 2.540% │ 326.5 M ± 2.587%
BM_LatencyHash<RandValues<uint32_t>, CarbonHashBench> │ 3.082 ns ± 2.846% │ 1.298 G ± 2.923%
BM_LatencyHash<RandValues<uint32_t>, AbseilHashBench> │ 3.401 ns ± 3.611% │ 1.176 G ± 3.739%
BM_LatencyHash<RandValues<uint32_t>, LLVMHashBench>.. │ 6.209 ns ± 4.064% │ 644.3 M ± 4.236%
BM_LatencyHash<RandValues<uint64_t>, CarbonHashBench> │ 3.122 ns ± 2.871% │ 2.563 G ± 2.956%
BM_LatencyHash<RandValues<uint64_t>, AbseilHashBench> │ 3.426 ns ± 2.811% │ 2.335 G ± 2.892%
BM_LatencyHash<RandValues<uint64_t>, LLVMHashBench>.. │ 6.497 ns ± 3.081% │ 1.231 G ± 3.179%
```
For the first comparison mode on one of Carbon's benchmarks, the results
look like:
```
Computing statistically significant deltas only wherethe P-value < 𝛂 of 0.05
Metric key:
BenchmarkName... <median> ± <% at 95th conf>
vs Comparable: 👍 <delta> p=<U-test P-value>
<median> ± <% at 95th conf>
Benchmark ┃ CPU Time ┃ bytes_per_second
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━
BM_LatencyHash<RandValues<uint8_t>, CarbonHashBench>. │ 3.037 ns ± 1.781% │ 329.2 M ± 1.813%
vs Abseil: │ 👍 -8.200% p=0.000183 │ 👍 8.933% p=0.000183
│ 3.309 ns ± 2.064% │ 302.2 M ± 2.022%
vs LLVM: │ 👍 -49.401% p=0.000183 │ 👍 97.632% p=0.000183
│ 6.003 ns ± 1.502% │ 166.6 M ± 1.480%
│ │
BM_LatencyHash<RandValues<uint16_t>, CarbonHashBench> │ 3.026 ns ± 1.816% │ 661 M ± 1.784%
vs Abseil: │ 👍 -8.599% p=0.000183 │ 👍 9.408% p=0.000183
│ 3.311 ns ± 1.873% │ 604.1 M ± 1.839%
vs LLVM: │ 👍 -49.829% p=0.000183 │ 👍 99.319% p=0.000183
│ 6.031 ns ± 2.806% │ 331.6 M ± 2.730%
│ │
BM_LatencyHash<RandValues<uint32_t>, CarbonHashBench> │ 3.017 ns ± 2.696% │ 1.326 G ± 2.625%
vs Abseil: │ 👍 -9.754% p=0.000183 │ 👍 10.808% p=0.000183
│ 3.344 ns ± 1.537% │ 1.196 G ± 1.514%
vs LLVM: │ 👍 -49.857% p=0.000183 │ 👍 99.427% p=0.000183
│ 6.018 ns ± 3.269% │ 664.7 M ± 3.167%
│ │
BM_LatencyHash<RandValues<uint64_t>, CarbonHashBench> │ 3.025 ns ± 3.395% │ 2.644 G ± 3.284%
vs Abseil: │ 👍 -9.812% p=0.000183 │ 👍 10.879% p=0.000183
│ 3.354 ns ± 2.640% │ 2.385 G ± 2.572%
vs LLVM: │ 👍 0.476x p=0.000183 │ 👍 2.101x p=0.000183
│ 6.357 ns ± 2.477% │ 1.258 G ± 2.418%
│ │
```
For the second mode, in this case comparing a baseline build with `-Oz`
vs an experiment with `-Os`, the results look like:
```
Computing statistically significant deltas only wherethe P-value < 𝛂 of 0.05
Metric key:
BenchmarkName... 👍 <delta> p=<U-test P-value>
baseline: <median> ± <% at 95th conf>
experiment: <median> ± <% at 95th conf>
Benchmark ┃ CPU Time ┃ bytes_per_second
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━
BM_LatencyHash<RandValues<std::pair<uint32_t, uint32_t>>, CarbonHashBench> │ 👍 -35.870% p=0.000557 │ 👍 55.930% p=0.000557
baseline: │ 5.704 ns ± 1.877% │ 1.403 G ± 1.911%
experiment: │ 3.658 ns ± 4.209% │ 2.187 G ± 4.039%
│ │
BM_LatencyHash<RandValues<std::pair<uint32_t, uint64_t>>, CarbonHashBench> │ 👍 -19.475% p=0.00119 │ 👍 24.186% p=0.00119
baseline: │ 4.974 ns ± 3.029% │ 3.217 G ± 3.124%
experiment: │ 4.005 ns ± 4.297% │ 3.995 G ± 4.120%
│ │
BM_LatencyHash<RandValues<std::pair<uint32_t, int*>>, CarbonHashBench>.... │ 👍 -11.740% p=0.00153 │ 👍 13.302% p=0.00153
baseline: │ 4.634 ns ± 3.433% │ 3.453 G ± 3.555%
experiment: │ 4.09 ns ± 2.999% │ 3.912 G ± 2.911%
│ │
```
The script itself uses a new tool for managing dependencies called `uv`:
https://docs.astral.sh/uv/ This tool allows for the script to contain an
inline set of dependencies that will be installed and cached for
subsequent runs. This seemed particularly important as dependencies like
SciPy and NumPy can be particularly difficult to manager or keep
installed in other ways, but are essential to this scripts statistical
analysis. So far, the `uv` system has been working remarkably well for
me and been a relatively pleasant experience on the whole.
I have included as much of the Python dependencies as have good type
information into the MyPy configuration to get good type checking in
pre-commit however.
Last but not least, this has been a pet project of mine for a quite a
while and so may be a bit rough around the edges as I added and tweaked
functionality based on specific benchmarks I was looking at. It feels
like its gotten useful enough to contribute somewhere, but totally open
to any refactoring or improvements needed. I tried to take a few passes
over it to organize and document the code before sending it, but I'm
sure there are still some things that could use improvement.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
As far as I'm aware, the the devcontainers aren't in frequent use, which
is why they fall out of date. Comparing with
https://github.com/llvm/llvm-project/, I don't see devcontainer configs
maintained as part of llvm
(https://github.com/llvm/llvm-project/issues?q=devcontainer doesn't have
much either) so I think we should trim these instead of investing in
maintenance.
These configs aren't being maintained. In the docker configs, note `RUN
bazel build //explorer` is broken. Also, #5496 noted the clang version
is out of date.
Closes#5496
The version of clangd/clang-tidy on developer machines has slowly
diverged from the one on the CI builders, which is causing a slowly
increasing amount of pain as clang-tidy CI runs fail (incorrectly) over
things that a newer clangd/clang-tidy was perfectly fine with locally.
This bumps the Clang version used in the ubuntu builders to 19, which is
the most recent in Debian stable.
We use https://apt.llvm.org instead of LLVM's GitHub releases
(https://github.com/llvm/llvm-project/releases) as the former more
reliably has packages for newer Clang/LLVM versions on x64. The
community-build releases binaries on LLVM's GitHub have stopped
including Ubuntu packages that match the GitHub x64 Ubuntu workers for
some time (for at least the 18 and 19 releases).
By moving to apt.llvm.org packages we only download and install the
headers and libraries needed for development, rather than every output
of building llvm, which is much faster and saves lots of disk space. We
also remove the system installations of other versions of clang/llvm so
we should end up using negative disk space. We can no longer easily
cache the installation but apt.llvm.org is a reliable end point.
We bump the ubuntu image version for the github workers to 24.04, as
apt.llvm.org has stopped building images for 22.10 in 2022 at its end of
life.
The `pre_commit` workflow disabled sudo unlike the other workflows that
install Clang/LLVM, including the `clang-tidy` workflow (which is also
run on `pull_request`). We bring it into alignment with the other
workflows so that we can install the llvm packages. And we lock its
ubuntu image to 24.04 so that it can be moved in lockstep with the other
workflows that depend on Clang/LLVM.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
The docs explain that you must use `--local-lldbinit` in the command
line, and include an example of how to run a file_test under lldb from
the command line.
This PR includes `.lldbinit` file and `lldbinit.py` file which set up
our default options, copied from the VSCode launcher.
The instructions include settin the `max-string-summary-length`, and we
include this in the vscode launcher for lldb, as printing `Dump()`
output can easily get truncated otherwise when printing an InstBlockId.
We had a long discussion of this, so trying to document what seems to be
the conclusion... and also clean up the exceptions that I could find.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
We propose updating our milestones to accelerate design and
implementation of
memory safety in Carbon, and a roadmap for 2025 reflecting this change.
We also
provide a retrospective for 2024's progress.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Also makes the style guide explicitly comment on void, but this was the
intent IIRC because it matches Carbon's `-> ()` (and "always" versus
"except for void", which we definitely went back and forth on).
Includes adjusting function pointers, which I definitely forget this
syntax works sometimes.
Excludes utils/tree_sitter/src/scanner.c because it claims to be C, but
really we should probably fix that to be cpp.
Introduce a principle that the Carbon language should not encroach on
the
developer's namespace. Satisfy this principle by making `Core` a
keyword.
---------
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This updates to bazel 8.0.0, also updating bazel mod deps and tools to
make that function. The release is a couple weeks old, and we haven't
updated in a while, and it's a major release. Note it includes some
incompatible flag flips that this is trying to update with respect to.
I'll try generally enabling incompatible support separately.
The most visible bazel behavior change here will be the change from `~`
to `+` in repo path names. (If you're curious,
https://github.com/bazelbuild/bazel/issues/23127 indicates this fixes a
Windows performance issue)
Note that this is building on top of both the action env update in #4728
(which got me started down this path) and the proto removal in #4731
(which would add significant work to this update). Only the commit
starting at "Work towards bazel 8.0.0" is specifically part of this PR.
This restores the symlinks for the installation, but teaches the busybox
info search to look for a relative path to the busybox binary itself
before walking through symlinks. This let's it find the tree structure
when directly invoking `prefix_root/bin/carbon` or similar, either
inside of a Bazel rule or from the command line, and mirrors how we
expect the installed tree to look. This works even when Bazel resolves
the symlink target fully, and potentially to something nonsensical like
a CAS file.
In order to make a convenient Bazel target that can be used with `bazel
run //toolchain`, this adds an override to explicitly set the desired
argv[0] to use when selecting a mode for the busybox and a busybox
binary. Currently, the workaround uses an environment variable because
that required the least amount of plumbing, and seems a useful override
mechanism generally, but I'm open to other approaches.
This should allow a few things to work a bit more nicely:
- It should handle sibling symlinks like `clang++` to `clang` or
`ld.lld` to `lld`, where that symlink in turn points at the busybox.
We want to use *initial* `argv[0]` value to select the mode there.
- It avoids bouncing through Python (or other subprocesses) when
invoking the `carbon` binary in Bazel rules, which will be nice for
building the example code and benchmarking.
It does come at a cost of removing one feature: the initial symlink
can't be some unrelated alias like `my_carbon_symlink` -- we expect the
*first* argv[0] name to have the meaningful filename for selecting
a busybox mode.
It also trades the complexity of the Python script for some complexity
in the busybox search in order to look for a relative `carbon-busybox`
binary. On the whole, I think that tradeoff is worthwhile, but it isn't
free.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Pursuant to discussion regarding #4699, turn on
`misc-non-private-member-variables-in-classes` using the
`IgnoreClassesWithAllMemberVariablesBeingPublic` flag (the check treats
structs as classes, so we need this for structs with all-public
members). Updates the style guide notes to match, which should be pretty
minor due to the scoping of test fixtures.
Also fixes some underscore uses in test files on the way. Basically this
is keeping the style for [class data member
naming](https://google.github.io/styleguide/cppguide.html#Variable_Names)
even while making them public.
Proposes a set of core features for declaring and implementing generic
variadic
functions.
A "pack expansion" is a syntactic unit beginning with `...`, which is a
kind of
compile-time loop over sequences called "packs". Packs are initialized
and
referred to using "pack bindings", which are marked with the `each`
keyword at
the point of declaration and the point of use.
The syntax and behavior of a pack expansion depends on its context, and
in some
cases by a keyword following the `...`:
- In a tuple literal expression (such as a function call argument list),
`...`
iteratively evaluates its operand expression, and treats the values as
successive elements of the tuple.
- `...and` and `...or` iteratively evaluate a boolean expression,
combining
the values using `and` and `or`, and ending the loop early if the
underlying
operator short-circuits.
- In a statement context, `...` iteratively executes a statement.
- In a tuple literal pattern (such as a function parameter list), `...`
iteratively matches the elements of the scrutinee tuple. In conjunction
with
pack bindings, this enables functions to take an arbitrary number of
arguments.
---------
Co-authored-by: josh11b <josh11b@users.noreply.github.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
The only documentation I can find for `.bazelversion` is in
https://github.com/bazelbuild/bazelisk/blob/master/README.md. However,
`bazel` will error out if it doesn't match the `.bazelversion`. For
example:
```
╚╡/usr/bin/bazel build :all
ERROR: The project you're trying to build requires Bazel 7.3.0 (specified in [elided]/carbon-lang/.bazelversion), but it wasn't found in /usr/bin.
```
Switching to this because the `MODULE.bazel` requires tighter version
pinning in order to avoid churn, and this should help catch mistakes
early.
In `MODULE.bazel`, demote mention of the version issue because it should
only really occur now when the version is being deliberately changed, so
the connection should be more apparent.