Found while implementing objectui#6240, which closed both of these in the OTHER object writer (app-shell's MetadataService). Filed rather than folded in: it is a different package and a different file, and objectui#6240's dispatch fenced its file face to MetadataService.ts and its tests.
The code
packages/plugin-designer/src/MetadataFieldsPage.tsx, handleFieldsChange:
constnextFields: Record<string,ServerFieldSchema>={};for(constfofnext){nextFields[f.name]=fromDesignerField(f,prevFields[f.name]);}Two hazards, both of them silent.
1. A field with no name keys as the literal string "undefined"
DesignerFieldDefinition.name is declared required, but this page is handed whatever the in-memory designer model holds. The spec does not catch it. Measured against the installed @objectstack/spec 17.2.0:
ObjectSchema.safeParse({ name: 'account', label: 'Account',
fields: { undefined: { type: 'text', label: 'N' } } })
=> success = true
So a nameless field produces a document that PARSES, is STORED, and has no reader anywhere — a silently corrupt object rather than a loud refusal. objectui#6240 resolved this in MetadataService by throwing before the request is issued, with the measurement above as the reason.
2. A field named __proto__ is dropped by the assignment itself
nextFields['__proto__'] = … invokes the prototype setter instead of creating a key, so the field disappears from the serialised body. And __proto__ is a SPEC-LEGAL field name — ObjectSchema.fields' key schema is /^[a-z_][a-z0-9_]*$/, which it matches. Measured: fields: { __proto__: { type: 'text', label: 'P' } } parses green, so the spec would have accepted the field the client silently threw away.
MetadataService builds through Object.fromEntries for exactly this reason (it defines an own property), and the behaviour is pinned in MetadataService.objectPayloadFieldsMap.test.ts — including an ablation showing that switching back to assignment reds that one case and nothing else.
Also worth checking in the same pass
Duplicate names. A designer list carrying two fields called amount collapses into one map entry with no diagnostic; MetadataService now refuses that too.
Refs: objectui#6240 (the same two hazards, resolved in MetadataService) · objectui#5761 (the parity family; this is value-level, its coverage note 4)
Generated by Claude Code
Found while implementing objectui#6240, which closed both of these in the OTHER object writer (
app-shell'sMetadataService). Filed rather than folded in: it is a different package and a different file, and objectui#6240's dispatch fenced its file face toMetadataService.tsand its tests.The code
packages/plugin-designer/src/MetadataFieldsPage.tsx,handleFieldsChange:Two hazards, both of them silent.
1. A field with no name keys as the literal string
"undefined"DesignerFieldDefinition.nameis declared required, but this page is handed whatever the in-memory designer model holds. The spec does not catch it. Measured against the installed@objectstack/spec17.2.0:So a nameless field produces a document that PARSES, is STORED, and has no reader anywhere — a silently corrupt object rather than a loud refusal. objectui#6240 resolved this in
MetadataServiceby throwing before the request is issued, with the measurement above as the reason.2. A field named
__proto__is dropped by the assignment itselfnextFields['__proto__'] = …invokes the prototype setter instead of creating a key, so the field disappears from the serialised body. And__proto__is a SPEC-LEGAL field name —ObjectSchema.fields' key schema is/^[a-z_][a-z0-9_]*$/, which it matches. Measured:fields: { __proto__: { type: 'text', label: 'P' } }parses green, so the spec would have accepted the field the client silently threw away.MetadataServicebuilds throughObject.fromEntriesfor exactly this reason (it defines an own property), and the behaviour is pinned inMetadataService.objectPayloadFieldsMap.test.ts— including an ablation showing that switching back to assignment reds that one case and nothing else.Also worth checking in the same pass
Duplicate names. A designer list carrying two fields called
amountcollapses into one map entry with no diagnostic;MetadataServicenow refuses that too.Refs: objectui#6240 (the same two hazards, resolved in
MetadataService) · objectui#5761 (the parity family; this is value-level, its coverage note 4)Generated by Claude Code