Skip to content

Stop partial PATCH bodies clearing fields they never set - #108

Merged
SiteRelEnby merged 2 commits into
mainfrom
fix/partial-patch-bodies
Oct 24, 2026
Merged

SiteRelEnby merged 2 commits into
mainfrom
fix/partial-patch-bodies

Conversation

@SiteRelEnby

Copy link
Copy Markdown
Collaborator

Two bugs with one cause. These bodies clear a column by sending an explicit null, and the hand-written adapters wrote that null whether or not the caller had populated the field. Right for a screen that owns the whole form, wrong for one patching a single setting.

Flipping either switch under Settings, Fronting sent the new value plus nulls for description, tag, colour, note, avatar and banner, and the server cleared all six. Shipped in 1.5.0, so it has been destroying data rather than just failing to save. Checked against a real instance before and after.

Unticking quiet hours on a channel had the opposite problem: Moshi dropped the null, so the field never reached the server and the window stayed on. That one needs an explicit flag, since null there means both "clear it" and "not editing it" and the body had no way to say which.

Clearing is now opt-in per body and defaults to off, so a screen sending part of a form cannot destroy the rest. The three full-form callers opt in. Member and group had no partial caller yet but were one quick-rename action away from the same thing. The gate sits in PatchWriter.clears() rather than per field, so fields added later inherit it.

Also adds a reflective parity test over the four bodies. The existing tests check a hand-written list of names, so a field added to a data class and not to its adapter passes them by construction, which is how the step-up credentials went missing before. This one asks the class what its fields are and names the missing one.

Two bugs, one cause. These bodies clear a column by sending an explicit null,
and the hand-written adapters wrote that null whether or not the caller had
populated the field. That is right for a screen that owns the whole form and
wrong for one that patches a single setting.

Flipping either switch under Settings, Fronting sent the new value plus nulls
for description, tag, colour, note, avatar and banner, and the server cleared
all six. Shipped in 1.5.0. Verified against a real instance before and after.

Unticking quiet hours on a channel had the opposite problem: Moshi's generated
adapter dropped the null, so the field never reached the server and the window
stayed. That one needs an explicit flag, because null there means both "clear
it" and "not editing it" and the body had no way to say which.

Clearing is now opt-in per body, defaulting to off, so a screen that sends part
of a form cannot destroy the rest of it. The three full-form callers opt in.
Member and group had no partial caller yet, but were one quick-rename action
away from the same bug.

Also adds a reflective parity test over all four bodies. The existing ones
check a hand-written list of names, so a field added to a data class and not to
its adapter passes them by construction, which is how the ceilings and the
step-up credentials went missing before. This one asks the class what its
fields are and names the missing one.
@SiteRelEnby
SiteRelEnby enabled auto-merge October 24, 2026 01:02
@SiteRelEnby
SiteRelEnby merged commit ee6f64e into main Oct 24, 2026
1 check passed
@SiteRelEnby
SiteRelEnby deleted the fix/partial-patch-bodies branch October 24, 2026 01:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant