docs(skills): formula §5 绑定作用域表补上「condition 求不出值 = 该次写入失败」(#4814) - #4906
Merged
xuyushun441-sys merged 1 commit intoAug 3, 2026
Merged
Conversation
…ition fails the write (#4814) The `objectstack-formula` skill's `previous` binding-scope table listed exactly where `previous` is unbound and then closed with "makes the whole expression unevaluable" — the pre-17 outcome (warn + hook does not fire). #4775 changed that outcome to aborting the operation, so the table's rows changed meaning without a word of the table changing. Adds the #4775 rule (before*/after* same direction, error names hook and key, onError is not an escape) and the #4800/B1 cell in full: one `previous.*` condition fails every predicate bulk update of that object, with a diagnosis instead of `No such key: previous`, and a record-change flow trigger is not a way around it. Plus a pointer under the legacy → CEL table, since `OLD.x` / `ISCHANGED(x)` are how a migrating author arrives at `previous.x`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
xuyushun441-sys
marked this pull request as ready for review
August 3, 2026 15:13
xuyushun441-sys
enabled auto-merge
August 3, 2026 15:13
xuyushun441-sys
deleted the
claude/issue-4814-formula-skill-condition-failure-scope
branch
August 3, 2026 15:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4814
skills/objectstack-formula/SKILL.md§5 的previous绑定作用域表,把「在哪儿不绑定」列得很齐,然后用一句 pre-17 的后果收尾:#4775 合入之后这句话所描述的世界已经不存在了:求不出值不再是 warn + hook 不触发,而是抛错并中断该次写入。也就是说,表里每一行的含义都变了,而表一个字没动 —— 正是本单要修的漂移。
补了哪两格
1. fail loud 的后果(#4775) —— 紧跟表格加了一条⚠️ 说明:求不出值(拼错的 key、已退役字段、CEL 没有重载的比较、以及在不绑定处引用
previous)不会降级成「这条 hook 没触发」,而是让这次写入失败,错误点名 hook 与 key;before*与after*同一方向;onError不是逃生口(它管的是 handler 抛错,而 condition 求值发生在任何 handler 之前);编译不过的 condition 同样中断。并保留了「为什么两种结果必须分开」的理由 —— guard 被吞成false会放行本该被拦的写入,审计 hook 被吞成false会漏记,这是一个结果压住的两种相反失败。2. #4800/B1 那一格 —— 表里
multi: true那一行补全:批量路径上record也只是裸 payload,所以这次写入没设置的已声明字段同样求不出值。表下另起一段写清代价:某对象上只要有一条引用previous.*的 hook 条件,该对象的每一次批量更新都会失败,且失败点名一个与这次写入无关的 hook;fail loud 在这里不开例外,但错误是专门诊断而不是裸No such key: previous(点名这是 predicate 批量写、说明 N 行没有单一前置记录、给出两条出路:去掉previous,或按 id 单记录写入);并明确写出 record-change flow trigger 不是出路 —— 它绑的是同一批生命周期 hook,拿到的是同样未绑定的previous。3. 顺带一处指路 —— legacy → CEL 机械翻译表下加了一条 blockquote:
OLD.x/ISCHANGED(x)都落到previous.x,而previous只在绑定处存在(见 §5),insert 事件与multi: true批量上不绑定、#4775 之后是写入失败。理由见下。表的实际结构与议题描述不一致(如实报告)
议题正文把它写成「§5 的
ISCHANGED(x)→previous.x != record.x迁移表」,像是一张表。实际文件里是两张表、两个不同章节:## Mandatory patterns for AI emission→### 5. Update hook condition — previous vs record(约 288–330 行)previous在哪儿绑定/不绑定,三行),以及紧随其后的那句后果说明## Mechanical translation table (legacy → CEL)(约 355 行起,独立顶层章节)OLD.x→previous.x、ISCHANGED(x)→previous.x != record.x的迁移表所以两格补在 §5 的绑定作用域表(那才是讲后果的地方),而迁移表那边只加一条指向 §5 的 blockquote —— 迁移表恰恰是读者到达
previous.x的入口,只改 §5 会漏掉从迁移表照抄下来的那条路径。#4861 的复核评论也明确要求「表格那一行与紧随其后那句话的口径都要改」,已照此办理。措辞来源
skills/objectstack-formula/SKILL.md§5 该补的那一行已写进给 PM 的报告,由 #4814 在对侧车道补上」—— 那份报告不在任何 PR/issue 正文或评论里,#4775 的九条评论与 #4861 的评论都没有它。没有编造一段冒充原文,措辞取自三个可核对的来源:skills/objectstack-data/references/data-hooks.md的 hook 的condition求不出值时:全局 fail loud —— 抛错并中断该次操作(方案 B 已拍板;Blocked-by #4770) #4775 callout(由 PR docs(skills): an unevaluable hook condition aborts the write (#4775) #4883 落地),本次直接沿用它的句式与论证("does not degrade to…it fails the write"、两种相反失败的解释、"opposite failures"、practical consequence 一段)。这是仓内已发布的 skill 面对同一条规则的既有口径,两处 skill 用同一套话正是本单要保的东西。packages/objectql/src/hook-wrappers.ts的unevaluableConditionError/uncompilableConditionError(B1 分支的原话:predicate bulk write / 无单一前置记录 / 两条出路 / flow trigger 不是出路),以及cel-fault.ts与 validation 谓词共用错误形状这一事实。before*/after*同一方向、不接onError、编译不过同样阻断)与 批量写上 hook 的 previous:B1 已拍板(fail loud 无例外,并入 #4775);本条转为「批量写 hook 按行触发」设计卡孵化点 #4800/B1 的拍板评论。即:文档措辞与实现文案同源,而不是我自己重述一遍。
验证
node scripts/check-doc-authoring.mjs✓ doc authoring guard: 215 files cleannode scripts/check-role-word.mjsOK (43 baselined file(s), no new occurrences)node scripts/check-nul-bytes.mjsOK (2985 tracked source file(s), no raw NUL bytes)pnpm --filter @objectstack/spec check:skill-docs✅ Skill docs in syncpnpm --filter @objectstack/spec check:skill-refs✅ 9 generated files in sync with packages/specpnpm --filter @objectstack/spec check:skill-examples✅ 201 prose examples type-check against @objectstack/specpnpm --filter @objectstack/spec check:generated✓ All 8 generated artifacts are up to date.无需重新生成任何产物(本次只改 SKILL.md 正文,未动 frontmatter,
gen:skill-docs/gen:skill-refs均已在同步状态)。范围
改动仅
skills/objectstack-formula/SKILL.md+ 一个 changeset,共 35 行新增 / 5 行删除。content/docs/releases/一个字未碰;未动packages/**、content/docs/**、其他 skill。changeset 用空 frontmatter(先例:.changeset/skill-hook-condition-aborts.md、.changeset/skills-definehook-examples.md—— 同为 skills-only 文档改动),不发布任何包。草稿状态,未 enable auto-merge、未 undraft,由 PM 复核后决定。
Generated by Claude Code