Skip to content

finding: the docs teach catch it by code for ReadonlyFieldRejectedError but still do not name the constant #16159 now publishes #16281

Description

@claude

Filed by the domain:engine execution seat while landing slice 2 of #16159 (ERR_READONLY_FIELD_REJECTED). ⛔ Observation, not a runtime defect — no assignee, no pm:queue; triage grades it. Deliberately not ridden on that PR: the dispatch fenced the docs page out, and the reason it gives is right — the sentence in question becomes followable, not false.

Blocked-by: #16159

The observation

content/docs/kernel/contracts/data-engine.mdx:361 tells readers, of ReadonlyFieldRejectedError:

Catch it by code, not instanceof, and read drops for the per-reason breakdown; the code is stable across reasons deliberately, so adding a reason never adds an error code.

That instruction was already true and is now followable: @objectstack/objectql publishes READONLY_FIELD_REJECTED_CODE as of #16159's slice 2. The page still does not say so, so a reader following its advice writes the string themselves — which is the exact cost #16159 exists to remove, and which acquires a check:error-code-provenance stamp site in the reader's own package.

The same shape will apply to every remaining row of #16159's table as the sweep lands: ERR_DRIVER_CONNECT, ERR_DATASOURCE_UNAVAILABLE, ERR_SUMMARY_RECOMPUTE, ERR_TRANSACTION_UNSUPPORTED, ERR_CROSS_DATASOURCE_TRANSACTION_WRITE. ⇒ this is deliberately one card for the whole sweep rather than one per slice, so it does not need re-filing five more times.

What was measured, on origin/main at 07a43dc74 plus slice 2's branch

reading value control
files in content/docs naming ERR_READONLY_FIELD_REJECTED 3 (kernel/contracts/data-engine.mdx, references/api/contract.mdx, references/api/error-code-ledger.mdx)
files in content/docs naming any *_CODE constant of this package 0 firing control @objectstack/objectql = 12 files; negative control (a token that does not exist) = 0
files in content/docs naming ReadonlyFieldRejectedError 1

no page goes stale by the conversions, and none of the three pages is wrong today. This is an affordance the documentation could now point at, not a correction it needs.

Why it is worth a card rather than a shrug

The card that produced it (#16159) argues its whole case from this page: "the published guidance and the published surface disagree today, in the documentation's own words". Landing the constant closes half of that — the surface now offers what the guidance assumes — and leaves the other half in place, because the guidance still does not name what it is now possible to import. A reader who does what the page says still ends up re-spelling the literal.

Suggested shape, for triage rather than a ruling

A clause naming the constant beside the existing instruction, e.g. "…catch it by codeREADONLY_FIELD_REJECTED_CODE, exported from @objectstack/objectql — not instanceof…". ⚠️ Two things worth deciding rather than assuming: whether references/api/contract.mdx and references/api/error-code-ledger.mdx are generated projections (in which case the change belongs at their generator, not the page), and whether the right moment is per-row or once at the end of #16159's sweep, when all seven constants exist.

Refs: #16159 · #16260 · content/docs/kernel/contracts/data-engine.mdx


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions