diff --git a/.changeset/skill-hook-condition-aborts.md b/.changeset/skill-hook-condition-aborts.md new file mode 100644 index 0000000000..f7cbcd79c6 --- /dev/null +++ b/.changeset/skill-hook-condition-aborts.md @@ -0,0 +1,31 @@ +--- +--- + +Docs-only: the `objectstack-data` skill's hook reference taught the pre-17 +failure mode for an unevaluable `condition`. + +`skills/objectstack-data/references/data-hooks.md` had been updated for #4770 +(the condition reads the record, not the payload) and #4784 (`previous` is +bound), but its closing bullet still said an undeclared key leaves the condition +"logged at WARN and treated as false" — the behaviour #4775 replaced. An +unevaluable condition now **aborts the operation**. + +This is the AI-authoring reference for hooks, so the stale sentence pointed the +wrong way on the one axis that matters: it told an author a typo is a soft +failure. It also silently downgraded the two bullets above it — `previous` is +unbound on inserts and on `multi: true` writes, and `has()` is not a null guard — +from "this breaks your write" to "this quietly disables your hook". + +Replaced with a callout carrying the #4775 rule and the reason the two outcomes +had to split (a `before*` guard swallowed into `false` lets writes through; an +audit hook swallowed into `false` drops records — opposite failures), plus the +practical authoring consequence. + +Swept the rest of `skills/` and `.claude/skills/` against the same rc.2 window; +nothing else was stale. `objectstack-automation` already documents #4343's +`script`-node retirements, `objectstack-query` already carries the #4286 +`cursor` / `joins` / `windowFunctions` prescriptions, and +`objectstack-formula` already documents #4649 fail-closed predicates and #4763's +build-time `has()` rejection. + +Releases nothing. diff --git a/skills/objectstack-data/references/data-hooks.md b/skills/objectstack-data/references/data-hooks.md index 3d1b19d1d6..9a0bacfdb8 100644 --- a/skills/objectstack-data/references/data-hooks.md +++ b/skills/objectstack-data/references/data-hooks.md @@ -260,8 +260,21 @@ in neither). So: `has(record.spent) && record.spent > record.budget` still faults on `null > null`. `has()` answers "is this key declared at all", which is a question about your spelling, not about your data. -- An **undeclared** key (a typo) stays unevaluable: the condition is logged at - WARN and treated as false. + +⚠️ **An unevaluable condition ABORTS the operation (#4775).** A typo'd key +(`record.stauts`), a `previous` reference on an insert, or a comparison CEL has +no overload for does **not** degrade to "the hook did not fire" — it **fails the +write**. Until protocol 17 the gate emitted a `logger.warn` and returned `false`, +which is why the two bullets above are load-bearing rather than stylistic: a +`before*` guard swallowed into `false` silently let writes through, and an audit +hook swallowed into `false` silently dropped records. Those are opposite +failures, so "the condition said no" and "the platform could not work out what +the condition says" are now different outcomes and the second one is loud. + +Practical consequence when authoring: spell keys against the object's **declared** +fields, and never reach for `previous` in a hook that can fire on insert or on a +`multi: true` write — that mistake used to cost you a hook that quietly never +ran, and now costs you every write the hook is attached to. #### `onError` — Error Handling