Anton asked me to start a discussion from the end of #12748, which Claude found and fixed for me. The bug was a compile-time constant (a record holding an empty list with spare capacity) that reached StaticInitializerMachine.evalLowLevel with an op it didn't expect. A debug compiler panics there with a clear message ("non-construction low-level operation reached static initializer materialization"). The release compiler doesn't, because base.invariant is unreachable in optimized builds, as design.md specifies. So the nightly quietly emitted a list pointing into read-only memory, and the user's roc test died with a SIGSEGV that looked like a bug in their own program.
The invariant policy is sound in general: no runtime checks in hot paths, no fallbacks, no silent repair. But on cold paths like the static initializer, which run once per constant at compile time, keeping the check would cost essentially nothing. It would also turn a mysterious segfault into "compiler bug: (invariant), please report", which is the most useful bug report we could get from users of the nightlies. That wouldn't be a fallback or a repair. It's still a crash, just a loud one with a message.
So the question is whether it's worth having a second kind of invariant that stays checked in release builds, for compile-time paths where performance doesn't matter, or perhaps shipping the nightlies with safety on. Or is there a reason the unreachable matters even there that I'm missing?
More details here: http://143.244.172.148:9100/notes/roc-static-data-and-12748.md
The original compiler bug (fixed now, thanks for merging and improving the PR, Anton) surfaced in "real" code. It was agent-written code, and it was doing something mildly janky. We since fixed our code to use a cleaner approach even with the compiler fixed. But it seems plausible that other folks could encounter similar bugs.
As I mention in the PR, the good news is that we hunted for similar bugs and found 8 different places in the code that seemed like they could surface similar bugs, and they were all sound. But I still stand by the reasoning above.
If Richard Feldman agrees with the recommendation, I am happy to send a PR. This should be in Claude's wheelhouse, and I understand the issue well enough to make sure any proposed fix seems somewhat reasonable.
I don't want to change the policy
in general, my thinking on this is that if we start doing this, no matter how bug-free the compiler (eventually) becomes, it will always end up falling short of the build times it could deliver, because we have checks that exist solely for the purpose of "but what if there's a bug in the compiler?"
over time, successful compilers consistently get to a point where compilation bugs are super rare - which is why "it's never a bug in the compiler" is a meme, even though of course it still very occasionally is the problem
Yup, makes sense. The good news here is that the symptom, while not perfect, was clear enough.
so the value of defensive checks decreases over time, relative to what they cost on every build
Last updated: Nov 04 2026 at 18:54 UTC