Architecture Decisions — Register
2026-10-22: every proposal below was ACCEPTED by the project owner and recorded in ADR 0002. The exceptions are KQ-2, 3, 5, 6 and 7, which need CosmoOS changes or rulings; Nova uses the conservative defaults listed in ADR 0002. Add new open questions below with the next free ID (OD-22+).
Original status: Milestone 0 (master prompt §23.K). Each item lists the proposed (now accepted) answer.
Language and compiler (owner: Nova)
| ID | Question | Proposed | Alternatives | Safety impact | Perf impact | Blocks |
|---|---|---|---|---|---|---|
| OD-1 | Compiler implementation language | C# / .NET 10, NativeAOT for distribution (ADR 0001) | Rust, C++20 | none directly | compile speed only | M1 |
| OD-2 | Memory architecture | Hybrid (C): ownership + regions-as-loans + optimisation-only escape analysis (memory-model.md) | A (pure ownership), B (regions) | defines the safety argument | — | M1 (shapes IR) |
| OD-3 | Lifetime-parameterised structs (references in user aggregates) | Not in v0 (E3). Designed in M6f (od3-design.md); accepted (ADR 0006) and implemented in M6x (2026-10-23; milestone-6x.md): region parameters on structs, enums and functions (struct Parser<region src>), one loan set per value, call-site propagation by regions, drop check (type-system.md §25, ownership.md E3/E4) | Rust-style 'a now | larger checker surface | enables zero-copy | — (done in M6x) |
| OD-4 | class keyword | Reserved; future sugar for always-boxed non-Copy types | Classes now; drop the keyword | none if sugar | — | M6 |
| OD-5 | Panic strategy | Abort, no unwinding; destructors do not run on panic | Unwinding via C setjmp (no setjmp in CosmoOS libc, and costly) | simpler cleanup proofs | smaller code | M1 |
| OD-6 | Integer overflow | Panic in all builds; explicit wrapping*/checked*/saturating* | Rust-like wrap in release | logic safety | small check cost (BCE/range analysis M9) | M1 |
| OD-7 | Copyability of structs | Implicitly Copy iff all fields Copy and no drop; @noncopy to opt out | Explicit copy struct opt-in (Rust-like) | none (both sound) | — | M2 |
| OD-8 | Arena with destructors | v0: arena contents must have no drop (R2); later a drop list | Allow drops now | resource leaks if done wrong | — | M4 |
| OD-9 | Closures | None in v0. Non-capturing fn pointers only. Scoped capturing closures in M6+. M11 G8: ADR 0012 accepted 2026-10-25 (function values fn(…) -> R, scoped closures borrow fn(…) -> R with arrow literals, inferred captures, effects on function types) | — | closures carry borrows | — | M6 |
| OD-9a | Monomorphised closures (each literal its own type, F: Fn(T) -> R bounds; inlinable calls, owning captures through generics) | Deferred by ADR 0012: decide when a performance need appears, with a benchmark. ADR 0019 accepted and implemented 2026-10-28: specialisation in the compiler (optimisations.md §5), no language change; benchmarks/sort is 34% (clang) and 28% (gcc) faster. Closure types and Fn bounds stay open as a language question. Re-examined 2026-10-29 and kept deferred (owner): specialisation met the measured need and Box<dyn fn> stores closures; take it up when a real program needs a closure stored without an allocation, or lazy iterator adapters | — | none beyond ADR 0012 | removes the indirect call | — |
| OD-9b | Owning, heap-allocated closures (returnable, storable, sendable) | Deferred by ADR 0012: only together with dyn (OD-10). M13 G3: ADR 0015 accepted 2026-10-28: move literals boxed as Box<dyn fn(…) -> R, A>, an explicit and fallible allocation (so the kernel profile may use them with KernelHeap); implemented 2026-10-28 (type-system §36.5) | — | needs dyn and allocation | an allocation per closure | OD-27 |
| OD-28 | Global and per-CPU state: static items whose mutable state is reached only through Share types (lock guards, atomics), statically initialised C state, @percpu statics accessed where the CPU cannot change | Proposed by M14 K1 for CosmoOS's roadmap 2.0 (SA2, SA3). ADR 0024 accepted 2026-10-29: static of Share types and static mut (every use unsafe), built by @constant constructors and C constant macros; per-CPU data a kernel-library type | state only in C, as today | a static is shared by every thread: it must be Share | none | SA2 |
| OD-29 | Nova-to-Nova calls with Nova's types across compilation units: C in several translation units (K2a), then separate compilation per package with interface files (ADR 0013 D4 deferred it until build times were measured) | Proposed by M14 K2: a whole-program build of 202,000 lines takes 13.1 s in novac plus 33.8 s in clang, one translation unit, on every change. K2a accepted (ADR 0022, 2026-10-29): --split, one C file per Nova file; separate compilation stays open | stay whole-program | none (the checks are the same) | build time | SA6 |
| OD-30 | Where the kernel library (KernelHeap, KRef<T>, the lock guards, Quiesce, and a new ObjectCache<T>) lives and who owns it | Proposed by M14 K3. ADR 0025 accepted 2026-10-29: in Nova's repository, lib/kernel, selected by kernel = "cosmoos"; trusted = true packages may declare @threadSafe | in Nova's repository | unsafe at the floor, argued once | none | SA2 |
| OD-31 | How a self-hosted CosmoOS builds its kernel when the generated C is no longer committed (its roadmap 2.0's rule 7), since novac does not run on CosmoOS | Proposed by M14 K4. ADR 0023 accepted 2026-10-29: source releases carry the generated C | novac on CosmoOS; a compiler written in Nova | none | none | SA1 |
| OD-32 | novac running on CosmoOS (a .NET runtime port, or .NET through the Linux personality) | Recorded by ADR 0023: not needed while source releases carry the generated C | — | none | none | — |
| OD-33 | A Nova compiler written in Nova, for a self-hosting toolchain | Recorded by ADR 0023 as the long-term direction | — | none | none | — |
| OD-34 | Self-pointing C state in statics (a static Mutex, wait queues, list heads) and moves of non-Copy values through raw pointers (ObjectCache<T>) | Left open by ADR 0025 §7. ADR 0027 accepted 2026-10-29: here in static initialisers, MUTEX_INIT_AT in CosmoOS; unsafe read/write for any T, Layout.of<T>(), a static-only ObjectCache<T> | a lazily initialised StaticMutex<T>; stateful Box allocators | read/write can duplicate or leak ownership (unsafe) | none (here); two pointers per cache box | SA2, SA3 |
| OD-10 | ||||||
| OD-9c | Effect-polymorphic functions: a function whose effects are its own plus those of a closure argument's type (so sortBy could run in an atomic context with an @effects() comparator) | Deferred by G8c (type-system.md §36.4): the library methods have the effects of a closure without an effect list. ADR 0020 accepted 2026-10-29: @effectsOf(p), Swift's rethrows for sleep and alloc; effect variables stay open | — | none | none | ADR 0012 §3.7 |
| OD-23 | Floating-point types (f32/f64): arithmetic semantics, formatting for Console, casts, and the kernel-profile ban | Deferred by ADR 0005. Schedule as a separate increment (after M6). M11 G7: ADR 0011 accepted 2026-10-25 (IEEE, no contraction, never-panicking arithmetic, checked float→int, shortest round-trip printing (Schubfach), --no-float; then sqrt/abs/floor/ceil/min/max) | Add in M6 | float formatting cost | Ex2/Ex13 run with integers until then | post-M6 |
| OD-24 | Weaker atomic orderings (acquire, release, relaxed) for userland atomics | Deferred by ADR 0016: sequentially consistent only in v1, until a benchmark needs more. ADR 0021 accepted 2026-10-29 after benchmarks/atomics (a ring 5–9× faster on x86-64 with acquire/release): ordered …With methods in lib/std | — | ordering bugs are not data races, but are logic bugs | fences on weakly ordered CPUs | — |
| OD-25 | Scoped threads (Thread.scope) that borrow the spawner's locals | Deferred by ADR 0016: needs a rule for borrows that outlive one closure call. ADR 0018 accepted and implemented 2026-10-28: fork-join, Thread.both(a, b) (type-system §38.6, ownership T4), which needs no new borrow rule. Handles and loops of spawns (Rust-style scopes) stay open | — | borrows across threads | none | — |
| OD-26 | Several versions of one package in one build | Deferred by ADR 0017: one version per package name, as today; several would need per-version C names (c-backend.md §2.1). Re-examined 2026-10-29 and kept deferred (owner): the index has no packages yet, so no build can meet a conflict; take it up when published packages' requirements conflict | — | none | code size | — |
| OD-10 | Dynamic dispatch (dyn Interface) | Future. Static generics only in v0. M13 G2: ADR 0015 accepted 2026-10-28: fat pointers behind borrow/borrow mut/Box, dyn-compatible interfaces, no scoped T and no downcasting in v1 (OD-10a dyn(r) I, OD-10b downcasting stay open) | vtables now | — | code size | M6 |
| OD-11 | Package / manifest format | nova.toml with name, version, profile, dependencies. M10: ADR 0013 accepted 2026-10-26 (path and git dependencies with a lock file, as the owner chose; package-level names, import; whole-program builds). M13 G6: ADR 0017 accepted 2026-10-28: a git index, caret requirements, a solver | — | — | — | M10 (T5–T6) |
| OD-12 | Growable scratch arrays (Goose "one growable on top") | Not in v0 | adopt | complex shrink rules | faster temporaries | M5 |
| OD-13 | Rc<T>/Weak<T> library type | Post-M6, explicit and opt-in, single-threaded | never | cycles leak | RC traffic | post-M6 |
| OD-14 | @flat inline variable-size layouts | Post-M9 research | — | — | — | — |
| OD-17 | Call-site borrow syntax | Implicit shared borrow, mut x for exclusive, borrow x/borrow mut x elsewhere | Rust &x/&mut x | none | — | M2 |
| OD-18 | Surface syntax for references in types | borrow T / borrow mut T (as the prompt proposes) | &T/ref T | none | — | M2 |
CosmoOS integration (owner: CosmoOS project owner)
| ID | Question | Proposed | Blocks |
|---|---|---|---|
| OD-15 | Is the Nova runtime "library" under libc invariant L1 (may it use raw cosmo_* syscall wrappers)? | No: public libc functions only, until the owner says otherwise | C1 (confirms the approach) |
| OD-16 | May Profile A also target the musl/Linux personality? | Later, as an opt-in profile; native is the default | C3 |
| OD-19 | Is checked-in generated C acceptable (port route S1)? Or must generation run in the build (.NET in CI)? | S1: checked-in, deterministic, with a header naming the novac version and source hash | C1→C3 in-tree |
| OD-20 | Will the owner schedule a Nova unit (AGENTS.md restricts work to the owner-chosen 1.2 unit)? | Propose after C1 succeeds out of tree (S0) | in-tree work |
| OD-21 | Missing libc pieces (aligned_alloc, math.h, poll, strtod, exec*): add to CosmoOS libc, or implement in the Nova runtime? | Add to libc as owner-chosen units (they benefit C too); Nova works around them meanwhile | C3 |
| KQ-1…KQ-8 | Kernel questions | See cosmoos/kernel-memory-and-lifetimes.md §8 | C5–C8 |
Also to report to the owner (no decision needed from Nova): CosmoOS's limits.h CHAR_MIN/MAX are wrong on AArch64. About 18 doc/code disagreements are listed in the two audit reports.