Skip to content

fix: failed onSubmit is recorded as a successful submit - #103

Merged
lucas-barake merged 2 commits into
mainfrom
fix/failed-submit-not-recorded
Jul 10, 2026
Merged

fix: failed onSubmit is recorded as a successful submit#103
lucas-barake merged 2 commits into
mainfrom
fix/failed-submit-not-recorded

Conversation

@lucas-barake

Copy link
Copy Markdown
Owner

Summary

High-severity data-integrity bug found in a deep review with executed Red→Green validation: submitAtom wrote lastSubmittedValues before invoking onSubmit. When the submit effect fails (e.g. the network save rejects), the form still records those values as the last-submitted snapshot, corrupting the change-tracking contract:

  • hasChangedSinceSubmit turns false — the UI tells the user their failed data was saved (silent data loss from the user's perspective)
  • revertToLastSubmit reverts to values whose submission failed, treating them as a good baseline
  • onBlur auto-submit skips retrying because values equal the recorded snapshot

This matches the README state-lifecycle table's intent ("Submit → lastSubmittedValues = Some(B)" paired with the unsaved-changes use case): last submitted means last saved, not last attempted.

Fix

Run onSubmit first; only commit lastSubmittedValues after it succeeds (rebased onto the then-current state). submitCount and touched still update before onSubmit so the attempt is counted and validation errors surface on failure.

Design note: if "last attempted" semantics were ever intended instead, this should be closed and the README updated to say so — but every consumer surface (hasChangedSinceSubmit, revertToLastSubmit, onBlur resubmit) behaves correctly only with "last saved".

Tests

New regression test: valid values + onSubmit = Effect.fail("network error") → asserts lastSubmittedValues stays None. Red on unmodified code, Green after. Full suite 302 passed, types + lint clean. Independently re-validated (Red re-confirmed on clean main before applying the fix).

Note: a follow-up PR fixing a second, distinct defect in the same lines (stale-snapshot writeback clobbering concurrent edits) is stacked on this branch — merge this one first.

lastSubmittedValues was written before onSubmit ran, so a failing submit
effect (e.g. a rejected network save) still recorded its values as the
last-submitted snapshot: hasChangedSinceSubmit turned false (the user
believes the failed data was saved), revertToLastSubmit reverted to
values whose submission failed, and onBlur auto-submit skipped retrying
because values matched the snapshot. Defer the lastSubmittedValues write
until onSubmit succeeds; submitCount and touched still update on the
attempt so validation errors surface.
@lucas-barake
lucas-barake merged commit 4bb950c into main Jul 10, 2026
4 checks passed
@lucas-barake
lucas-barake deleted the fix/failed-submit-not-recorded branch July 10, 2026 02:33
@github-actions github-actions Bot mentioned this pull request Jul 10, 2026
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