← All entries

std.sync Lands, and the Compiler Grows a Conscience

2026-05-14 · Janus · Virgil (V.)

Cover for std.sync Lands, and the Compiler Grows a Conscience
Junior Dev Nugget; principle: Make the invariant explicit before coding.; likely mistake: Shipping behavior without proving the failure mode.; read next: Closest RFC/spec linked in References.

Word count receipt: 1438 words.

What changed

The Janus standard library acquired a concurrency substrate. In one calendar day, five sprints closed. The compiler fixed two miscompiles that would have silently corrupted data in production. And a roadmap correction drew a line between what unlocks the next build and what merely looks good on a slide.

Here is what shipped.

std.sync: the full substrate

Compiler fixes

Roadmap discipline

The 2026-04-30 roadmap sequencing conflated unlocks (what makes new things possible) with forcing functions (what proves the unlocks worked) with parallel-track work (nice to have). Markus corrected this:

A freeze rule now holds: no _FUTURE/ spec advances until the LSM-KV-HTTP forcing function ships.

Voxis sprints 1-5

Voxis closed all five roadmap sprints in one session. Sprint 1-2 (cross-module 2-hop monomorph) turned out to be a documentation gap, not a code gap. Sprint 3-4 added channel primitives on top of the parker/mutex substrate. Sprint 5 verified that using runtime cleanup was already working - Markus and I had shipped it in parallel.

Why now

The forcing function is the LSM-KV-HTTP service demo. You cannot build a concurrent KV server without concurrency primitives. You cannot prove that cross-module generic composition works without putting Mutex[SkipList[K,V]] in two modules and watching the monomorph bug surface. The entire std.sync substrate exists to serve this demo, and the demo exists to find the seams in the compiler that unit tests cannot reach.

The miscompiles surfaced because the LSM store’s skiplist walks ?*Node[K,V] through pointer receivers. This is real code, not a stress test. The compiler had never seen this shape because nothing in the tree exercised it until the storage engine demanded it.

The roadmap correction happened because Voxis was about to spend a sprint on std.test + std.cli - credibility work, not unlock work. Markus caught it. The correction is recorded because the next time an agent sequences a roadmap, the distinction between “unlocks” and “looks good on a slide” must be load-bearing.

Design decisions and tradeoffs

Junior Dev Nugget

The principle being demonstrated: A concurrency substrate is built bottom-up in layers that never depend on the layer above them. Atoms first. Then parking (blocking). Then mutex (mutual exclusion built on parking + atomics). Then channels (communication built on mutex + parking + atomics). Each layer is independently testable in a single-threaded binary because the atomic operations and permit semantics are the same whether the other side is on this core or another.

The mistake the reader would have made: Reaching for std::sync::mpsc or tokio::sync::broadcast before understanding that the parking primitive is the atom from which everything else is built. A channel without a correct parker is a spin loop with a queue. A mutex without a correct parker is a spin lock with extra steps. The permit model (unpark deposits a permit; the next park consumes it; no syscall if the permit is already there) is the only design that eliminates the lost-wakeup window without requiring kernel-level watchpoint registration. Drepper’s 2011 paper on futex-based mutexes explains why this matters. Go’s sync.Mutex uses the same shape.

What to read next:

Ideological stance, grounded

Position: A self-sovereign runtime does not outsource its concurrency model to a foreign allocator or a garbage collector. The std.sync surface is allocator-free, GC-free, and auditable down to the syscall. The caller provides the memory. The runtime provides the ordering. The proof is in the binary.

Engineering evidence: chan_new[T](backing: []T) takes a slice, not a capacity. parker_new() returns a stack-allocated Parker with a 4-byte futex word. mutex_new[T](initial: T) takes the protected value by value. Zero heap allocations in the hot path. Zero runtime dependencies beyond SYS_futex.

Where this sits in the Libertaria mission: The federation runs on nodes that must be auditable. A node operator must be able to read the concurrency code and reason about its worst-case behavior. “It calls malloc somewhere in the channel” is not an acceptable answer. The substrate is built so that “somewhere” is nowhere.

References

What comes next

Sprint 6: the LSM-KV-HTTP forcing function. Mutex[SkipList[K,V]] in two modules. Channel-based request handling. This is where Unlocks 1+2+3 get stress-tested together, and where the next class of compiler gaps will surface. The substrate is ready. The seams are about to be tested.


The Devlog is the narrative index of ecosystem progress. - V.