ADR-0015: Prove the spine first; keep the kernel domain-agnostic so kernel⟂realm separation is a relocation, not a rewrite
ADR-0015: Prove the spine first; keep the kernel domain-agnostic so kernel⟂realm separation is a relocation, not a rewrite
Status
Accepted
Date
2026-06-24
Context
The walking skeleton (docs/proof/walking-skeleton.md) must prove the kernel. The kernel’s entire value proposition is the contribution boundary — domain content is contributed across a boundary, not compiled in (ADR-0001 doctrine: one kernel, many modules, no private reality). A skeleton that hardcodes the domain proves a bespoke app, not a kernel.
But the two highest-risk unknowns are the truth model (ADR-0003, Proposed) and the kernel language (ADR-0006, Proposed), and standing up a realm compiler + install/Universe boundary is significant build for a 2–3 person team (ADR-0014). Doing the full kernel⟂realm separation in slice 1 would delay the de-risking of the two freeze gates.
This is the same shape as ADR-0013 (build online-first, but design for offline). We sequence the build for fast de-risking, while refusing to paint ourselves into a corner on the thing we deferred.
Decision
Slice 1 proves the spine; slice 2 proves the separation — but the kernel is domain-agnostic from slice 1.
Slice 1 (spine): prove write → event → projection → read end-to-end on a concrete domain (projects), discharging the ADR-0003 truth-model spike and the ADR-0006 language build-off. Slice 1 does not build the realm compiler, the install/Universe path, or the separation acceptance tests.
Guardrail (non-negotiable — the tripwire that keeps slice 2 additive):
- The kernel’s engines (value-type registry, entity/action registries, action executor, event log, projection engine, serving store, authority) are registry/definition-driven. No engine branches on a specific domain type.
- Kernel source names zero domain types. No
WorkPackage, noprojects.*in anykernel/file; noswitch(entityType). - Domain content lives in
realms/as definition objects, hand-registered into the kernel registries at boot (no compiler yet). - Enforced by a grep check in slice-1 acceptance that fails if any kernel file references a domain type.
Slice 2 (separation): introduce a v0 realm compiler, the install-into-a-Universe path, and the separation proofs — kernel builds and boots with the projects realm removed; a second trivial realm drops in through the identical path. Because of the guardrail, this is a relocation of where definitions come from (hand-registered → compiled package), not a re-architecture.
Alternatives Considered
Full separation in slice 1 (the grill’s Options 1–3: agnostic kernel + v0 compiler, ± declarative authorability, ± external second-author)
- Pros: proves the contribution story immediately — the kernel’s actual value.
- Cons: enlarges slice 1 and delays the truth-model + language de-risk for a small team.
- Rejected for now (user chose spine-first); slice 2 picks this up. The guardrail preserves the option at low cost.
Naive spine (hardcode the domain into the engines)
- Pros: fastest possible spine.
- Cons: slice 2 becomes a rewrite of the engines — exactly the corner the kernel⟂realm critique warns against.
- Rejected: the guardrail exists precisely to forbid this.
Consequences
- Slice 1 stays small and answers the two Proposed ADRs (0003, 0006) fast.
- The grep guardrail is cheap insurance that slice 2 is additive, not a rewrite.
- The ADR-0006 build-off remains valid for the real kernel: it exercises registry-driven dynamic execution + codegen, not a throwaway hardcoded path.
- Risk: under time pressure, slice 1 could violate the domain-agnostic guardrail. The grep check is the tripwire; if it is ever disabled, this ADR is being violated and slice 2’s cost balloons.
- Refines ADR-0014 (sequencing) and ADR-0008 (realms). Supersedes nothing.