A customer set a mobile reorder option on a custom page, saved, and later found the field back at its default. It looked like a frontend bug, and the evidence pointed at the persistence path.
Our first read was a mobile UI bug. The field was rendering correctly. The save button was wired to a JavaScript handler. The page refreshed on submit. We started tracing the frontend.
That was wrong.
The field was saving, just not always
The symptom was real, but the diagnosis was off. The field value was making it to the server and the POST was landing. What mattered was what the backend did with it, depending on whether the record already existed.
This custom-page module used separate handlers for ADD and UPDATE. They had been written at different times and had drifted into different field contracts.
The ADD path handled the relevant settings, styles, title, and display-order field. The UPDATE path handled only two positional fields and omitted the setting under investigation. So editing an existing custom page quietly dropped the value.
A page reload was not enough to confirm persistence. We needed a safe read-back of the stored field to tell the rendered state from the saved state.
The bug had been there long enough that nobody had traced it to the save path. People had been filing tickets about the UI.
Proving the fix before trusting it
Legacy systems can make path selection hard to see. A fix can land on a handler that looks relevant while a different path, configuration, or include order controls the behavior in practice. That is why evidence after a save matters as much as the code change.
We built a small, access-controlled diagnostic view to verify the fix before closing the ticket. It compared the expected value with the stored field and the rendered result, and it exposed only the minimum case data the check needed. A mismatch became visible without the diagnostic turning into a broad record browser.
It earned its place immediately. Without it we would have tested the fix by eyeballing a form reload, which is exactly how the bug hid for so long.
The fix was symmetry
Once the shape mismatch was clear, the fix was not complicated. We updated the frontend payload builder to send the full field set on both the ADD case and the UPDATE case. Then we updated the UPDATE branch on the backend to accept and persist those fields the same way ADD did.
The change touched the backend save handler, the JavaScript payload constructor, and the verification view. A follow-up authorized test confirmed that the field persisted and rendered as expected.
What the fix left open
This incident raises an audit question: where else do separate create and update paths exist, and which fields lack a clearly tested contract? Those paths should be inventoried and ranked by risk and observed symptoms before anyone changes them speculatively.
The broader improvement is a shared, explicit payload contract for fields that should behave the same across create and update, with intentional exceptions defined at the serialization layer. That is a refactor and deserves its own scoped work.
For this save path, the verified contract and the read-back check now make the behavior observable. In other systems, a setting that won’t persist can come from frontend state, API validation, authorization, caching, configuration, or persistence. Split write paths are one high-value hypothesis to test, and they don’t replace evidence.
When a saved setting reverts, check whether the create and update paths write the same fields before you blame the interface. Require a read-back of the stored value after the fix, because a reload cannot separate what was rendered from what was saved.