Skip to content

docs(spec): strictReadonlyWrites 契约不再宣称 INSERT 对其惰性 —— #5503 已让 insert 拒绝 runtime-owned 值 (#7064) - #7109

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-7064-strict-insert-contract
Aug 9, 2026
Merged

docs(spec): strictReadonlyWrites 契约不再宣称 INSERT 对其惰性 —— #5503 已让 insert 拒绝 runtime-owned 值 (#7064)#7109
os-project-manager merged 1 commit into
mainfrom
claude/issue-7064-strict-insert-contract

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes #7064

问题

packages/spec/src/contracts/data-engine.tsstrictReadonlyWrites TSDoc 的收尾段落仍断言:

INSERT ignores it, for the same reason onFieldsDropped never fires there: insert is exempt from both strips, so there is nothing to refuse.

这句话在 #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:

探针 输入 实测结果
A:strict + runtime-owned { name, account_number: 'ACC-777777' } + strictReadonlyWrites: true 抛出 ReadonlyFieldRejectedError:code = ERR_READONLY_FIELD_REJECTED,operation = 'insert',fields = ['account_number'],drops[0].reason = 'readonly',消息以 "Insert on 'probe7064' was REFUSED" 开头并点名 isSystem / preserveAudit;驱动零写入,onFieldsDropped 未触发
B:非 strict 对照 同上负载,仅 onFieldsDropped 监听 写入完成(序列值 ACC-0001,伪造值被剥离),事件 { fields: ['account_number'], reason: 'readonly' }
C:author-declared readonly 对照 { locked_note: 'set-at-create' }(readonly: true 字段)+ strict 不抛错、无事件、调用方初值落库 —— #3413 的 create 豁免在本 seam 成立

探针 C 是防止重写过度声明的关键:insert 只拒绝 runtime-owned 值,author-declared 两类剥离在 engine seam 上仍豁免 create。

改动(仅 prose,三处,同一文件)

  1. 接口头注释:剥离原因枚举补上 [17.0-rc2验收] autonumber 字段可被普通调用者改写:POST 提交显式值绕过序列、PATCH 直接改号落库 —— readonly 剥离不保护 type:'autonumber' #5503 的 runtime-owned 剥离(唯一同样作用于 INSERT 的一类)。
  2. Semantics 段:注明 runtime-owned 剥离自 [17.0-rc2验收] autonumber 字段可被普通调用者改写:POST 提交显式值绕过序列、PATCH 直接改号落库 —— readonly 剥离不保护 type:'autonumber' #5503 起同样汇报在 'readonly' reason 臂下。
  3. 收尾段整段重写为 "INSERT — refuses runtime-owned values (since [17.0-rc2验收] autonumber 字段可被普通调用者改写:POST 提交显式值绕过序列、PATCH 直接改号落库 —— readonly 剥离不保护 type:'autonumber' #5503)":保留 dated 注记(旧句写作时为真、被 [17.0-rc2验收] autonumber 字段可被普通调用者改写:POST 提交显式值绕过序列、PATCH 直接改号落库 —— readonly 剥离不保护 type:'autonumber' #5503 证伪,但不再原文复述旧句,避免给未来的 census grep 重新埋一份过期断言);正文与既有词汇对齐 —— 引用 ReadonlyFieldRejectedError 自身文档("Thrown by engine.update — and, since [17.0-rc2验收] autonumber 字段可被普通调用者改写:POST 提交显式值绕过序列、PATCH 直接改号落库 —— readonly 剥离不保护 type:'autonumber' #5503, by engine.insert")、错误消息点名的豁免写入方(isSystempreserveAudit data 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-declared readonly 策略(#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/ 全树 grep strictReadonlyWrites 及四种拼写均零命中)。
  • 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 用例全绿。
  • pin-coverage 双向检索:没有任何测试引用被改句子的新旧拼写,改动双向均不使任何用例变红 —— 这符合预期(纯 prose),证据即三探针矩阵(fix(spec): stop teaching the retired ETL layer as a live retry surface in flow.zod.ts (#6630, part 2) #6753 式如实声明)。
  • node scripts/check-nul-bytes.mjs OK;被改文件控制字节自扫 clean。

范围外记录(未在本 PR 处理)

🤖 Generated with Claude Code

https://claude.ai/code/session_018ffcE95NaMJcL9XJ9VDYgk


Generated by Claude Code

…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
@vercel

vercel Bot commented Aug 9, 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 Aug 9, 2026 4:18pm

Request Review

@github-actions github-actions Bot added the size/s label Aug 9, 2026
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

106 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 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 @objectstack/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/tenancy-modes.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 @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/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 @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/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/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/permissions/system-context.mdx (via packages/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/http-protocol.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/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/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.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/field-grouping-and-order.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)

7 release-owned page(s) also reference the affected code. These are read-only:

  • 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/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WriteObservabilityOptions.strictReadonlyWrites still documents "INSERT ignores it", but #5503 wired insert to refuse

2 participants