docs(spec): strictReadonlyWrites 契约不再宣称 INSERT 对其惰性 —— #5503 已让 insert 拒绝 runtime-owned 值 (#7064) - #7109
Conversation
…ores it (#7064) The closing paragraph of the strictReadonlyWrites TSDoc still asserted the option is inert on insert ('INSERT ignores it ... insert is exempt from both strips, so there is nothing to refuse') — true when #5126 shipped, false since #5503 wired engine.insert to REFUSE a payload carrying a runtime-owned value under strict, throwing ReadonlyFieldRejectedError (operation: 'insert') and writing nothing. Verified by execution against origin/main before rewriting (three-probe matrix): strict insert with an autonumber value throws ERR_READONLY_FIELD_REJECTED / operation 'insert' with nothing written; the same insert without strict silently strips and fires onFieldsDropped with reason 'readonly'; an author-declared readonly field on insert stays exempt at this seam (#3413) even under strict. Prose only: the interface header and the Semantics arm enumeration gain the runtime-owned strip (#5503), and the INSERT paragraph now states what insert refuses (runtime-owned values only), names the engine-level exempt writers the error message names (isSystem, preserveAudit #3493), and pins the layer boundary against the DataProtocol ingress policy (#3043/#6640) so the two never read as one rule. No key/type/behaviour change; all 10 spec generated artifacts verified unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ffcE95NaMJcL9XJ9VDYgk
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 7 release-owned page(s) also reference the affected code. These are read-only:
|
Fixes #7064
问题
packages/spec/src/contracts/data-engine.ts中strictReadonlyWritesTSDoc 的收尾段落仍断言:这句话在 #5126 落地时为真,自 #5503 起两个半句都为假:insert 携带 runtime-owned 值(如 autonumber 记录号)在
strictReadonlyWrites: true下会抛出ReadonlyFieldRejectedError(ERR_READONLY_FIELD_REJECTED,operation: 'insert')且什么都不写入。契约文件是调用方设置进程内选项前唯一会读的地方,恰恰是它在断言该选项在一条会抛错的路径上是惰性的(#6947 过期断言家族)。重写前先以执行验证(三探针矩阵,对 origin/main @ 0bffdae)
临时探针测试(未提交,已删除)基于
engine-autonumber-runtime-owned.test.ts的 rig,直接调用engine.insert:{ name, account_number: 'ACC-777777' }+strictReadonlyWrites: trueReadonlyFieldRejectedError:code = ERR_READONLY_FIELD_REJECTED,operation = 'insert',fields = ['account_number'],drops[0].reason = 'readonly',消息以 "Insert on 'probe7064' was REFUSED" 开头并点名isSystem/preserveAudit;驱动零写入,onFieldsDropped未触发onFieldsDropped监听{ fields: ['account_number'], reason: 'readonly' }{ locked_note: 'set-at-create' }(readonly: true字段)+ strict探针 C 是防止重写过度声明的关键:insert 只拒绝 runtime-owned 值,author-declared 两类剥离在 engine seam 上仍豁免 create。
改动(仅 prose,三处,同一文件)
'readonly'reason 臂下。ReadonlyFieldRejectedError自身文档("Thrown byengine.update— and, since [17.0-rc2验收] autonumber 字段可被普通调用者改写:POST 提交显式值绕过序列、PATCH 直接改号落库 —— readonly 剥离不保护 type:'autonumber' #5503, byengine.insert")、错误消息点名的豁免写入方(isSystem、preserveAuditdata import: a "historical" import can't preserve original timestamps / audit fields — updated_at is stamped now, readonly fields stripped on upsert (#3479 follow-up) #3493)、RUNTIME_OWNED_FIELD_TYPES(今日仅autonumber)。分层防线(按派发卡要求):重写明确标注
isSystem/preserveAudit豁免对是"本进程内 seam"的;DataProtocol ingress 对 create 的 author-declaredreadonly策略(#3043,preserveAudit在该层为 UPDATE-only,#6640,落地措辞见FieldSchema.readonly)是另一层,本段不放宽也不收窄。这一句是必要的:探针 C 实测 engine seam 上 create 可以播种 readonly 初值,而field.zod.ts告诉作者 create 不能 —— 两者只有分层表述才同时为真。全文 census
按四种拼写("ignores it" / "never fires there" / "nothing to refuse" / "exempt from both")做仓库级检索,含拼接缝形式:过期断言只有这一份(
data-engine.ts:84-85);onFieldsDropped成员注释及其它命中处描述的是别的仍为真的事实(hook 覆写键、isSystem update 等),未动。验证
pnpm --filter @objectstack/spec build && check:generated:全部 10 个生成物 gate 绿,工作树无生成物变动 —— describe 管线不读本文件,render-input 判定成立(content/docs/references/全树 grepstrictReadonlyWrites及四种拼写均零命中)。pnpm --filter @objectstack/spec typecheck:绿(test-typecheck ledger 58 文件 / 266 错误,前后 sha256 一致,零移动)。pnpm --filter @objectstack/spec test:354 文件 / 9250 用例全绿。pnpm --filter @objectstack/objectql test(探针在场时):164 文件 / 2796 用例全绿。node scripts/check-nul-bytes.mjsOK;被改文件控制字节自扫 clean。范围外记录(未在本 PR 处理)
content/docs/kernel/contracts/data-engine.mdx未复述本过期断言,但其WriteObservabilityOptions小节整体停在 [决策] readonly 剥离的 strict/reject 模式落在哪一层 —— B(WriteObservabilityOptions)推荐,A/C/D 各有代价(#4903 后续) #5126 之前:代码块只有onFieldsDropped,完全未提strictReadonlyWrites,剥离原因枚举也缺 [17.0-rc2验收] autonumber 字段可被普通调用者改写:POST 提交显式值绕过序列、PATCH 直接改号落库 —— readonly 剥离不保护 type:'autonumber' #5503。按派发卡属另一卡类,已评论记录在同文件的开放卡 docs:data-engine.mdxstill documentsEngineQueryOptions.cursorand query-leveldistinct— both retired by #4286 #7057。🤖 Generated with Claude Code
https://claude.ai/code/session_018ffcE95NaMJcL9XJ9VDYgk
Generated by Claude Code