Found while implementing objectui#6240 (the object payload's fields array-to-map conversion). Filed, not fixed — a different level from the container shape that card is about, and a different level from objectui#6480.
What it is
MetadataService.saveFields preserves unknown keys of the fetched OBJECT document by spreading it:
constupdatedObject={ ...existingObject,name: objectName,fields: <rebuilt>};That spread is object-level only. The fields value is rebuilt entirely from DesignerFieldDefinitions via toFieldPayload, so every key the SERVER sent inside a field and the designer does not model is dropped: expression (a formula authored in metadata-admin), precision / scale, system, sortable, and anything a plugin registered.
Why now
The loss is not new, but it was unreachable. While fields went out as an ARRAY the whole body was refused 422 INVALID_METADATA (invalid_type @ fields) before persistence, so nothing saveFields dropped ever reached storage. objectui#6240 makes the body parse, so from that fix onward the drop lands.
The correct form is already in the repo
The sibling writer solves exactly this. MetadataFieldsPage.handleFieldsChange carries the previous server entry into the new one:
nextFields[f.name]=fromDesignerField(f,prevFields[f.name]);// fromDesignerField spreads carryOver(prev)
saveFields already fetches the same document (client.meta.getItem('object', objectName)) for the object-level spread, so the per-field previous entries are in hand at the same moment — there is nothing extra to fetch.
Not objectui#6480
objectui#6480 is the OBJECT-level spread: read decorations (_diagnostics, _draft) that the served document carries and ObjectSchema refuses by name. This is the FIELD level and the opposite direction — keys that should survive and do not. The two edit neighbouring expressions and should not be folded together.
Refs: objectui#6240 (the conversion that makes this reachable) · objectui#6480 (the object-level half)
Generated by Claude Code
Found while implementing objectui#6240 (the object payload's
fieldsarray-to-map conversion). Filed, not fixed — a different level from the container shape that card is about, and a different level from objectui#6480.What it is
MetadataService.saveFieldspreserves unknown keys of the fetched OBJECT document by spreading it:That spread is object-level only. The
fieldsvalue is rebuilt entirely fromDesignerFieldDefinitions viatoFieldPayload, so every key the SERVER sent inside a field and the designer does not model is dropped:expression(a formula authored in metadata-admin),precision/scale,system,sortable, and anything a plugin registered.Why now
The loss is not new, but it was unreachable. While
fieldswent out as an ARRAY the whole body was refused422 INVALID_METADATA(invalid_type @ fields) before persistence, so nothingsaveFieldsdropped ever reached storage. objectui#6240 makes the body parse, so from that fix onward the drop lands.The correct form is already in the repo
The sibling writer solves exactly this.
MetadataFieldsPage.handleFieldsChangecarries the previous server entry into the new one:saveFieldsalready fetches the same document (client.meta.getItem('object', objectName)) for the object-level spread, so the per-field previous entries are in hand at the same moment — there is nothing extra to fetch.Not objectui#6480
objectui#6480 is the OBJECT-level spread: read decorations (
_diagnostics,_draft) that the served document carries andObjectSchemarefuses by name. This is the FIELD level and the opposite direction — keys that should survive and do not. The two edit neighbouring expressions and should not be folded together.Refs: objectui#6240 (the conversion that makes this reachable) · objectui#6480 (the object-level half)
Generated by Claude Code