First to Site
Release 3.9

Sale Check Form-Save Row Preservation

Empty rows submissions from stale tabs no longer wipe saved Sale Check rows

Overview

Seven project.draft_sts_checklist.rows wipes were observed in production in early April. Investigation traced the trigger to a specific edge case in the Sale Check form save path: under certain conditions the browser posted rows: [] even though the project had saved rows, and the server took the empty submission at face value and wiped the stored rows.

Git tag v3.9.0 (part of Release 3.9) patches the form-save path so an empty-rows submission no longer clobbers existing data.

What Changed

The Sale Check form-save handler now runs a preservation guard before writing the draft checklist. If the browser posts rows: [] while the project already has saved rows, the server keeps the stored rows instead of treating the empty payload as intentional.

Trigger conditions

The empty-rows payload was being produced by:

  • Stale browser tabs where the Sale Check JS controller had been torn down but the form was still submittable.
  • Partial JS init where the rows array hadn't yet been populated from the stored state when a rapid save fired.
  • Markup-vs-script mismatches after a front-end deploy (the JS expected an older DOM structure).

All three produce a submission where rows is an empty array (not missing, not null - explicitly []). The new guard treats explicit empty arrays as suspicious when stored rows exist.

What the guard does

If postData.draftStsChecklist.rows is an empty array
AND project.draftStsChecklist.rows has >=1 stored row
THEN override the incoming rows with the stored rows.

The rest of the submission still applies - other draftStsChecklist fields update normally. Only the rows array is protected.

What this does NOT fix

This is the form-save path. A separate destructive path (Clone Sale Check Template) was also investigated and a guard was implemented (fix(sale-check): guard destructive template apply, preserve rows on same-type) but reverted in the same release because Almario's form-save fix addresses the actual root cause of the observed wipes. The Clone Template flow's reset-to-template behaviour is the intended behaviour for that button.

  • Trello iDdBEqFx tracks the original duplicate-wipe report and the investigation.