Janus hardens the substrate: storage replay, atomics, and build cache
Junior Dev Nugget; principle: Real systems work turns type-system promises into storage, replay, cache, and ABI pressure. That pressure is where decorative features either become machinery or break.; likely mistake: Thinking a language feature is done when the syntax parses or the happy-path test passes. The real proof starts when storage recovery, generics, optional payloads, and cross-module boundaries all touch it at once.; read next: The public Janus material on storage, effects, capabilities, and the eight axes of provability.
What changed
Janus shipped another heavy trench wave.
The headline is not one isolated feature. The headline is that several deep layers moved at once:
-
Byte-keyed storage moved from substrate toward recovery. The storage layer now has a byte-keyed path for the log-structured engine, a copying read helper for decoded values, a storage facade for the truth-layer work, and early replay machinery for variable-length records. The path is no longer just “can we write bytes?” It is now “can we reopen and recover them without lying?”
-
Atomics crossed from doctrine into lowering. The compiler gained ordering validation, atomic operation representation, lowering nodes, LLVM emission for atomic operations and fences, and end-to-end smoke coverage. That matters because concurrency semantics cannot remain commentary. They have to survive into the generated program.
-
The build system became infrastructure. Janus now has a real cache story: XDG cache placement, startup cleanup, free-space guardrails, cache inspection commands, object-cache hardening, and cached assembly/object artifacts. This is not glamorous. Good. Toolchains become serious when repeated builds stop behaving like ritual punishment.
-
Storage pressure exposed and closed compiler lies. Cross-module constants used in array sizes, qualified field types, optional slice wrapping, and generic slice payloads all surfaced as load-bearing edges. Some were closed. One important generic-slice path remains an active dragon.
The pattern is healthy: storage forced the compiler to prove that its type facts survive real program shapes.
Why this now
Toy compilers die in examples. Real compilers are found in the reopen path.
A storage engine does not care whether a feature looked elegant in isolation. It forces the language to answer ugly questions:
- Does this cross-module constant still mean the same thing inside an array declaration?
- Does this qualified field type survive layout encoding?
- Does this optional slice still carry both pointer and length after wrapping and unwrapping?
- Does a generic field with a slice payload keep its shape when loaded through a heap node?
- Does a replay buffer survive restart instead of depending on lucky stack lifetime?
- Does the build cache know enough about the compiler and target to be safe?
This is the phase where Janus earns trust the hard way.
Design decisions and tradeoffs
-
Chosen path: make storage drive compiler hardening. The LSM path is doing what good systems code does: it creates real pressure on generics, slices, optionals, cross-module names, and ABI lowering.
-
Chosen path: treat atomics as compiler semantics, not library folklore. Ordering, operation metadata, address lowering, and emitted fences belong in the compiler pipeline, not in a wishful comment above a function.
-
Chosen path: invest in build-cache plumbing. Fast feedback is not luxury. It is how a small team keeps enough iteration pressure on a large compiler without bleeding hours into repeated rebuilds.
-
Chosen path: keep public reporting focused on lessons. The public does not need internal coordinates. It needs to know what class of engineering truth was forced into the open.
-
Open risk: generic containers carrying slice values are still a dangerous edge. One active bug shows a slice payload can keep a plausible length while the pointer goes rotten when loaded through a generic node. That is exactly the kind of bug that deserves zero romance and immediate pressure.
The Junior Dev Nugget
- The principle being demonstrated: real features are verified at the hostile boundary, not the demo boundary.
- The mistake the reader would have made: testing a generic container with integers, declaring victory, and then being shocked when byte slices expose a different ABI shape.
- What to read or look at next: compare a scalar payload path with a slice payload path. Ask where pointer, length, optional tag, and generic field layout are represented at each compiler stage.
A scalar test can prove the hallway exists. A slice test proves whether the hallway is wide enough to carry furniture.
Ideological stance, grounded
Sovereign software is not software that sounds independent. It is software whose hidden dependencies are dragged into daylight.
Storage does that. Atomics do that. Build systems do that. They are rude teachers. They do not care about slogans.
The lesson from this wave is simple: a language that wants to be a sovereign stack must preserve facts across boundaries. Source boundary. Module boundary. Generic boundary. Optional boundary. ABI boundary. Cache boundary. Recovery boundary.
Every boundary that erases truth becomes a future outage.
Janus is still fighting dragons. Good. The important part is that the dragons are now concrete enough to name, isolate, and kill.
References
- Public Janus documentation on storage and the standard library direction.
- Public Janus material on effects, capabilities, and the eight axes of provability.
- Public Janus devlog archive.
What comes next
The next useful pressure points are clear:
- finish the remaining generic-slice payload bug in the byte-keyed storage path;
- keep replay and recovery tests moving until the storage engine survives boring restart scenarios;
- extend atomics from smoke coverage toward realistic concurrent surfaces;
- keep the build cache honest by treating cache keys as part of compiler correctness, not mere convenience.
That is a satisfying night: fewer slogans, more machinery.