Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .changeset/6609-declared-keys-header-honesty.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
---
---

Comment-only truthfulness fix in `@object-ui/types`; no published behaviour changes, no
schema change, no test-logic change.

`packages/types/src/__tests__/form-field-zod-coverage.test.ts` introduced its pinned key
list as "Every key `FormField` (../form.ts) declares by name". The interface declares one
key the list deliberately omits — `field`, the resolved object-field metadata stash
(objectui#3090) — so the sentence overclaimed, and the pin's own rule ("any schema edit
must touch the list here in the same PR") read as an invitation to close the gap by adding
`field` to `DECLARED_KEYS` and to `FormFieldSchema`. Doing that would make
`objectui validate` accept and type a runtime-only stash on authored documents,
re-opening the spec-vocabulary pun objectui#3090 closed at the `normalizeSectionField`
chokepoint — a contract widening arriving disguised as housekeeping.

The list header now says what the list is (the AUTHORABLE key surface) and records the
exclusion as deliberate, with the reason: the stash is runtime-only, and the same key
name in the authored spec form-view vocabulary is a string naming the referenced object
field. The `FormFieldSchema` doc comment in `packages/types/src/zod/form.zod.ts` carried
the same "keys mirror the interface" overclaim and is corrected the same way
(objectui#6609).
27 changes: 25 additions & 2 deletions packages/types/src/__tests__/form-field-zod-coverage.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,13 +22,36 @@
* objectstack#4075 mechanism — see check-spec-symbol-derivation.mjs, lie #3).
* A set-coverage assertion is the #3017 fallback for exactly this case: the
* zod side stays deliberate and reviewed, and any schema edit must touch the
* list here in the same PR.
* list here in the same PR. That list is the AUTHORABLE key surface, not every
* key the interface declares — one declared key sits outside it on purpose, for
* the reason its own note records (objectui#6609).
*/

import { describe, it, expect } from 'vitest';
import { FieldConstraintsSchema, FormFieldSchema } from '../zod/form.zod.js';

/** Every key `FormField` (../form.ts) declares by name, in declaration order. */
/**
* The AUTHORABLE key surface of `FormField` (../form.ts) — the keys a DOCUMENT
* may itself carry, and so the keys `objectui validate` parses through this
* schema. Ordered to follow the interface loosely, as a reading aid only: the
* assertion sorts both sides, so the order here carries no claim (`visibleOn`
* precedes `hidden`/`readonly` in the interface and follows them here).
*
* ⚠️ NOT "every key the interface declares by name", and the gap is DELIBERATE.
* `FormField` also declares `field` — the resolved object-field metadata stash
* (#3090), which the object-bound form paths fill at RUNTIME with a
* server-served field definition so widgets can read `precision`, `currency`,
* `reference_to`, … No document ever writes it. And on the SPEC form-view side
* — the other authoring surface, the one #3090 keeps separate — that same key
* name means something else entirely: a STRING naming the referenced object
* field. Admitting `field` here and to `FormFieldSchema` would therefore make
* `objectui validate` accept and type a runtime-only stash on authored
* documents, re-opening the exact spec-vocabulary pun #3090 closed at the
* `normalizeSectionField` chokepoint. The refusal is pinned below by the
* `still rejects the SPEC form-field vocabulary` case: `{ field: 'email' }`
* must not parse. So a `field` entry here is a contract widening to be ruled
* on — never housekeeping that restores consistency (objectui#6609).
*/
const DECLARED_KEYS = [
'id',
'name',
Expand Down
16 changes: 11 additions & 5 deletions packages/types/src/zod/form.zod.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -444,11 +444,17 @@ export const CommandSchema = BaseSchema.extend({
* different layers, and `normalizeSectionField` in `@object-ui/plugin-form` is
* the translation chokepoint between them (#3090).
*
* Keys mirror the `FormField` interface in `../form.ts`. Until #3090 this
* schema validated only 13 of the interface's declared keys and *required*
* `type` (the interface says optional) — so `objectui validate` silently
* ignored typos in `visibleWhen`/`widget`/`dependsOn`/… (strip mode) and
* rejected metadata the renderer accepts. The pinned key list lives in
* Keys mirror the AUTHORABLE surface of the `FormField` interface in
* `../form.ts` — not every key that interface declares. `FormField.field` (the
* resolved object-field metadata stash) is runtime-only and stays OUT of this
* schema on purpose: in the authored vocabulary that same key name carries a
* different meaning — a string naming the referenced object field — so
* validating it here would re-open the pun #3090 closed (objectui#6609).
*
* Until #3090 this schema validated only 13 of the interface's declared keys
* and *required* `type` (the interface says optional) — so `objectui validate`
* silently ignored typos in `visibleWhen`/`widget`/`dependsOn`/… (strip mode)
* and rejected metadata the renderer accepts. The pinned key list lives in
* `__tests__/form-field-zod-coverage.test.ts`.
*/
/**
Expand Down
Loading