Skip to content

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.

  • 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.requires can’t express — the check only fails when this feature’s own shape demands it (has a PII field), not unconditionally. A plain r.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. bootCheck has no DB dependency, so this is the cheapest way to exercise it — no setupTestStack needed.
prompt-store → entity with a PII field, declares the bootCheck
user-data-hook → companion feature the check requires when PII is present
  1. prompt-store defines an entity with a pii: true field.
  2. It registers r.bootCheck(({ features }) => { ... }), closing over its own field definitions to decide whether the invariant applies.
  3. At boot, validateBoot runs every registered check. If prompt-store is mounted without user-data-hook, the check throws and boot fails with [Feature prompt-store] r.bootCheck failed: ....
  4. Mount user-data-hook alongside it, and the same check passes.

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.

Terminal window
bun test samples/recipes/boot-check/src/__tests__/feature.test.ts

Two cases: companion mounted → boot succeeds; companion missing → boot fails with the feature-prefixed message.


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