From 5e075eb788ddc67c8d7d73deafec5cf62d1e77ba Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Aug 2026 18:13:53 +0000 Subject: [PATCH 1/2] docs(skills): objectstack-platform states load-time refusal, not silent stripping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An unknown top-level `defineStack` key has thrown since the outermost strict door closed; the published platform skill still taught that it was silently stripped and therefore a harmless no-op. The direction of that error is the harmful one: it ranks a stack that does not load as cosmetic. Four sites corrected, all re-measured against the built `@objectstack/spec`: - rules/bootstrap-patterns.md — the `driver:` mechanism sentence, the "(Silently Stripped)" heading, and the inline "no-op" comment. The prescription (drivers are plugins) is unchanged; only the stated mechanism moves, and it now quotes the real load-time and TS2353 output. - SKILL.md — the blanket "unknown keys are silently stripped" sentence is replaced by the measured per-surface split (refused vs warned-then-dropped) rather than flipped wholesale. - SKILL.md — the feature-flags aside repeating the same stale claim. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01AeA3nU1B5Q2pgxqxgUrexd --- skills/objectstack-platform/SKILL.md | 27 ++++++++++++++++-- .../rules/bootstrap-patterns.md | 28 +++++++++++++++---- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/skills/objectstack-platform/SKILL.md b/skills/objectstack-platform/SKILL.md index 380e749396..e799e53116 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: `roles`. … +``` + +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: [/* ... */], }); ``` From 8e1b43c0122114c2b53f0d99a6edfbfd5fd06bf9 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 02:20:52 +0000 Subject: [PATCH 2/2] docs(skills): use `policies` as the phantom-key example in the quoted refusal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The quoted defineStack refusal used the ADR-0090 D3 reserved word as its example key, which added a third occurrence to a file baselined at two and red-lit check:role-word. The sibling example in the sentence above it is already `policies:`, so the quote now uses that instead. Not an edited quote: the refusal was re-measured live against the built @objectstack/spec with `policies` as the offending key, and the output is reproduced as measured. The two pre-existing occurrences are untouched, and the baseline is not modified — the ratchet returns to 2 by removing the new occurrence, which is the author-side remedy. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01AeA3nU1B5Q2pgxqxgUrexd --- skills/objectstack-platform/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/objectstack-platform/SKILL.md b/skills/objectstack-platform/SKILL.md index e799e53116..06f724c755 100644 --- a/skills/objectstack-platform/SKILL.md +++ b/skills/objectstack-platform/SKILL.md @@ -192,7 +192,7 @@ 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: `roles`. … + ✗ (root): Unrecognized key(s) on this stack definition: `policies`. … ``` Undeclared keys are handled per surface, and the two postures are worth