ADR-0003: Remove attributes with a flag on ATTRIBUTE-UPDATE
Context
ATTRIBUTE-UPDATE could only set an attribute: the frontend called setAttribute and core-service stored the value. Boolean attributes (disabled, required, hidden, open, …) are on whenever present, including disabled="", so the Props tab could turn them on but never off. Clearing any optional attribute also left attr="" behind instead of removing it, and undo of “add attribute” could only restore an empty value.
Decision
Add an optional remove?: boolean to AttributeUpdateActionPayload. When true, the frontend calls removeAttribute and deletes the key from the JHTML node; core-service (action.go) does delete(attrs, attr). value is ignored. The Props writer uses it for null writes and for the reverse of adding an attribute that didn’t exist.
Alternatives considered
- A new
ATTRIBUTE-REMOVEaction type — rejected: every consumer of action types (apply, commit, history labels, socket relay, backend switch) would need a new case for what is the same operation with a different outcome. - Treat
value: ""as removal — rejected: empty values are meaningful (alt=""for decorative images,sandbox=""for full restrictions, boolean attributes are stored as""). value: null— rejected: changes the field’s type for every consumer, and Go’sp["value"].(string)assertion would silently yield"".
Consequences
- Old payloads are unaffected;
removedefaults to absent/false. - Clients that don’t know the flag would set
attr=""instead of removing it. All current consumers (frontend apply, core-service) were updated together. - Undo of adding an attribute now removes it instead of leaving it empty.