Skip to content

fix(lint): 写集诊断如实描述驱动分歧,而非"静默丢弃" (#4271) - #4368

Merged
os-zhuang merged 6 commits into
mainfrom
claude/adoring-panini-8ae2c7
Jul 31, 2026
Merged

fix(lint): 写集诊断如实描述驱动分歧,而非"静默丢弃" (#4271)#4368
os-zhuang merged 6 commits into
mainfrom
claude/adoring-panini-8ae2c7

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

问题

hook-body-write-unknown-fieldaction-body-write-unknown-field 三条诊断告诉作者:未声明的列 "silently never lands in the stored record"。

main 上实测,两个方向都是错的

实际行为

body 到 driver 之间没有任何一层过滤这个 key:

  1. applyMutationsToInputpackages/runtime/src/sandbox/body-runner.ts)是纯 Object.assign,未知 key 原样拷回 payload。
  2. validateRecordpackages/objectql/src/validation/record-validator.ts)insert 走已声明字段,update 是 if (!def) continue —— 既不拒绝也不剥离。
  3. engine.ts 把整行直接交给 driver。

于是由 driver 决定,两个家族的结论相反:

Driver 实际结果
SQL 游离列进入 knex 语句,整笔写入失败table deal has no column named stagee)。什么都没存下,连拼写正确的字段也一起丢了,而报错出现在离作者错误很远的地方。
Schemaless(memory、MongoDB) driver 展开 payload,游离 key 确实被持久化,成为下游无人读取的未声明列。

所以 "silently never lands" 在 SQL 上是"响亮失败且丢掉整笔写入",在 schemaless 上是"确实落库了"。

为什么值得改

诊断信息如果错误描述了它所警告的故障,会教出错误的排查直觉:被告知"值会静默消失"的作者,不会把自己真正看到的 driver 报错和造成它的拼写错误联系起来;在 schemaless 上,也不会去找那个真的存在的游离 key。

改动

#4355 的关系:那个 PR 修的是散文档,本 PR 是同一处更正落在随包发布的面上 —— 作者真正读到的那条诊断,外加一个把它钉住的测试。

回归测试

新增 packages/runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts(6 个用例)。放在 packages/runtime,因为它同时依赖两个 driver 且拥有 body-runner.ts

insert 用例走完整链路 —— 真 QuickJS 沙箱 → 真 hook body → 真引擎 → 真 SQLite 表 —— 所以"未经过滤抵达 driver"是被证明而非假设的:若该路径上任何一层将来学会过滤,SQL 那半会停止抛错、测试转红。update 用例直接打引擎,因为 validateRecord 的 update 分支在那里,而 beforeUpdate body 只会把 flat-input envelope 混进被测对象。另含一个对照组:字段拼写正确时两种 driver 都正常落库。

验证

🤖 Generated with Claude Code

os-zhuang and others added 2 commits July 31, 2026 16:56
…a silent no-op (#4271)

`hook-body-write-unknown-field` and `action-body-write-unknown-field` told
authors the undeclared column "silently never lands in the stored record".
Measured on main, that is wrong in both directions.

Nothing between the body and the driver filters the key: `applyMutationsToInput`
is a plain `Object.assign`, and `validateRecord` walks declared fields on insert
and `continue`s past a key with no field def on update. So the driver decides —
SQL puts the stray column in the statement and the WHOLE write fails with a
driver-level error (nothing stored, error far from the authoring mistake), while
a schemaless driver spreads the payload and persists the stray key.

A lint that misdescribes the failure it warns about teaches the wrong debugging
instinct: an author told the value silently vanishes will not connect the driver
error they actually see to the typo that caused it, and on a schemaless driver
will not go looking for the stray key that is really there.

All three messages now state the split. The rule headers, the `ScriptBodySchema`
/ `ActionSchema.body` notes and the two still-unreleased #4271 changesets are
corrected to match. #4355 fixed the prose docs; this is the same correction on
the surfaces that ship in the packages.

Both outcomes are pinned by a new integration test,
`runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts`.
Its insert cases run the full chain — real QuickJS sandbox, real hook body, real
engine, real SQLite table — so "reaches the driver unfiltered" is proved rather
than asserted: if anything on that path learns to filter, the SQL half stops
throwing and the test goes red.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 31, 2026 9:57am

Request Review

…-8ae2c7

# Conflicts:
#	packages/lint/src/reference-integrity-suite.test.ts
#	packages/lint/src/validate-action-body-writes.ts
#	packages/spec/src/ui/action.zod.ts
@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests protocol:ui tooling labels Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/lint, @objectstack/spec.

107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/lint, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit 78caf51 into main Jul 31, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/adoring-panini-8ae2c7 branch July 31, 2026 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant