Measured 2026-09-10
compiler 546d4dcbd305, tree 08d8d5170
traffic.py Segmentation fault (core dumped) rc=139
vessel.py Segmentation fault (core dumped) rc=139
pinned v407 traffic.py rc=1 (ordinary error)
42 dispatching on the receiver at run time warnings in each before the crash,
on .water_height(), .current(), .depth(), .bed_height(), .wind(), plus
one several unrelated classes declare a .up property — reading it through the receiver at run time.
Why it only became visible now
These two modules were blocked at math.atan2 until 0838c1be3. Clearing that
wall let them compile far enough to reach this, which is the first-wall mechanism
delivering a CRASH instead of the expected next refusal. Four null rows taught
us to expect a new wall; none of them predicted the new wall would be a
segfault.
The open-world dispatch work is the obvious suspect given the 42 warnings
immediately preceding, and that is a suspicion, not a bisect. Not attributed
to a commit: the range between v407 and 08d8d5170 contains several seats' work,
and CLAUDE.md is explicit that a tier or census delta gets attributed to a RANGE
before it gets attributed to anyone. frankZ holds dispatch and should look first,
but the honest next step is git bisect over that range, not a reading.
THE INSTRUMENT FAILED TOO, AND THAT IS WORTH ITS OWN LINE
The census that found this reported both rows as FAIL <module> :: with an
empty reason, because the harness did grep -m1 'error' on the log and a
segfault writes no error: line — the log holds 42 warnings and then stops. So a
crash rendered as the least alarming row in the output, less informative than
every ordinary refusal beside it.
A harness that extracts a reason by matching a word cannot report a failure
that produces no words. The fix is to branch on the exit code first and only
then look for text — rc=139 is unmistakable and needs no parsing. Any census
over this corpus should do the same, and the two empty rows were nearly read as
an uninteresting formatting glitch.
Scope honesty
Not minimised. Both reproducers are real 600-line application modules, so the first job is to shrink one — the 42 warning sites are the obvious place to start cutting, and the shared-import hypothesis predicts that a single site in a COMMON dependency will reproduce it alone.
RE-MEASURED 2026-09-14 — it does not reproduce
Tree 6d059b47f, compiler built at that tree, three runs per module, from the
owner's checkout (/home/neo/lekkerzeilen, read-only):
traffic.py rc=0 rc=0 rc=0 60 `dispatching on the receiver at run time`
vessel.py rc=0 rc=0 rc=0 42 `dispatching on the receiver at run time`
No segfault, no core, and both modules now reach a binary.
The 42/42 coincidence was not a fan-in tell, and it is worth saying which way
The original summary read the identical 42 warnings across two unrelated modules
as evidence of ONE crash site reached through a shared import — the same
reasoning that correctly collapsed five *-unpacking rows into three. At HEAD
the counts are 60 and 42. They diverge, so the modules were never sharing a
site and the inference was wrong. It was a reasonable read and the discriminator
was always cheap; nobody ran it while the ticket was open because the crash made
the warning counts look like scenery.
What is NOT established
Which commit fixed it. Four nights of Track N receiver-dispatch work sit
between the report and now. On shape alone the candidate is
189259975 fix(N): a class-reference receiver no longer walks RTTI off a non-instance — a receiver-dispatch crash walking RTTI off something that is not
an instance is exactly what 42 dispatch warnings followed by a silent SIGSEGV
looks like. That is a hypothesis, not a measurement. What would settle it:
build at 189259975^ and at 189259975 and run traffic.py against each. Two
self-host builds, and nobody has spent them.
The residual question therefore has an owner named here rather than being left implied: anyone who sees an rc=139 from this shape again should start at that pair of builds rather than re-deriving the ticket.