fix(lint): 写集诊断如实描述驱动分歧,而非"静默丢弃" (#4271) - #4368
Merged
Merged
Conversation
…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>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
…-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
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…-8ae2c7 # Conflicts: # packages/spec/src/data/hook-body.zod.ts
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.
问题
hook-body-write-unknown-field和action-body-write-unknown-field三条诊断告诉作者:未声明的列 "silently never lands in the stored record"。在
main上实测,两个方向都是错的。实际行为
body 到 driver 之间没有任何一层过滤这个 key:
applyMutationsToInput(packages/runtime/src/sandbox/body-runner.ts)是纯Object.assign,未知 key 原样拷回 payload。validateRecord(packages/objectql/src/validation/record-validator.ts)insert 走已声明字段,update 是if (!def) continue—— 既不拒绝也不剥离。engine.ts把整行直接交给 driver。于是由 driver 决定,两个家族的结论相反:
table deal has no column named stagee)。什么都没存下,连拼写正确的字段也一起丢了,而报错出现在离作者错误很远的地方。所以 "silently never lands" 在 SQL 上是"响亮失败且丢掉整笔写入",在 schemaless 上是"确实落库了"。
为什么值得改
诊断信息如果错误描述了它所警告的故障,会教出错误的排查直觉:被告知"值会静默消失"的作者,不会把自己真正看到的 driver 报错和造成它的拼写错误联系起来;在 schemaless 上,也不会去找那个真的存在的游离 key。
改动
ctx.input写入)、:488(ctx.api写入)、validate-action-body-writes.ts:273(action)。ScriptBodySchema与ActionSchema.body的 JSDoc、reference-integrity-suite.test.ts的两处注释,以及两个尚未发布的 L2 hook body 写集不透明:把「写了目标对象上不存在的字段」从 accepted gap 变成作者时 lint 告警 #4271 changeset。@objectstack/spec仅改 JSDoc —— 无 schema、无生成物变更(spec 全量 279 文件 / 7160 测试通过可证)。与 #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 分支在那里,而beforeUpdatebody 只会把 flat-input envelope 混进被测对象。另含一个对照组:字段拼写正确时两种 driver 都正常落库。验证
check:type-check-coverage、check:doc-authoring、check:role-word、check:nul-bytes全绿;改动文件 ESLint 干净main(含 docs(hook-bodies): 写集一节改为准确的覆盖面描述 —— #4305/#4344 之后"没有静态检查"已不成立 (#4351) #4355 / fix(objectql,spec):filterfolds towhereon EVERY engine method;top/limitjoins the #3795 slot table (#4346) #4356 / fix(spec,rest,runtime): request bodies are checked against the schemas the catalog declares (#3899) #4322)后全部重跑🤖 Generated with Claude Code