01 · Before and afterThe pattern
Admit, then persist; and keep effect dependencies to the data the effect reads.
// before: createReceipt('preparing'); createDoc(); if (file.size > limit(ws)) return 'too-large';
if (file.size > limit(ws)) return 'too-large'; // reject before any write
const blobId = await blobs.put(ws, file); // can fail without side effects
await createReceipt(ws, attemptId, 'preparing'); await createDoc(ws, { blobId });
useEffect(() => loadPreview(item.id), [item.id]); // not [item.id, onWorkspaceChangedCallback]02 · Run it on your appThe check
If an import fails in one destination and the user retries in another, can the first destination end up with a half-created record?
If the honest answer is no or not sure, this is worth a look before it reaches production.