Boot check
Declare a feature’s own mount-invariant with r.bootCheck(...) instead of
relying on framework-internal knowledge. The recipe reproduces the
prompt-store trap (kumiko-enterprise#229): a feature ships PII-annotated
fields but the companion feature that’s supposed to govern user data was
never mounted, and nothing caught it — until now.
What it shows
Section titled “What it shows”r.bootCheck(fn)— a check function that runs once at boot with a ctx exposing every mounted feature. Throw to fail the boot with a clear, feature-prefixed message.- Conditional invariants
r.requirescan’t express — the check only fails when this feature’s own shape demands it (has a PII field), not unconditionally. A plainr.requires("user-data-hook")would fail even for a prompt-store variant with no PII fields at all. validateBoot— the framework’s boot-time validator, run directly against a feature list.bootCheckhas no DB dependency, so this is the cheapest way to exercise it — nosetupTestStackneeded.
Feature composition
Section titled “Feature composition”prompt-store → entity with a PII field, declares the bootCheckuser-data-hook → companion feature the check requires when PII is presentprompt-storedefines an entity with apii: truefield.- It registers
r.bootCheck(({ features }) => { ... }), closing over its own field definitions to decide whether the invariant applies. - At boot,
validateBootruns every registered check. Ifprompt-storeis mounted withoutuser-data-hook, the check throws and boot fails with[Feature prompt-store] r.bootCheck failed: .... - Mount
user-data-hookalongside it, and the same check passes.
When to reach for it
Section titled “When to reach for it”You’re writing a feature whose validity depends on another feature being
mounted, but only under a condition your feature alone can evaluate (e.g.
“only if I have PII fields”, “only if I expose more than N screens”). If the
requirement is unconditional, r.requires/r.optionalRequires is simpler
and already covered by the boot validator.
bun test samples/recipes/boot-check/src/__tests__/feature.test.tsTwo cases: companion mounted → boot succeeds; companion missing → boot fails with the feature-prefixed message.
Source code
Section titled “Source code”The feature entry point — embedded straight from the source file, so the code here is exactly what runs. Multi-file samples keep their remaining files next to it on GitHub (link below):
// Boot-Check Sample// Shows: how a feature declares its own mount-invariant via r.bootCheck,// for conditional cross-feature requirements r.requires can't express.
import { createEntity, createTextField, defineFeature } from "@cosmicdrift/kumiko-framework/engine";
// The prompt-store trap (kumiko-enterprise#229): a feature with a PII field// was mounted without its required companion feature, and nothing caught// it at boot. r.requires("user-data-hook") can't express this — it would// fail even for a prompt-store variant with no PII fields at all.const promptFields = { text: createTextField({ pii: true }) };
export const promptStoreFeature = defineFeature("prompt-store", (r) => { r.entity("prompt", createEntity({ fields: promptFields })); r.bootCheck(({ features }) => { const hasPiiField = Object.values(promptFields).some((field) => field.pii); const hasUserDataHook = features.some((f) => f.name === "user-data-hook"); if (hasPiiField && !hasUserDataHook) { throw new Error("prompt-store has PII fields but no user-data-hook feature is mounted"); } });});
export const userDataHookFeature = defineFeature("user-data-hook", () => {});📄 On GitHub: samples/recipes/boot-check/src/feature.ts