Roll back optimistic new-chat expense on money-request failure#96573
Roll back optimistic new-chat expense on money-request failure#96573MelvinBot wants to merge 5 commits into
Conversation
Co-authored-by: daledah <daledah@users.noreply.github.com>
|
@MelvinBot please use option 2 in this proposal |
…e failure Co-authored-by: daledah <daledah@users.noreply.github.com>
|
Fixed the failing What failed: Why: That test exercises exactly the scenario this PR changes — a brand-new chat ( Fix: Updated the post-failure assertions in that test to expect the rollback end-state instead of surviving-with-errors — the IOU report actions, transaction-thread actions, and transaction are now expected to be gone immediately after failure. The later assertions (all reports/actions/transactions removed) were already correct and are unchanged. See
Verified locally: The other failing check, |
|
All the code checks are now passing. The real failure — The only check still red is |
…n dismiss Instead of rolling back every optimistic entity in failureData, keep the standard error-merge behavior and reset the new chat/IOU report metadata to non-optimistic so the chat is no longer stuck on an infinite loading skeleton. Dismissing the failed expense now fully removes the orphaned chat and IOU report shells (deleteReport cascades to the linked IOU report and threads and now also clears report metadata). Co-authored-by: daledah <daledah@users.noreply.github.com>
…nse' into claude-rollbackFailedNewChatExpense Co-authored-by: daledah <daledah@users.noreply.github.com>
…ys visible) Option 2 keeps the standard error-merge behavior on failure, so the failed IOU action, transaction thread actions and transaction remain with red-brick-road errors until dismissed. Reverts the option-1 rollback expectations added earlier so the test matches the current behavior. Co-authored-by: daledah <daledah@users.noreply.github.com>
|
MelvinBot has made 5 consecutive commits trying to fix CI failures. Automatic CI fix dispatches are now paused for this PR. Next steps: A human should review the recent commits and resolve the conflicting CI errors manually. |
|
🤖 Switched the implementation to option 2 from the proposal and pushed to this PR. What changed vs. the previous (option 1) approach:
Expenses added to an existing chat/IOU report are untouched (standard error-merge, still retryable). The PR description and test steps were updated to match option 2 (chat loads with the failed expense → dismiss removes the expense and the chat). Tests updated & run locally:
Note: I couldn't record on-device screenshots/videos in this run — please add the platform recordings before marking the PR ready for review. |
|
@MelvinBot please open this PR |
|
🤖 Done — this PR is now marked Ready for review. |
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 471b2686ba
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // them entirely (see #93542) rather than only clearing the error, so navigate the user out of the now-deleted | ||
| // chat and delete it — deleteReport cascades to the linked IOU report and the transaction thread(s). | ||
| if (reportID && report?.errorFields?.createChat) { | ||
| Navigation.goBack(undefined, {afterTransition: () => deleteReport(reportID, true)}); |
There was a problem hiding this comment.
Delete the failed chat, not the current IOU report
When the user opens the failed expense report and dismisses the IOU action error, reportID is the IOU report ID because the failure data attaches the action errors under REPORT_ACTIONS<iouReportID> and errorFields.createChat to that IOU report. Calling deleteReport(reportID, true) from this context deletes only the IOU report and its transaction thread; deleteReport does not follow chatReportID back to the brand-new DM, so the chat shell/preview remains orphaned. Use the parent chat report ID for this rollback path, or otherwise distinguish whether the current report is the chat or the expense report.
Useful? React with 👍 / 👎.
| onyxMethod: Onyx.METHOD.MERGE, | ||
| key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${chat.report?.reportID}`, | ||
| value: { | ||
| isOptimisticReport: false, |
There was a problem hiding this comment.
Keep created-row dismiss deleting failed new chats
For a failed brand-new chat, this flips the chat metadata to non-optimistic, but the created/welcome row close handler still calls clearCreateChatError, which deletes the report only when REPORT_METADATA.isOptimisticReport is true; once this failure merge runs, that handler only clears errorFields.createChat. If the user closes the red error on the created row first, the optimistic chat and IOU shell are left behind, and the expense close path will no longer see report.errorFields.createChat to clean them up.
Useful? React with 👍 / 👎.
|
@MelvinBot could you please check all comments above? |
Explanation of Change
When an expense is created for a brand-new user (a chat that doesn't exist yet) and the request fails on the server (e.g. the "Simulate failing network request" toggle), the app optimistically created a chat report, an IOU report, a transaction, the report actions and a transaction thread. Two symptoms were reported:
isOptimisticReport: true(only the success path reset it tofalse), sofetchReportshort-circuited, never calledOpenReport, and the loading skeleton spun forever.This implements option 2 from the proposal: keep the failed expense visible (with its red-brick-road error) until the user dismisses it, and clean everything up on dismiss.
buildOnyxDataForMoneyRequestkeeps the standard error-mergefailureData(so the failed expense stays visible and retryable), and additionally resets the newly-created chat and IOU report metadata toisOptimisticReport: false— mirroring the success path. This unblocksfetchReport/OpenReportso the chat is no longer stuck on an infinite loading skeleton.dismissError(inReportActionItem) now detects a failed brand-new-chat expense (report.errorFields.createChat) and, instead of only clearing errors, navigates the user out of the chat and callsdeleteReport, which cascades to the linked IOU report and the transaction thread(s). Nothing orphaned is left behind, matching the issue's Expected Result.deleteReportnow also clears the report'sREPORT_METADATA(e.g.isOptimisticReport) so a deleted report leaves nothing behind.Expenses added to an existing chat or IOU report are untouched: they keep the standard error-merge behavior so they remain retryable and no server-backed data is deleted. Because
failureDataonly runs on a genuine server failure (offline requests are queued, not failed), offline behavior is unchanged.Unit tests in
BuildOnyxDataForMoneyRequestTestcover the new-chat failure path (error-merge kept, metadata reset to non-optimistic, nothing SET to null) and the existing-chat path (standard error-merge, no metadata reset). TheRequestMoneyTestRedBrickRoad test continues to assert the failed expense stays visible until dismissed.Fixed Issues
$ #93542
PROPOSAL: #93542 (comment)
Tests
Offline tests
Creating an expense while offline queues the request (it does not fail), so the optimistic chat/expense persist as before. The rollback only applies to a genuine server failure once back online.
QA Steps
Same as Tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari