Found while fixing objectui#6041 / objectui#6044 (the field-level members of the #5761 parity family). Filed, not fixed — out of the scope of those cards, and each key plausibly takes a different correct resolution, which is the #5761 ruling.
The measurement
The gate built for #5761 (scripts/check-designer-field-key-parity.mjs) compares declared payload keys against FieldSchema. Its PAYLOAD_SHAPES list contains three field shapes and no object shape, so nothing checks the parent document the designers actually PUT.
Measured against the installed @objectstack/spec 17.2.0, ESM build (dist/data/index.mjs), on origin/main @ 7da7b8a1d:
const base = { name: 'account', label: 'Account', fields: { n: { type: 'text', label: 'N' } } };
ObjectSchema.safeParse(base) => success = true (control)
ObjectSchema.safeParse({ ...base, isSystem: true }) => success = true (control)
ObjectSchema.safeParse({ ...base, pluralLabel: 'A' }) => success = true (control)
ObjectSchema.safeParse({ ...base, group: 'Sales' }) => success = false
unrecognized_keys keys=["group"]
ObjectSchema.safeParse({ ...base, sortOrder: 3 }) => success = false
unrecognized_keys keys=["sortOrder"]
ObjectSchema.safeParse({ ...base, relationships: [ … ] }) => success = false
unrecognized_keys keys=["relationships"]
ObjectSchema's accept set is 42 keys and contains none of the three. The controls matter: isSystem and pluralLabel are accepted, so this is a real key-by-key result and not a schema that refuses everything.
The writers
Both are on the wire — the body of PUT /api/v1/meta/object/:name.
packages/app-shell/src/services/MetadataService.ts — ObjectMetadataPayload declares group, sortOrder and relationships; toObjectPayload populates all three and saveObject PUTs it.packages/plugin-designer/src/MetadataObjectsPage.tsx — the merged ServerObjectSchema written on save carries group verbatim.
group is the live one: the Object Manager renders a grouping control, and toObjectDefinition populates group unconditionally ('System Objects' / 'Custom Objects' in metadataConverters, raw.group in MetadataObjectsPage). So saving an object through the designer looks like the exact shape #5761 describes — a hard 422 INVALID_METADATA that then blocks every later save of that object, with nothing in the UI to say which key did it. Whether it is live today depends on what the deployed route parses with, which is worth measuring rather than assuming — this issue reports the schema fact, not a reproduced HTTP response.
Why this is not a mechanical rename
Same reason #5761 gave for the field-level keys, and the reason it ruled one card per key:
Suggested shape of the fix
Extend PAYLOAD_SHAPES with the object-level shapes and give the gate a second oracle (ObjectSchema alongside FieldSchema), so the class is closed one level up rather than three more tombstones being written after the fact. The gate's ledger already ratchets in both directions and would carry these three the same way it carries formula and sortOrder.
Refs: #5761 (the gate) · #6041 · #6044 · #6045 · #4644 · #4687 · #4676
Found while fixing objectui#6041 / objectui#6044 (the field-level members of the #5761 parity family). Filed, not fixed — out of the scope of those cards, and each key plausibly takes a different correct resolution, which is the #5761 ruling.
The measurement
The gate built for #5761 (
scripts/check-designer-field-key-parity.mjs) compares declared payload keys againstFieldSchema. ItsPAYLOAD_SHAPESlist contains three field shapes and no object shape, so nothing checks the parent document the designers actually PUT.Measured against the installed
@objectstack/spec17.2.0, ESM build (dist/data/index.mjs), onorigin/main@7da7b8a1d:ObjectSchema's accept set is 42 keys and contains none of the three. The controls matter:isSystemandpluralLabelare accepted, so this is a real key-by-key result and not a schema that refuses everything.The writers
Both are on the wire — the body of
PUT /api/v1/meta/object/:name.packages/app-shell/src/services/MetadataService.ts—ObjectMetadataPayloaddeclaresgroup,sortOrderandrelationships;toObjectPayloadpopulates all three andsaveObjectPUTs it.packages/plugin-designer/src/MetadataObjectsPage.tsx— the mergedServerObjectSchemawritten on save carriesgroupverbatim.groupis the live one: the Object Manager renders a grouping control, andtoObjectDefinitionpopulatesgroupunconditionally ('System Objects'/'Custom Objects'inmetadataConverters,raw.groupinMetadataObjectsPage). So saving an object through the designer looks like the exact shape #5761 describes — a hard 422INVALID_METADATAthat then blocks every later save of that object, with nothing in the UI to say which key did it. Whether it is live today depends on what the deployed route parses with, which is worth measuring rather than assuming — this issue reports the schema fact, not a reproduced HTTP response.Why this is not a mechanical rename
Same reason #5761 gave for the field-level keys, and the reason it ruled one card per key:
group— the spec hasfieldGroups(field grouping) and no object-level grouping key. It may belong upstream (the Both field designers authorplaceholder, a key FieldSchema rejects by name — but the designer's own preview renders it, so this is a contract question not a deletion #4676 resolution), or the designer's grouping may be a UI-only concern that must not reach the payload at all.sortOrder— no spec equivalent; likely the finding(types): VectorFieldMetadata has two declared keys FieldSchema rejects —indexedanddistance_metric#4687 resolution (delete the declaration), and it is the object-level twin of objectui#6045.relationships— the spec models relationships through field-levelreference/master_detailplusindexes, so this one is a data-model question, not a spelling one.Suggested shape of the fix
Extend
PAYLOAD_SHAPESwith the object-level shapes and give the gate a second oracle (ObjectSchemaalongsideFieldSchema), so the class is closed one level up rather than three more tombstones being written after the fact. The gate's ledger already ratchets in both directions and would carry these three the same way it carriesformulaandsortOrder.Refs: #5761 (the gate) · #6041 · #6044 · #6045 · #4644 · #4687 · #4676