Sovereign Systems: Beyond Rust & Zig
Sovereign Systems: Beyond Rust & Zig
Section titled “Sovereign Systems: Beyond Rust & Zig”“The compiler doesn’t stop at the software boundary. It reaches through to the hardware and pulls the truth back up into the type system.”
Every systems language promises control. C gives you the machine and hopes you survive. Rust gives you a borrow checker and calls it safety. Zig gives you explicit everything and washes its hands at the hardware boundary.
Janus :sovereign does something none of them dare: it makes hardware safety a compile-time property.
Not a library. Not a convention. Not a runtime check that fires too late. A type error — caught before the binary is emitted.
The Bare-Metal Graveyard
Section titled “The Bare-Metal Graveyard”Before we build, let’s bury the myths. Rust and Zig are excellent languages. They are also fundamentally incomplete for the domains where failure means dead satellites, crashed rovers, and corrupted flight controllers.
Where Rust Breaks
Section titled “Where Rust Breaks”no_std is a lie of omission. Strip out the standard library and what remains is a language that still assumes a heap allocator exists somewhere. Box, Vec, String – the entire ownership model’s ergonomics collapse without alloc. You’re left writing C-with-lifetimes.
Panic infrastructure is a landmine. In space, panic!() means a dead satellite. Rust’s answer? #[panic_handler] – a single global function you wire up yourself. No structured recovery. No per-subsystem isolation. One panic path for the entire firmware.
MMIO is unsafe soup. Every register access is unsafe. Every DMA buffer is unsafe. Every interrupt handler is unsafe. When 80% of your bare-metal code is unsafe, the borrow checker isn’t protecting you – it’s just making you type more. The safety model evaporates exactly where you need it most.
No deterministic execution guarantees. Rust’s iterators, closures, and trait dispatch can introduce non-obvious allocations and unpredictable codegen. For hard real-time – satellite attitude control loops at 100Hz – you need proof that a function completes in N cycles. Rust gives you nothing.
Where Zig Breaks
Section titled “Where Zig Breaks”Zig is honest about the machine but silent about intent. @intToPtr and @ptrToInt are clean, but there’s no semantic difference between “this is a hardware register at 0x4000_1000” and “this is a random pointer cast.” The compiler can’t help you because it can’t see what you meant.
No radiation hardening at the language level. Zig’s comptime is powerful, but it doesn’t know about bit-flips. Single Event Upsets corrupt memory in space. Zig treats memory as reliable. On a satellite, that assumption kills.
Allocator model is beautiful but incomplete. Zig forces explicit allocators – brilliant for desktop, but in bare-metal you often need zero dynamic allocation, ever. Zig doesn’t enforce this; it just makes it possible. “Possible” isn’t “proven.”
No formal link between hardware and safety. Zig’s packed struct maps registers, but there’s no capability model saying “this peripheral is owned by this subsystem and only this subsystem.” You enforce that by convention. Convention doesn’t survive a 3 AM debugging session on a flight model.
Stack Safety: The Three Walls
Section titled “Stack Safety: The Three Walls”Stack overflow is the most common silent killer in systems programming. Every language treats it as a runtime problem. Janus treats it as a compile-time property.
Wall 1: Compile-Time Stack Budget Analysis
Section titled “Wall 1: Compile-Time Stack Budget Analysis”// :sovereign profile — pledge-based stack budgetsfunc deep_recursion(n: u32) !u32 pledge stack(4096) // Compiler enforces: this call chain uses <= 4KBdo if n == 0 do return 1 end return deep_recursion(n - 1)? // Compiler: "unbounded recursion — pledge violated"endThe compiler statically analyzes call graphs and rejects programs that might exceed their pledge. No runtime check needed – the violation is caught before the binary is emitted.
Wall 2: Capability-Gated Guard Pages
Section titled “Wall 2: Capability-Gated Guard Pages”// A fiber's stack is a capability — bounded, revocable, delegablefiber spawn("worker", capabilities: [ stack(size: 64KB, guard: true), // Guard page is a first-class concept memory(heap: 1MB), channel(#sys_log, perms: .write_only),])The language knows guard pages exist. The compiler emits the guard_register call. The runtime never forgets to set one up.
Wall 3: Software Canary (Opt-In)
Section titled “Wall 3: Software Canary (Opt-In)”@canary // Emits a per-frame random canary checkfunc parse_untrusted_input(buf: []u8) !Parsed do // Security-critical code gets defense-in-depthendThe Full Picture
Section titled “The Full Picture”| Layer | Mechanism | Cost | Catches |
|---|---|---|---|
| Compile-time | pledge stack(N) analysis | Zero | Statically provable overflows |
| Guard page | MMU-enforced hardware trap | Zero | Overflows that escape static analysis |
| Software canary | Optional @canary per-function | ~2 instructions | Intra-page corruption (buffer overwrite within the same page) |
No other language offers all three simultaneously. Rust panics on overflow in debug or silently corrupts in release. Zig disables stack probing in freestanding mode. C relies on -fstack-protector, which adds overhead to every function.
Janus :sovereign is the first language where stack safety is a compile-time-verifiable, hardware-enforced, capability-gated property.
The Sovereign Arsenal
Section titled “The Sovereign Arsenal”Every feature below maps to a real failure mode that has killed actual missions.
1. MMIO as First-Class Typed Peripherals
Section titled “1. MMIO as First-Class Typed Peripherals”// The register map IS the type. Not a wrapper. Not unsafe. The type.peripheral UART0 at 0x4000_1000 register CR: u32 field TXEN: bit[0] = .disabled // Reset value is part of the type field RXEN: bit[1] = .disabled field BAUD: bits[2..5] end
register DR: u32 field DATA: bits[0..7] field FERR: bit[8] read_only // Compiler rejects writes to read-only fields endendThe compiler knows FERR is read-only. It knows CR is at offset 0x00 from base 0x4000_1000. No unsafe. No pointer casts. Syntactic Honesty: the peripheral declaration is the hardware truth.
Rust makes you write unsafe { core::ptr::write_volatile(0x4000_1000 as *mut u32, val) }. That’s not programming – that’s praying with extra steps.
2. Radiation-Hardened Memory
Section titled “2. Radiation-Hardened Memory”// TMR (Triple Modular Redundancy) as a type qualifierlet critical_state: tmr u32 = 0x0000_0000
// Compiler emits: three copies + majority vote on every read// The programmer sees ONE variable. The machine sees three.critical_state = compute_attitude() // Writes to all threelet val = critical_state // Majority vote, auto-corrects single bit-flipThe tmr qualifier reveals that this memory is triple-redundant. You don’t hide it behind a library. You don’t pretend it’s normal memory. The type system knows the hardware is unreliable and the codegen compensates.
No other language has this. Not Rust. Not Zig. Not Ada/SPARK – which gets closest but buries it in annotations.
3. WCET Pledges (Worst-Case Execution Time)
Section titled “3. WCET Pledges (Worst-Case Execution Time)”func attitude_control_loop(sensors: *SensorArray) !CommandVector pledge wcet(10_000 cycles) // Hard ceiling pledge no_alloc // Zero dynamic allocation — compiler enforced pledge no_recursion // Call graph must be a DAG pledge deterministic // No branches dependent on uninitialized memorydo // If any code path MIGHT exceed 10,000 cycles, // the compiler rejects the program. At compile time. Not at runtime.endThe compiler does static analysis on the call graph, counts instructions per path, and refuses to emit a binary if the pledge can’t be proven.
Rust has zero concept of this. Zig has zero concept of this. Even Ada/SPARK requires external tools (RapiTime, aiT) to analyze WCET – it’s not in the language.
Janus makes WCET a compile-time property. The pledge is part of the function’s type signature. If you call a function that violates your WCET budget, you get a type error. Not a runtime overrun. Not a missed deadline. A type error.
4. Peripheral Ownership as Capabilities
Section titled “4. Peripheral Ownership as Capabilities”// Subsystem A owns UART0. Period. Compiler-enforced.capsule navigation requires peripheral(UART0, perms: .read_write) requires peripheral(SPI1, perms: .read_only) pledge no_allocdo func send_telemetry(data: []const u8) !void do UART0.DR.DATA = data[0] // Legal: we own UART0 // SPI1.DR.DATA = 0xFF // COMPILE ERROR: read_only permission endend
capsule payload_science requires peripheral(SPI1, perms: .read_write)do func read_sensor() !SensorReading do // UART0.CR.TXEN = .enabled // COMPILE ERROR: no capability for UART0 let raw = SPI1.DR.DATA // Legal: we own SPI1 return raw endendTwo capsules. Two peripheral sets. Zero overlap enforced at compile time. No mutex. No runtime lock. The type system guarantees that navigation and payload_science never touch each other’s hardware.
In Rust, you’d use a HAL crate with ownership types – but it’s a library convention, not a language guarantee. Swap HAL crates and your safety model vanishes. In Janus, the compiler is the enforcer.
5. Interrupt Priority Inversion Prevention
Section titled “5. Interrupt Priority Inversion Prevention”interrupt TIMER0_IRQ priority(3) pledge wcet(500 cycles) pledge no_blocking // Cannot acquire any lock held by lower prioritydo // This ISR runs at priority 3. // If it tries to call a function that acquires a lock // also used by a priority-2 context — COMPILE ERROR.
heartbeat_counter += 1 // Atomic by declaration, not by prayerendPriority inversion killed the Mars Pathfinder in 1997. It took a remote patch via deep space communication to fix a mutex bug. In Janus, the compiler catches it before the binary ships. The pledge no_blocking combined with priority-aware lock analysis means priority inversion is a compile-time error.
6. Watchdog Integration as a Language Primitive
Section titled “6. Watchdog Integration as a Language Primitive”watchdog system_wdt timeout(2000ms)
func main_loop() never pledge watchdog(system_wdt) // Compiler verifies: every path kicks within 2000msdo loop do let sensors = read_sensors() // 50ms max let commands = compute(sensors) // 200ms max (from wcet pledge) actuate(commands) // 100ms max kick system_wdt // Explicit. Visible. Honest. // Delete this line — COMPILE ERROR // WCET sum exceeds 2000ms — COMPILE ERROR endendEvery embedded developer has shipped code that forgot to kick the watchdog on one error path. The satellite resets. Telemetry is lost. In Janus, the compiler proves that every execution path through a pledge watchdog function kicks the dog within the timeout window.
7. Memory-Mapped I/O Fencing
Section titled “7. Memory-Mapped I/O Fencing”func configure_dma() !void pledge memory_fence // All MMIO writes ordered; no reordering across fence pointsdo DMA1.CR.EN = .disabled // Step 1: disable fence // Hardware memory barrier emitted here DMA1.CMAR = buffer.as_ptr() // Step 2: set source DMA1.CNDTR = buffer.len() // Step 3: set length fence // Another barrier DMA1.CR.EN = .enabled // Step 4: enable // Compiler GUARANTEES step ordering. No volatile tricks. No UB prayers.endIn C, you’d use volatile and hope the compiler doesn’t reorder. In Rust, you’d use core::sync::atomic::fence(Ordering::SeqCst) – correct but communicates nothing about why the fence exists. In Janus, the fence keyword inside a pledge memory_fence function is self-documenting intent with compiler-verified ordering.
Profile Mapping
Section titled “Profile Mapping”Every feature lands precisely where it belongs in the profile system:
| Feature | :core | :service | :sovereign |
|---|---|---|---|
peripheral declarations | — | — | First-class |
tmr type qualifier | — | — | First-class |
pledge wcet | — | — | First-class |
pledge no_alloc | Available | Available | Enforced by default |
interrupt with priority analysis | — | — | First-class |
watchdog primitives | — | — | First-class |
fence with ordering proof | — | — | First-class |
| Guard page integration | — | Automatic (nurseries) | Capability-gated |
@canary annotation | — | — | Opt-in |
pledge stack(N) | — | — | First-class |
The lower profiles don’t need this – they target hosted environments. :sovereign targets the metal itself, where the compiler has full knowledge of the target hardware.
The Implementation Path
Section titled “The Implementation Path”This maps cleanly onto what already exists:
:core— Stack is just memory. No special treatment. (Complete.):service— Nursery-spawned tasks get automatic guard pages. (Natural fit with the nursery model.):sovereign—pledge stack(N)compile-time analysis + guard page integration + optional@canaryannotation. The compiler knows about the hardware floor beneath it.
The guard page infrastructure built in Nexus OS becomes the runtime backing for Janus :sovereign’s stack safety model. The language doesn’t reinvent it – it declares it as a capability and lets the kernel enforce it.
The Philosophical Kill Shot
Section titled “The Philosophical Kill Shot”Here’s what Rust and Zig fundamentally can’t fix: they separate the language from the hardware.
Rust’s safety model ends at unsafe. Zig’s explicitness ends at “you figure out the hardware.” Both languages say: “Past this point, you’re on your own.”
Janus :sovereign says: there is no point where you’re on your own. The peripheral map is a type. The execution time is a pledge. The interrupt priority is a constraint. The watchdog is a proof obligation. The radiation protection is a qualifier.
The language and the machine become one legible surface.
That’s what makes it the best systems language on this planet – and the only one worth sending off it.
Related Reading:
- The Manifesto — Why Janus Exists
- The Bedrock — Foundational Principles
- Strategic Pragmatism — Tactical vs. Strategic Design
- Profiles System — Understanding the Capability Ladder