# The writeonce principles The doctrine in one page. Every design argument in this repo eventually lands on one of these thirteen; later documents link here instead of re-arguing them. Each principle: what it is, why it holds, where it is enforced. ## 1. One binary is the whole system The application, the database, the API, and (later) the UI ship as a single deployable — there is nothing else to install, operate, or version-skew. *Why:* the assembled-stack tax (app + DB server + proxy + glue) is the problem writeonce exists to delete. *Enforced by:* [`01-problem.md`](01-problem.md), the single-binary story in [the OOP spec](superpowers/specs/2026-08-01-oop-compiler-vm-design.md). ## 2. Zero dependencies — kernel primitives only The runtime is C on libc; the compiler is OCaml on its stdlib; everything else is epoll/io_uring, inotify, eventfd, signalfd, sendfile, mmap. The kernel is the framework. *Why:* every dependency is a supply chain, an upgrade treadmill, and a black box in the one binary that must be understood end to end. *Enforced by:* [the kernel-primitives catalogue](plan/exploration/linux/00-linux.md), the dependency doctrine in [the OOP spec](superpowers/specs/2026-08-01-oop-compiler-vm-design.md). ## 3. Memory safety without a GC tax Objects are owned values: one owner, moves on assignment, second-class borrows checked mostly at compile time (mutable value semantics — the Rust-borrow shape without lifetime inference). GC-ness is **inferred** by the compiler (iteration 7b): a class in a reference cycle, or one whose values must escape as long-lived aliases, is traced by an incremental per-shard tri-color mark-sweep collector in budgeted slices — the developer writes no memory annotation, and no global pause exists by construction. *Why:* deterministic memory for the default case, aliasing freedom where the design wants it, and never a stop-the-world in a runtime that is also the database. *Enforced by:* [the OOP spec §4](superpowers/specs/2026-08-01-oop-compiler-vm-design.md). ## 4. No inheritance, ever No `extends`, no `override`, no virtual hierarchies. Is-a is a tagged union; has-a is composition; polymorphism is structural interfaces. *Why:* hierarchies fossilize early guesses and make dispatch, ownership, and diagnostics all harder; composition keeps every unit flat and movable. *Enforced by:* [the OOP spec](superpowers/specs/2026-08-01-oop-compiler-vm-design.md), the reject rows of [the systems-track verdict table](superpowers/specs/2026-08-01-systems-track-design.md). ## 5. Thread-per-core shards; ownership moves, data never shares One pinned worker per core, each owning its engine, heap, and event loop. Cross-shard work is a message send that moves ownership. There is no `Arc>` anywhere and never will be. *Why:* sharing mutable state buys contention, locks, and heisenbugs; moving ownership buys linear scaling and per-shard GC. *Enforced by:* [the shard-fiber arc plan](superpowers/plans/2026-08-20-shard-fiber-arc.md) (stages 1+2 landed; supersedes the discarded 2026-08-01 shard-actor plan and the Rust-era plan 09, removed with that track 2026-08-18). ## 6. The runtime never stops The executable is a systemd service that deploys without restarting: two VM slots (Blue/Green), in-runtime compile of an approved proposal, atomic dispatch switch, previous version resident for instant rollback — and the binary embeds its own source, so prod is always self-describing. *Why:* restarts drop connections, dump caches, and turn deploys into events; a database that is also the app must not blink. *Enforced by:* [the blue-green spec](superpowers/specs/2026-08-03-blue-green-vm-design.md). ## 7. The log is authoritative; residency is a declared per-table policy **Amended 2026-08-26.** This principle read "RAM is authoritative; the WAL makes it durable. All reads serve from memory." The durability half was never under strain and is unchanged. The residency half was false for a real workload, so it is now a declaration rather than a law. **Durability, unconditional:** every mutation is WAL-logged and fsynced before acknowledgment; boot replays the log; a torn tail is dropped whole by CRC; an ack means the commit reached disk. Mirrors (Postgres) are reconstructible backups that reads and acks never depend on. None of this is per-table and none of it is negotiable. **Residency, declared:** what a table keeps in memory is stated at the declaration site. The default keeps every row resident and serves reads at memory speed. A table that cannot fit says so, and then only its indexes are resident while rows are read from the log by offset — the kernel page cache is the hot copy, which is why the engine uses `pread` and deliberately not `O_DIRECT`. *Why the amendment:* the original wording is right for a knowledge-management app and simply false for a 120 GB order table on a 32 GB host. A doctrine a real workload cannot satisfy does not get followed, it gets ignored — and the failure it produced was an OOM kill, which is the least debuggable outcome available. The fix keeps one storage engine and one source of truth: the log *is* the database, and RAM is how much of it you choose to serve fast. What was rejected in 2026-08-18 and stays rejected is a *second* engine — a paged B-tree with its own buffer pool ([`plan/discarded.md`](plan/discarded.md)). Reading rows from the log we already write is not that. *Enforced by:* [the db-engine binding plan](superpowers/plans/2026-08-01-db-engine-binding.md) (typed WAL + boot replay, shipped); the residency declaration and its enforcement are [databasev2 2](stories/databasev2/02-table-storage-modes.md); the mirror-is-backup doctrine is recorded in [`plan/discarded.md`](plan/discarded.md) (the Rust-era WAL and mirror plans 11/16 were removed with that track 2026-08-18). ## 8. Samples force the grammar Language features exist when a sample program exercises them; the examples directory is the de facto integration suite, and new surface is proven by re-expressing real workloads (blog, ecommerce, pricing, log-watcher). *Why:* grammars designed in the abstract grow features nobody needs and miss the ones real programs demand. *Enforced by:* [the web-app sample](examples/web-app/README.md) (the blog sample left with the Rust track), the sample-workload acceptance in [the systems-track spec](superpowers/specs/2026-08-01-systems-track-design.md). ## 9. Linux is the target Not POSIX, not portable-someday: Linux syscalls, Linux fd semantics, systemd as the process manager. Portability abstractions are refused. *Why:* targeting one kernel lets the runtime use its sharpest primitives directly instead of the lowest common denominator. *Enforced by:* [the kernel-primitives catalogue](plan/exploration/linux/00-linux.md). ## 10. Capabilities are typed builtins — no FFI Programs reach the system only through audited stdlib builtins — six reserved namespaces (`fs`, `proc`, `net`, `time`, `json`, `env`): bounded reads, args-array-only process runs, handles that close on drop. There is no `extern`, no escape hatch. *Why:* one FFI hole voids the entire memory-safety and security story; typed capabilities make the safe path the only path. *Enforced by:* [the systems-track spec Parts 2–3](superpowers/specs/2026-08-01-systems-track-design.md). ## 11. Plain diagnostics are the product Stable `WO-E###` codes, `file:line:col`, source excerpts, ownership errors naming both sites, many errors per run. *Why:* mutable value semantics only beats Rust ergonomics if the errors read like sentences; the compiler's error text is a first-class feature. *Enforced by:* [the OOP spec §6](superpowers/specs/2026-08-01-oop-compiler-vm-design.md), [the compiler architecture doctrine](plan/compiler/architecture.md). ## 12. The runtime is a recipe box Transports, fibers, routing, subscriptions, the DB engine, deploy machinery — each stays a separable capability. A web framework or a custom database experience is a `.wo` library composing them; the runtime itself stays framework-agnostic. *Why:* the next stories (web framework, richer database surfaces) must be buildable *on* the runtime without forking it. *Enforced by:* [the blue-green vision §2](plan/exploration/blue-green-vm/00-vision.md). ## 13. Statically typed, all the way to the register Every slot's type is known at compile time: no `Dynamic`, no `untyped`, no `cast`, no runtime reflection. The VM runs untagged 64-bit registers because the compiler already knows; JSON enters through checked decodes (`as T` yielding `?T`), never through dynamic objects. *Why:* the type system is the foundation the untagged VM, the borrow checker, and the annotation ORM (`@table` classes, `ref`/`multi` relations) all stand on — one dynamic hole collapses all three. The Haxe reference workload shows the alternative: its transcompiled C++ pays a hashed `__Field` lookup on every typedef access. *Enforced by:* the `Dynamic`/`untyped`/`cast` reject rows of [the systems-track verdict table](superpowers/specs/2026-08-01-systems-track-design.md), untagged registers in [the OOP spec §5](superpowers/specs/2026-08-01-oop-compiler-vm-design.md).