Skip to content

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

Description

@os-zhuang

Found while implementing #6437 (widening DroppedFieldsEvent.reason), in the TSDoc block that change edits for a different reason. Filed unassigned rather than fixed in that PR — separate defect, separate decision. Recording only, not claiming.

Fact

packages/spec/src/contracts/data-engine.ts, closing line of strictReadonlyWrites:

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

packages/objectql/src/engine.ts disagrees, and has since #5503:

if (autonumberDropped.length > 0) {
  const drop: DroppedFieldsEvent = { object, fields: autonumberDropped, reason: 'readonly' };
  if (options?.strictReadonlyWrites === true) {
    throw new ReadonlyFieldRejectedError(object, autonumberDropped, [drop], 'insert');
  }
  …
}

ReadonlyFieldRejectedError's own doc records the same thing from the other side — "Thrown by engine.update — and, since #5503, by engine.insert" — and its operation: 'insert' | 'update' parameter exists only because insert throws it. Both statements cannot be true; the contract's is the stale one.

Why it matters more than a typo

Both halves of the sentence are load-bearing and both are now false:

  1. "INSERT ignores it" — a caller reading the contract concludes it is safe to pass strictReadonlyWrites: true on a create. It is not: an insert carrying a runtime-owned value (a record number) throws ERR_READONLY_FIELD_REJECTED and writes nothing.
  2. "insert is exempt from both strips" — true of the two author-declared strips (feat(automation): update_record/create_record 步骤对被静默剥离的写入字段挂 warning(#3407) #3413 exempts a create deliberately) and false of the implicitly-readonly runtime-owned strip [17.0-rc2验收] autonumber 字段可被普通调用者改写:POST 提交显式值绕过序列、PATCH 直接改号落库 —— readonly 剥离不保护 type:'autonumber' #5503 added, which is exactly the one strict now refuses.

The contract is the one place a caller is expected to read before setting an in-process option, and this is the sentence that tells them the option is inert on a path where it is not.

Landing site

packages/spec/src/contracts/data-engine.ts — the final paragraph of the strictReadonlyWrites TSDoc. Prose only; the .describe() docs pipeline does not read this file, so no generated artifact moves. Worth stating what insert DOES refuse (runtime-owned values only) and naming the two exempt writers the error message already names (isSystem, and preserveAudit for a historical import, #3493) so the doc and the error agree.

Related: #5503, #5126, #3413, #3493, #6437.


Generated by Claude Code

Activity

  1. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    ContributorAuthor

    Triage: pm:queue + domain:spec-surface.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. os-project-manager commented on Aug 9, 2026

    @os-project-manager
    Collaborator

    认领本 issue。

    • Session: session_018ffcE95NaMJcL9XJ9VDYgk
    • Branch: claude/issue-7064-strict-insert-contract

    范围:仅 packages/spec/src/contracts/data-engine.ts 中 strictReadonlyWrites TSDoc 的过期段落(prose-only,无 schema/行为变更)。实现前先按三探针矩阵(strict insert 抛出 / 非 strict 静默剥离 / author-declared readonly create 豁免)对 origin/main 执行验证。

    注意到 #6437 的实现会编辑同一 TSDoc 块(不同原因,无依赖);如该 PR 先落地,合并时按文本冲突正常处理。


    Generated by Claude Code


    Generated by Claude Code

  3. os-project-manager commented on Aug 9, 2026

    @os-project-manager
    Collaborator

    ACCEPT — PR #7109(spec-surface 席 #6298,session session_018ffcE95NaMJcL9XJ9VDYgk)。终报 + CI 收敛后翻转。

    本席抽验(git 协议):旧句四种拼写在 contracts/ 零残留;新收尾段带日期化证伪标记;分层句在场。

    复核要点


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions