You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* fix(spec): Field.autonumber declares readonly: true (#5628)
`FieldSchema.readonly` is a two-part contract: "never editable in forms" AND
server-enforced on both write paths. #5503 closed the server half for
`autonumber` BY TYPE — a caller-supplied record number is stripped before any
driver sees it, flag or no flag. The form half is keyed on the FLAG, and the
builder never set it, so a renderer deciding editability from `field.readonly`
drew an editable "record number" input whose value the server was already
guaranteed to discard.
`Field.autonumber(...)` now emits `readonly: true`, applied AFTER the author's
config so it cannot be spread away, with the authoring type narrowed to
`readonly?: true` — `Field.autonumber({ readonly: false })` is a compile error
at the metadata site rather than a silently coerced value. A hand-written
`{ type: 'autonumber' }` literal is unaffected: it is covered by the by-type
server enforcement, which never depended on the flag.
Measured side effect, neutralized in the same change: the DataProtocol create
ingress (`stripReadonlyForInsert`, #3043) knows only the `isSystem` exemption,
while the engine's runtime-owned strip also honours `preserveAudit` (#3493).
With the flag present the ingress would have deleted a historical import's
legacy record number BEFORE the engine could keep it — and no test would have
gone red, because every existing preserveAudit pin calls `engine.insert`
directly. The ingress now skips runtime-owned field types outright and leaves
them to the engine strip, which runs on every insert path including the direct
`engine.insert` callers the ingress never sees. Author-declared `readonly` on
every other type keeps its full #3043 width.
The backing set moves to `@objectstack/spec/data` as
`RUNTIME_OWNED_FIELD_TYPES` — the protocol's one statement of the ownership —
now that a second consumer needs it; objectql keeps the reasoning comment and
imports the membership.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011M7UwH25Unfi73UHim7ajY
* chore(spec): finish the post-merge wholesale regen (docs references, api-surface)
Recovery commit: completes the regen the dev agent never reached before
the container restart. check:generated 10/10.
* test(objectql): type the new runtime-owned ingress cases cleanly
check:type-check-debt --re-measure caught +3 in objectql's TEST_DEBT
layer (355 -> 358): the new cases copied the file's frozen-debt idioms —
one-arg registerObject (packageId is required) and .at() under the
package's lib target. Fixed to the file's clean two-arg idiom and indexed
access; raw count back to 355, the 32-case suite stays green.
---------
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments