You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
The conformance shim has two platform sources that its comment says are one: on the ubuntu lane, 48 linux examples never run and 23 darwin ones do #837
spec_helper.rb has two platform sources, and its own comment says it has one:
PLATFORMS=[:darwin,:bsd,:unix]# line 23 — a literal# mspec/lib/mspec/guards/platform.rb. Only the entry points the corpus reaches# are provided; PLATFORMS/WORDSIZE above stay the single source of truth so the# guard helpers and this class cannot disagree.classPlatformGuardPLATFORM=RUBY_PLATFORM# line 46 — derived
They can disagree, and on the lane that enforces the gate they do.
Proven, not inferred
internal/vm/kernel_introspect.go derives the triple from the build target:
So on the ubuntu-latest runner rbgo answers RUBY_PLATFORM == "x86_64-linux", and the two sources split:
call
reads
on ubuntu
PlatformGuard.os?(:linux)
PLATFORM.include?("linux")
true ✓
platform_is :linux
PLATFORMS.include?(:linux)
false ✗
The comment is not wrong about the intent — it is written on darwin, where PLATFORM contains darwin and PLATFORMS contains :darwin, so the two agree and the split is invisible.
What it costs, measured on the pinned corpus
2206 spec files in language/ + core/, counted by shape:
guard
guards
examples
files
the literal decides
platform_is :linux
31
≥48
23
skipped — should run
platform_is :darwin
18
≥23
12
run — should be skipped
platform_is_not :darwin
2
≥6
2
skipped — should run
platform_is_not :linux
4
≥5
4
run — should be skipped
platform_is :freebsd / :netbsd / :openbsd
29
≥43
18
skipped, though :bsdis in the literal
Examples are a lower bound: a static reader cannot expand it_behaves_like.
So on the gate's own runner, roughly 48 examples that describe Linux behaviour never execute, and 23 that describe darwin behaviour run on a Linux kernel. The _not forms invert the same error.
Why it is not visible as a failure
BASELINE was recorded through this same shim, so the gate is self-consistent: it enforces, file by file, a darwin-shaped population measured on Linux. Nothing is red. The number is simply about a different machine than the one producing it.
That also makes it a plausible contributor to the environment sensitivity BASELINE's header documents at length — the five files "measured on darwin and recorded at CI's own LOWER ubuntu value" are exactly where a platform mismatch would show up.
Suggested shape of a fix
PLATFORMS should be derived from RUBY_PLATFORM, the way PlatformGuard::PLATFORM already is, so the comment's claim becomes true. mspec itself derives it; the literal is the shim's own shortcut.
⛔ It moves the population, so it must be measured before BASELINE is regenerated — the same discipline #799 asks for, and for the same reason: UPDATE_BASELINE=1 records whatever it sees and would absorb the loss silently. The two changes interact (both select examples), so measuring them together, or one strictly after the other, is worth deciding deliberately.
Measured 2026-10-27 on corpus 87b1631 (the pinned SPEC_SHA), with a Go census of the guard shapes.
Why this is not in flight yet, and exactly what it should be when it is
PLATFORMS = [:darwin, :bsd, :unix] sits three lines below CUR_VERSION in the same file, and #845 is currently rewriting that line. Stacking a second branch on it would be stacking on a squash merge, which orphans the follower — so this waits for #845 to land rather than racing it. Recording the plan here so it is one sitting's work when the file is free.
The defect, stated precisely
spec_helper.rb carries two sources for the same fact and uses the wrong one for guards:
PLATFORM=RUBY_PLATFORM# line 46 — derived, correctPLATFORMS=[:darwin,:bsd,:unix]# line 23 — hardcoded, and what platform_is reads
So on the Linux lane — which is the lane the ratchet runs on — platform_is :linux do … end is false and its examples are removed, while platform_is :darwin is true and asserts darwin behaviour on a Linux host. Both directions are wrong on the machine that produces BASELINE.
⛔ Unlike #845, this is NOT a no-op, and that governs the PR's shape
Deriving moves the population on the Linux lane in both directions at once: :linux blocks start running (examples added, some of which may fail on first contact), :darwin blocks stop running (examples removed). UPDATE_BASELINE=1 would record the net and call it progress — the precise mistake #799 argues against.
So: move PLATFORMS, do not regenerate BASELINE, and let the ratchet name every file that shifts. A file that loses examples because a platform_is :darwin block correctly stopped running is a legitimate loss and needs recording deliberately, file by file, with a reason — not absorbed into a total.
The part that is measurable here, on darwin, today
The mapping does not need a Linux machine to be tested — only the population delta does. Extract it as a function of the platform string rather than computing it inline:
and then internal/vm/rubyspec_shim_test.go can drive it with "x86_64-linux", "arm64-darwin", "x86_64-freebsd14", "x64-mingw-ucrt" … through the existing runShim helper, on any host. That is the same seam internal/vm/kernel_introspect.go already uses for the same reason:
// It is a package var so a test can drive the Windows branch on any host: that// branch is otherwise unreachable off Windows …varrbconfigGOOS=func() string { returnruntime.GOOS }
⛔ Note what such a test does and does not prove. It proves the mapping; it says nothing about whether the specs behind those guards pass. Treating a green mapping test as evidence about the gate would be the mistake, and the two must be reported separately — the mapping in go test, the population in the ratchet's file-by-file output.
The list of families must come from mspec, not from guessing.mspec/lib/mspec/guards/platform.rb is the authority for which symbols platform_is accepts and how they relate (:unix as a family containing darwin and the BSDs, :windows excluding it). I have not opened it yet; whoever picks this up should, before writing the case above — the shape I sketched is a sketch.
Sizing it first
Before changing anything, count what moves: how many platform_is / platform_is_not sites name :linux, :darwin, :windows and the families, and how many examples sit behind each. That belongs in scripts/conformance/rubyspec/cmd/guards (#836), which already censuses ruby_version_is by shape and prints the sites rather than the totals — platform guards are the same shape of question and the same tool should answer it. #836 should merge first for that reason too.
⛔ Correcting the comment I posted above, on two counts
I said the family list "must come from mspec, not from guessing" and that my _platforms_for sketch was a sketch. I then opened mspec/lib/mspec/guards/platform.rb (at b79c65e). The sketch was wrong in kind, not in detail: mspec has no family taxonomy at all.
defself.os?(*oses)oses.any?do |os|
raise":java is not a valid OS"ifos == :javacaseoswhen:windowsthenPLATFORM =~ /(mswin|mingw)/when:wslthenwsl?elsePLATFORM.include?(os.to_s)endendend
A substring test against RUBY_PLATFORM, with :windows the only alias and :wsl the only probe. There is no list, and :unix is not a family containing linux — under mspec, platform_is :unix on "x86_64-linux" is simply false, because "x86_64-linux".include?("unix") is false. Implementing the families I sketched would have made rbgo diverge from the reference while looking more thorough than it.
So the fix is smaller and faithful: delete PLATFORMS and give platform_is/platform_is_not mspec's predicate, reading RUBY_PLATFORM directly. The shim already has PLATFORM = RUBY_PLATFORM on line 46; nothing else is needed. Confirmed safe to delete the constant: grep -rl PLATFORMS language/ core/ finds no spec that references it — it is purely internal to our shim.
And my first census was wrong, which is worth recording. I wrote the pattern platform_is_not\? *:[a-z]*, intending "platform_is with an optional _not". In a basic regex \? makes the preceding t optional, so it matches platform_is_no[t] and never plain platform_is. Every number it produced described the negative form alone, and nothing about the output said so — 247 and 219 both looked like totals. Re-run with an explicit alternation, the two forms partition the whole and the sum closes.
The census, closed
language/ + core/, corpus at the pinned 87b1631, grep -rnoE "platform_is(_not)? *:[a-z0-9_]+":
402 sites = 155 platform_is + 247 platform_is_not (and 155 + 247 = 402, which is the check that the partition is a partition).
platform_is :x
sites
platform_is_not :x
sites
:windows
95
:windows
219
:linux
32
:openbsd
9
:darwin
7
:aix
5
:aix
3
:linux
4
:netbsd
6
:freebsd
3
:freebsd
5
:netbsd
2
:openbsd
3
:mingw
2
:bsd
2
:darwin
1
:android
1
:android
1
:cygwin
1
:cygwin
1
155
247
:unix, :wasi and :wsl appear zero times in either form — so the :unix in today's hardcoded list guards nothing, and the families I was about to add would have been dead weight on top of being wrong.
What the hardcode actually gets wrong, and where
With PLATFORMS = [:darwin, :bsd, :unix], on the Linux lane that produces BASELINE:
sites
our shim
mspec
platform_is :linux
32
removed
runs
⛔ examples never reached
platform_is :darwin
7
runs
removed
⛔ asserts darwin behaviour on Linux
platform_is :bsd
2
runs
removed
⛔
platform_is_not :linux
4
runs
removed
⛔
platform_is_not :darwin
1
removed
runs
⛔ examples never reached
everything else
356
—
—
agrees
46 of 402 guard sites are answered wrongly on that lane, in both directions. The 32 :linux sites are consistent with the "≥48 examples never run" figure quoted earlier in this session — note those are different units, sites here and examples there, and only a sweep gives the second.
And on darwin, where a developer runs the suite by hand, the 2 platform_is :bsd sites run where mspec would remove them: "arm64-darwin".include?("bsd") is false. So the hardcode is wrong on both hosts, just much less so on this one.
Consequences for the PR's shape
Unchanged from the comment above: move it without regenerating BASELINE, and let the ratchet name every file that shifts. Examples will be both added (the 36 :linux sites) and removed (the 10 :darwin/:bsd ones), and a net figure would hide that.
Changed: there is no taxonomy to test, so the local test is simpler — drive mspec's predicate with "x86_64-linux", "arm64-darwin", "x64-mingw-ucrt", "x86_64-freebsd14" and assert the same answers os? gives. That still proves only the mapping, never the population; the two belong in separate reports.
This census was taken with grep and is therefore a site count that cannot see examples, cannot expand it_behaves_like, and counted one of my own patterns wrongly before I noticed. It should be re-derived by scripts/conformance/rubyspec/cmd/guards (#836) as a tested tool, with these numbers as the expected values to reproduce — if it disagrees with the table above, the table is the suspect.
Activity
tannevaled commentedon Oct 31, 2026
Why this is not in flight yet, and exactly what it should be when it is
PLATFORMS = [:darwin, :bsd, :unix]sits three lines belowCUR_VERSIONin the same file, and #845 is currently rewriting that line. Stacking a second branch on it would be stacking on a squash merge, which orphans the follower — so this waits for #845 to land rather than racing it. Recording the plan here so it is one sitting's work when the file is free.The defect, stated precisely
spec_helper.rbcarries two sources for the same fact and uses the wrong one for guards:So on the Linux lane — which is the lane the ratchet runs on —
platform_is :linux do … endis false and its examples are removed, whileplatform_is :darwinis true and asserts darwin behaviour on a Linux host. Both directions are wrong on the machine that producesBASELINE.⛔ Unlike #845, this is NOT a no-op, and that governs the PR's shape
Deriving moves the population on the Linux lane in both directions at once:
:linuxblocks start running (examples added, some of which may fail on first contact),:darwinblocks stop running (examples removed).UPDATE_BASELINE=1would record the net and call it progress — the precise mistake #799 argues against.So: move
PLATFORMS, do not regenerateBASELINE, and let the ratchet name every file that shifts. A file that loses examples because aplatform_is :darwinblock correctly stopped running is a legitimate loss and needs recording deliberately, file by file, with a reason — not absorbed into a total.The part that is measurable here, on darwin, today
The mapping does not need a Linux machine to be tested — only the population delta does. Extract it as a function of the platform string rather than computing it inline:
and then
internal/vm/rubyspec_shim_test.gocan drive it with"x86_64-linux","arm64-darwin","x86_64-freebsd14","x64-mingw-ucrt"… through the existingrunShimhelper, on any host. That is the same seaminternal/vm/kernel_introspect.goalready uses for the same reason:⛔ Note what such a test does and does not prove. It proves the mapping; it says nothing about whether the specs behind those guards pass. Treating a green mapping test as evidence about the gate would be the mistake, and the two must be reported separately — the mapping in
go test, the population in the ratchet's file-by-file output.The list of families must come from mspec, not from guessing.
mspec/lib/mspec/guards/platform.rbis the authority for which symbolsplatform_isaccepts and how they relate (:unixas a family containing darwin and the BSDs,:windowsexcluding it). I have not opened it yet; whoever picks this up should, before writing thecaseabove — the shape I sketched is a sketch.Sizing it first
Before changing anything, count what moves: how many
platform_is/platform_is_notsites name:linux,:darwin,:windowsand the families, and how many examples sit behind each. That belongs inscripts/conformance/rubyspec/cmd/guards(#836), which already censusesruby_version_isby shape and prints the sites rather than the totals — platform guards are the same shape of question and the same tool should answer it. #836 should merge first for that reason too.🤖 Generated with Claude Code
tannevaled commentedon Oct 31, 2026
⛔ Correcting the comment I posted above, on two counts
I said the family list "must come from mspec, not from guessing" and that my
_platforms_forsketch was a sketch. I then openedmspec/lib/mspec/guards/platform.rb(atb79c65e). The sketch was wrong in kind, not in detail: mspec has no family taxonomy at all.A substring test against
RUBY_PLATFORM, with:windowsthe only alias and:wslthe only probe. There is no list, and:unixis not a family containing linux — under mspec,platform_is :unixon"x86_64-linux"is simply false, because"x86_64-linux".include?("unix")is false. Implementing the families I sketched would have made rbgo diverge from the reference while looking more thorough than it.So the fix is smaller and faithful: delete
PLATFORMSand giveplatform_is/platform_is_notmspec's predicate, readingRUBY_PLATFORMdirectly. The shim already hasPLATFORM = RUBY_PLATFORMon line 46; nothing else is needed. Confirmed safe to delete the constant:grep -rl PLATFORMS language/ core/finds no spec that references it — it is purely internal to our shim.And my first census was wrong, which is worth recording. I wrote the pattern
platform_is_not\? *:[a-z]*, intending "platform_iswith an optional_not". In a basic regex\?makes the precedingtoptional, so it matchesplatform_is_no[t]and never plainplatform_is. Every number it produced described the negative form alone, and nothing about the output said so — 247 and 219 both looked like totals. Re-run with an explicit alternation, the two forms partition the whole and the sum closes.The census, closed
language/+core/, corpus at the pinned87b1631,grep -rnoE "platform_is(_not)? *:[a-z0-9_]+":402 sites = 155
platform_is+ 247platform_is_not(and 155 + 247 = 402, which is the check that the partition is a partition).platform_is :xplatform_is_not :x:windows:windows:linux:openbsd:darwin:aix:aix:linux:netbsd:freebsd:freebsd:netbsd:openbsd:mingw:bsd:darwin:android:android:cygwin:cygwin:unix,:wasiand:wslappear zero times in either form — so the:unixin today's hardcoded list guards nothing, and the families I was about to add would have been dead weight on top of being wrong.What the hardcode actually gets wrong, and where
With
PLATFORMS = [:darwin, :bsd, :unix], on the Linux lane that producesBASELINE:platform_is :linuxplatform_is :darwinplatform_is :bsdplatform_is_not :linuxplatform_is_not :darwin46 of 402 guard sites are answered wrongly on that lane, in both directions. The 32
:linuxsites are consistent with the "≥48 examples never run" figure quoted earlier in this session — note those are different units, sites here and examples there, and only a sweep gives the second.And on darwin, where a developer runs the suite by hand, the 2
platform_is :bsdsites run where mspec would remove them:"arm64-darwin".include?("bsd")is false. So the hardcode is wrong on both hosts, just much less so on this one.Consequences for the PR's shape
Unchanged from the comment above: move it without regenerating
BASELINE, and let the ratchet name every file that shifts. Examples will be both added (the 36:linuxsites) and removed (the 10:darwin/:bsdones), and a net figure would hide that.Changed: there is no taxonomy to test, so the local test is simpler — drive mspec's predicate with
"x86_64-linux","arm64-darwin","x64-mingw-ucrt","x86_64-freebsd14"and assert the same answersos?gives. That still proves only the mapping, never the population; the two belong in separate reports.This census was taken with
grepand is therefore a site count that cannot see examples, cannot expandit_behaves_like, and counted one of my own patterns wrongly before I noticed. It should be re-derived byscripts/conformance/rubyspec/cmd/guards(#836) as a tested tool, with these numbers as the expected values to reproduce — if it disagrees with the table above, the table is the suspect.🤖 Generated with Claude Code
conformance: derive CUR_VERSION from RUBY_VERSION — one fact, one pla…