writeonce/docs/00-principles.md
shoney.arickathil 28485a271c docs: iteration 7b migration — amend the normative docs (Phase 4)
The spec's §8 migration table, applied:

- 00-principles.md P3: "@gc is a per-class opt-in, reference-counted" ->
  GC-ness is inferred; incremental per-shard mark-sweep in budgeted slices;
  still no global pause by construction.
- OOP spec: decision-table GC row -> inferred (hybrid rule named); §3 rule 5
  -> traced classes alias freely, which classes is inferred; §4 memory model
  -> the RC + Bacon-Rajan paragraph replaced by tracing (snapshot roots,
  Yuasa barrier, born-black, budgeted slices); header rc comment -> union'd
  sweep link; mixing rule restated for tracing.
- 00-wob-format.md: header says version 4; opcodes 27-28 -> reserved (loader
  rejects); the owned-temporary rule's @gc exclusion restated for tracing.
- 08-builtin-surface.md: the push RC_INC special case and the set(m,k,v)
  retention gap DELETED — neither exists without RC; the corpus cycle is
  collected by tracing.
- story 07b: status -> LANDED 2026-08-18 (with the historical note kept);
  board: 7b row ✅ (supersedes iteration 2's RC memory model), pending row
  removed.
- gc-cycle README: Phase 3 flipped to landed (the ring runs, is reclaimed,
  ASan-clean; the ?Node RC_DEC-on-nil trap no longer exists); the barrier
  prose corrected to the as-built design (snapshot-at-beginning + deletion
  barrier + born-black, not per-slice root re-reads).
- plan 2026-08-18: all checkboxes ticked + a completion banner recording the
  four deviations from the plan as written.

(Error catalog was already amended with the keyword-removal commit: WO-E104
added, WO-W201 retired.)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 17:11:35 +02:00

139 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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<Mutex<…>>` 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:* [plan 09](plan/09-concurrency-scaleout.md) (shipped on the
Rust runtime), [the shard-actor plan](superpowers/plans/2026-08-01-shard-actor-vm-runtime.md).
## 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. RAM is authoritative; the WAL makes it durable
All reads serve from memory. Every mutation is WAL-logged and fsynced
before acknowledgment; boot replays the log. Mirrors (Postgres) are
reconstructible backups that reads and acks never depend on.
*Why:* one source of truth with predictable latency; durability is a
sequential append, not a storage engine bolted to the side.
*Enforced by:* [plan 11](plan/11-wal-and-recovery.md),
[plan 16](plan/16-postgres-mirror.md) (mirror-is-backup doctrine).
## 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 blog sample](examples/blog/README.md),
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 (`fs`,
`proc`, `net`, `time`, `json`): 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).