Skip to content

Commit 1800ffa

Browse files
os-warrenclaude
andauthored
docs(skills): objectstack-platform states load-time refusal, not silent stripping (#10038)
* docs(skills): objectstack-platform states load-time refusal, not silent stripping 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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeA3nU1B5Q2pgxqxgUrexd * docs(skills): use `policies` as the phantom-key example in the quoted refusal 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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeA3nU1B5Q2pgxqxgUrexd --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent b8f1e98 commit 1800ffa

2 files changed

Lines changed: 47 additions & 8 deletions

File tree

skills/objectstack-platform/SKILL.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,29 @@ holds a collection of one metadata kind — `manifest`, `objects`,
186186
There is deliberately **no** top-level `workflows` or `approvals` collection:
187187
an approval is authored as a flow with Approval nodes (ADR-0019), and record
188188
state machines are a `state_machine` validation rule on each object
189-
(ADR-0020). Unknown keys are **silently stripped** by strict parsing — a
190-
phantom key like `roles:` or `policies:` is a no-op, not an error.
189+
(ADR-0020). A phantom key like `roles:` or `policies:` is **not** a silent
190+
no-op — the top level refuses it and the stack fails to load:
191+
192+
```
193+
defineStack validation failed (1 issue):
194+
195+
✗ (root): Unrecognized key(s) on this stack definition: `policies`. …
196+
```
197+
198+
Undeclared keys are handled per surface, and the two postures are worth
199+
keeping straight:
200+
201+
- **Refused**`defineStack()`'s top level, each `objects[]` entry
202+
(`ObjectSchema`), and each field (`FieldSchema`). The parse throws, naming
203+
the surface and the offending key. TypeScript rejects the literal earlier
204+
still, with `TS2353: Object literal may only specify known properties`.
205+
- **Warned, then dropped** — the authoring surfaces whose shapes have not
206+
been closed yet (`connectors` is one). `defineStack()` prints the warning
207+
before the parse, and the value does not survive it:
208+
`defineStack: connectors.stripe.bogusKey: 'bogusKey' is not a declared connector key, so its value is dropped at load.`
209+
Treat these as errors-in-waiting — closing the remaining shapes is a
210+
scheduled migration, so a key that only warns today is expected to be
211+
refused later.
191212

192213
For the exact Zod shape — including which keys are optional and what types
193214
the collection items take — read
@@ -1042,7 +1063,7 @@ const metrics = kernel.getPluginMetrics();
10421063
## Feature Flags
10431064

10441065
Feature flags are **not a spec/metadata concept**. There is no `featureFlags:` /
1045-
`features:` key on `defineStack` (strict parsing silently strips unknown keys), and the
1066+
`features:` key on `defineStack` (writing one is refused at load, not stripped), and the
10461067
former `FeatureFlagSchema` (`@objectstack/spec/kernel`) was removed — it had zero runtime
10471068
consumers, and its only protocol home (the static `ObjectStackCapabilities.system.features`
10481069
descriptor) was itself dead: no endpoint ever served it. Runtime capability discovery is

skills/objectstack-platform/rules/bootstrap-patterns.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,27 @@ Guide for bootstrapping ObjectStack projects with defineStack().
44

55
## Basic Stack Configuration
66

7-
There is **no `driver:` key** on `defineStack()` — unknown keys are silently
8-
stripped by strict parsing, so a `driver:` entry is a no-op. Drivers are
9-
plugins: wrap them in `DriverPlugin` and put them in `plugins:`.
7+
There is **no `driver:` key** on `defineStack()`. Drivers are plugins: wrap
8+
them in `DriverPlugin` and put them in `plugins:`.
9+
10+
A `driver:` entry is **not** a harmless no-op. The top level of a stack
11+
definition rejects undeclared keys, so the stack does not load:
12+
13+
```
14+
defineStack validation failed (1 issue):
15+
16+
✗ (root): Unrecognized key(s) on this stack definition: `driver`. …
17+
The declared keys are enumerated by `ObjectStackDefinitionSchema`
18+
(@objectstack/spec, stack.zod.ts) and in the stack-definition
19+
reference docs.
20+
```
21+
22+
TypeScript refuses it earlier still, at compile time:
23+
24+
```
25+
error TS2353: Object literal may only specify known properties,
26+
and 'driver' does not exist in type 'ObjectStackDefinitionInput'.
27+
```
1028

1129
The `manifest` requires `id`, `version`, `type`, and `name`
1230
(`ManifestSchema` is strict — a missing required field throws at
@@ -66,12 +84,12 @@ There are no `@objectstack/adapter-*` packages.
6684

6785
## Incorrect vs Correct
6886

69-
### ❌ Incorrect — `driver:` Key (Silently Stripped)
87+
### ❌ Incorrect — `driver:` Key (Rejected at Load)
7088

7189
```typescript
7290
export default defineStack({
7391
manifest: { id: 'com.example.app', version: '1.0.0', type: 'app', name: 'App' },
74-
driver: new DriverPlugin(new InMemoryDriver()), // ❌ Not a defineStack key — no-op
92+
driver: new DriverPlugin(new InMemoryDriver()), // ❌ Not a defineStack key — defineStack throws
7593
objects: [/* ... */],
7694
});
7795
```

0 commit comments

Comments
 (0)