Skip to content

fix: build within the declared support range and watch above it - #21

Merged
skipbit merged 4 commits into
mainfrom
fix/split-string-view-and-clang-watch-target
Aug 11, 2026
Merged

fix: build within the declared support range and watch above it#21
skipbit merged 4 commits into
mainfrom
fix/split-string-view-and-clang-watch-target

Conversation

@skipbit

@skipbit skipbit commented Aug 11, 2026

Copy link
Copy Markdown
Owner

The nightly Clang watch has failed every night since it was added, always in the same place: on
Clang paired with libstdc++ 14, s | std::views::split(delimiter) in split() does not compile.

That combination is inside the declared support range, not outside it. The Linux requirements line
names compilers and standard libraries and says nothing about distributions, so "Clang 20–22 with
either libstdc++ or libc++" covers it. The red job was reporting a real breakage in what this
library promises, and it is also the route a user on an older Ubuntu is pointed at when the
distribution's own Clang is too old.

split() takes std::string_view

split() neither owns nor outlives its arguments and returns owning strings, so string_view is
what the signature should have said. Callers passing string literals no longer construct a temporary
std::string per argument.

This is a breaking API change, recorded in the changelog: a caller passing a type that converts
implicitly to std::string but not to std::string_view no longer compiles. There are no tags or
releases yet, and every call site in the tree passes a string literal.

The function body is unchanged. join() is left alone — its implementation concatenates with
operator+ between a std::string and the delimiter, which for a string_view delimiter would
need C++26.

The public header now includes <string> and <string_view> directly instead of relying on them
arriving transitively through <dross/type/string.h>.

The watch now looks above the declared range, and says so when it cannot

The job installed the newest versioned Clang from the suite the upstream install script adds, and
that is the release the required gates already build — so on the Clang axis it was watching nothing
the verified range did not already cover. It now watches the smallest suffixed suite above the
declared upper bound: the release most likely to enter the range next, so its evidence exists at the
moment that decision is made. Taking the largest available suite instead would skip past it. The
version is pinned rather than discovered, so it moves in the same commit as the declared range and
stays visible in the diff. The unsuffixed development suite is never watched: -Werror is public
here, so a newly added upstream diagnostic would turn a healthy build red.

The apt source line is composed directly rather than by fetching and running the upstream install
script as root, and the codename comes from /etc/os-release rather than being written in.

A release that has not been branched yet is a notice and a skip, not a failure. But the same 404 that
means "not branched yet" also appears when the index moves or is recompressed, and when the floating
runner label moves to a codename apt.llvm.org does not carry — and in those cases a green run means
the watch is dead rather than idle, which is worse than one that fails. On a 404 the job asks two
further questions, only on that path: whether the suite's own release file is served (it is — so the
index moved), and whether the codename is carried at all. Each answer is judged strictly as 200 or
404; anything else is evidence of neither and fails the job on its own. The run skips only when the
release is genuinely absent from a codename that is served. The same reasoning applies one level
down: if the pinned version is missing from the index but the index has no clang- entries
whatsoever, the naming this job searches for has itself moved, and that fails rather than skipping.

The requirements said the matrix verified more than it does

All three places that publish the support range said, or implied, that the build matrix verifies
every combination in the declared range. It does not: every required Clang job runs on Ubuntu 26.04,
so Clang against the older libstdc++ releases available on Ubuntu 24.04 is not built by any required
job, and neither GCC 14 nor Clang 21 has a required job of its own. The getting-started guide said
outright that "the build matrix verifies each of them".

Each document now notes which in-range combinations are not yet covered, keeping two groups apart.
Clang against the older libstdc++ on Ubuntu 24.04 is a gap to close, so the note says verification is
to be added. GCC 14 and Clang 21 are the middle of ranges whose ends are what CI verifies; they are
recorded as declared and unbuilt, with no promise of jobs that nothing plans to add.

The declared ranges themselves are unchanged — this records the gap rather than narrowing what is
promised.

Retargeting the watch also made a neighbouring sentence stale: two of the documents described newer
versions in general as exercised by the nightly watch, which is no longer what it does. They now
describe what each half of that job actually tracks.

Verification

Built and tested with GCC 13 against libstdc++ 13; the existing nine split cases pass unmodified,
as does the rest of the suite. The header was also syntax-checked on its own.

Clang with libstdc++ 14 — the pairing the nightly has been failing on — could not be reproduced
locally, so this change has not been shown to fix that build here. The nightly run after this merges
is the first real evidence either way.

…atch

split() neither owns nor outlives its arguments and returns owning strings,
so string_view is what the signature should have said. Callers passing string
literals no longer construct a temporary std::string per argument. With the
previous parameter types the body's `s | std::views::split(delimiter)` also
failed to compile on compiler and standard library pairings the declared range
promises, which is what the nightly watch has been reporting since it was
added. The body itself is unchanged; what reaches it is not.

This is a breaking API change: a caller passing a type that converts
implicitly to std::string but not to std::string_view no longer compiles.
There are no tags or releases yet, and every call site in the tree passes a
string literal or a pointer to one.

Declare <string> and <string_view> in the public header instead of relying on
them being visible transitively through <dross/type/string.h>.

The watch job installed the newest versioned Clang from the suite the upstream
install script adds, and that is the release the required gates already build,
so on the Clang axis it was watching nothing the verified range did not
already cover. Point it at the smallest suffixed suite above the declared
upper bound — the release most likely to enter the range next, so its evidence
exists when that decision is made. Taking the largest available suite instead
would skip past it. The version is pinned so it moves in the same commit as
the declared range, the suite codename is read from the runner rather than
written as a literal, and a release that is not published yet produces a
notice and a skip rather than a failure. The unsuffixed development suite is
never watched: -Werror is public here, so a newly added diagnostic would turn
a healthy build red.

The three documents that publish the support range present it as a flat list,
and two of them say outright that CI verifies it. It does not: no required job builds Clang
against the older libstdc++ releases available on Ubuntu 24.04, and neither
GCC 14 nor Clang 21 has a required job. Say so in all three, provisionally,
without changing the declared range itself.
A 404 on the watched suite's package index was read as "not branched yet"
whatever caused it. That is right for one cause and wrong for two others: if
apt.llvm.org moves or recompresses the index, or if the floating runner label
moves to a codename apt.llvm.org does not carry, the job reports the same
notice and goes green having built nothing. A watch that is dead but green
every night is worse than one that fails, and the GCC job next to it already
fails loudly when its upstream query comes back empty.

Ask two more questions, but only on the 404 path, so the ordinary run costs no
extra requests. If the suite's release file is served while its index is not,
upstream changed where or how the index is published and this job cannot
follow that silently. If the codename's own unsuffixed suite is absent, the
codename is not carried at all. Only when the suite is genuinely absent from a
codename that is served does the run skip with a notice. The unsuffixed suite
is read here purely as a codename oracle that does not depend on any version;
it is still never built from.

Separate "no match" from "grep could not run" when searching the index, for
the same reason: both used to end in a quiet skip. Keep the decompressed index
as a real file rather than piping it into grep — grep exits on the first match,
gunzip dies of SIGPIPE, and pipefail would then report a published compiler as
missing.

Pin the redirect protocol on the key fetch, so "upstream will not send us to
http" stops being an assumption, and record next to the keyring why the key
must stay scoped to this one source: the signature check during apt-get update
is what authenticates anything here, not the index probe above it.

Name the job for what it watches, and say in the notice what was actually
observed rather than asserting there is nothing above the declared range.

Restore the header's description of both jobs: each takes a compiler from
outside the distribution's own repositories, which was true of the GCC job
before this and still is.

In the requirements notes, drop two phrasings that stated more than is
measured. Which libstdc++ a Clang driver selects is derived from its search
for a GCC installation rather than measured here, and Ubuntu 24.04 does not
install libstdc++ 14 by default. Close the truncated sentence in the readme.
The two follow-up probes decided by asking whether the response was 200, and
treated everything else as its absence. A 5xx or a 403 from the suite's release
file is not evidence that the suite is unbranched, yet it flowed on toward the
notice-and-skip and the run ended green. Judge each strictly: 200 and 404 mean
what they say, and anything else fails the job on its own rather than being
read as one of them.

The same gap existed one level down. When the pinned version is not listed in
the package index, that reads as "not published yet" only if the index lists
clang packages under that name at all. If it contains no such entry whatsoever,
the naming this job searches for has itself moved, which is the same kind of
stale assumption a bare 404 was hiding. The index is already on disk, so
checking costs nothing.

Say what was observed before naming a cause, in the two messages that did not.
The skip notice now allows that the release may not have been branched yet
rather than declaring it, matching the hedging the failure messages already
used.

Give the main index probe the retry the two it spawns already had — it runs
every night and is the one most exposed to a transient blip.

The header claimed these jobs take compilers above what the required gates
verify. That holds for the Clang job, whose version is pinned above the
declared range, but the GCC job takes the newest versioned g++ apt can see
once the PPA is in place, and never compares it against anything. Say what
each job actually does.

In the requirements notes, separate the two groups that were sharing one
sentence. Clang against the older libstdc++ releases on Ubuntu 24.04 is a gap
to close, so saying verification is to be added is right. GCC 14 and Clang 21
are the middle of declared ranges whose ends are what CI verifies; they are
declared and unbuilt, and promising jobs for them commits to something nothing
plans to do — and would leave the note impossible to withdraw honestly.

Retargeting the watch also made the neighbouring sentence stale: it still
described newer versions in general as exercised by the nightly watch, when
the watch now covers one release above the range and deliberately skips the
development snapshot. Describe what each half of it actually tracks.

Note why the index path hardcodes an architecture, and break the changelog entry
across lines rather than leaving it far longer than any other entry in its list.
…omes from

Three places said the watch tracks the newest g++ the toolchain PPA offers.
The job adds the PPA and then takes the highest versioned g++ apt can see
across every configured source; the PPA is what makes a newer one available,
but the value is not necessarily from it. The accurate phrasing was already
in this file, above the install step — the loose one sat in the header and in
two of the requirements documents, describing the same mechanism two ways.

Narrow the removal promise to the sentence it belongs to. Splitting the
caveat left "this note will be removed" reading as though it governed the
whole thing, including the sentence about GCC 14 and Clang 21, which is not
going anywhere. The getting started guide already said the paragraph would be
trimmed, which is the right shape when only part of it goes.
@skipbit
skipbit merged commit 854c3e6 into main Aug 11, 2026
27 checks passed
@skipbit
skipbit deleted the fix/split-string-view-and-clang-watch-target branch August 11, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant