diff --git a/skills/objectstack-platform/SKILL.md b/skills/objectstack-platform/SKILL.md index 380e749396..06f724c755 100644 --- a/skills/objectstack-platform/SKILL.md +++ b/skills/objectstack-platform/SKILL.md @@ -186,8 +186,29 @@ holds a collection of one metadata kind — `manifest`, `objects`, There is deliberately **no** top-level `workflows` or `approvals` collection: an approval is authored as a flow with Approval nodes (ADR-0019), and record state machines are a `state_machine` validation rule on each object -(ADR-0020). Unknown keys are **silently stripped** by strict parsing — a -phantom key like `roles:` or `policies:` is a no-op, not an error. +(ADR-0020). A phantom key like `roles:` or `policies:` is **not** a silent +no-op — the top level refuses it and the stack fails to load: + +``` +defineStack validation failed (1 issue): + + ✗ (root): Unrecognized key(s) on this stack definition: `policies`. … +``` + +Undeclared keys are handled per surface, and the two postures are worth +keeping straight: + +- **Refused** — `defineStack()`'s top level, each `objects[]` entry + (`ObjectSchema`), and each field (`FieldSchema`). The parse throws, naming + the surface and the offending key. TypeScript rejects the literal earlier + still, with `TS2353: Object literal may only specify known properties`. +- **Warned, then dropped** — the authoring surfaces whose shapes have not + been closed yet (`connectors` is one). `defineStack()` prints the warning + before the parse, and the value does not survive it: + `defineStack: connectors.stripe.bogusKey: 'bogusKey' is not a declared connector key, so its value is dropped at load.` + Treat these as errors-in-waiting — closing the remaining shapes is a + scheduled migration, so a key that only warns today is expected to be + refused later. For the exact Zod shape — including which keys are optional and what types the collection items take — read @@ -1042,7 +1063,7 @@ const metrics = kernel.getPluginMetrics(); ## Feature Flags Feature flags are **not a spec/metadata concept**. There is no `featureFlags:` / -`features:` key on `defineStack` (strict parsing silently strips unknown keys), and the +`features:` key on `defineStack` (writing one is refused at load, not stripped), and the former `FeatureFlagSchema` (`@objectstack/spec/kernel`) was removed — it had zero runtime consumers, and its only protocol home (the static `ObjectStackCapabilities.system.features` descriptor) was itself dead: no endpoint ever served it. Runtime capability discovery is diff --git a/skills/objectstack-platform/rules/bootstrap-patterns.md b/skills/objectstack-platform/rules/bootstrap-patterns.md index d5e10b6c8a..42b027f203 100644 --- a/skills/objectstack-platform/rules/bootstrap-patterns.md +++ b/skills/objectstack-platform/rules/bootstrap-patterns.md @@ -4,9 +4,27 @@ Guide for bootstrapping ObjectStack projects with defineStack(). ## Basic Stack Configuration -There is **no `driver:` key** on `defineStack()` — unknown keys are silently -stripped by strict parsing, so a `driver:` entry is a no-op. Drivers are -plugins: wrap them in `DriverPlugin` and put them in `plugins:`. +There is **no `driver:` key** on `defineStack()`. Drivers are plugins: wrap +them in `DriverPlugin` and put them in `plugins:`. + +A `driver:` entry is **not** a harmless no-op. The top level of a stack +definition rejects undeclared keys, so the stack does not load: + +``` +defineStack validation failed (1 issue): + + ✗ (root): Unrecognized key(s) on this stack definition: `driver`. … + The declared keys are enumerated by `ObjectStackDefinitionSchema` + (@objectstack/spec, stack.zod.ts) and in the stack-definition + reference docs. +``` + +TypeScript refuses it earlier still, at compile time: + +``` +error TS2353: Object literal may only specify known properties, +and 'driver' does not exist in type 'ObjectStackDefinitionInput'. +``` The `manifest` requires `id`, `version`, `type`, and `name` (`ManifestSchema` is strict — a missing required field throws at @@ -66,12 +84,12 @@ There are no `@objectstack/adapter-*` packages. ## Incorrect vs Correct -### ❌ Incorrect — `driver:` Key (Silently Stripped) +### ❌ Incorrect — `driver:` Key (Rejected at Load) ```typescript export default defineStack({ manifest: { id: 'com.example.app', version: '1.0.0', type: 'app', name: 'App' }, - driver: new DriverPlugin(new InMemoryDriver()), // ❌ Not a defineStack key — no-op + driver: new DriverPlugin(new InMemoryDriver()), // ❌ Not a defineStack key — defineStack throws objects: [/* ... */], }); ```