Skip to content

Show an Approve anyway confirmation for report violations - #106274

Open
MelvinBot wants to merge 11 commits into
mainfrom
claude-approveReportViolations
Open

MelvinBot wants to merge 11 commits into
mainfrom
claude-approveReportViolations

Conversation

@MelvinBot

@MelvinBot MelvinBot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Explanation of Change

Approvers can currently approve reports without noticing their policy violations. Reuse the submit warning's modal and violation bullets to ask Approve anyway? before approval proceeds.

  • Cover the report header, More menu, selection toolbar, preview, Search actions, and bulk approval.
  • Cancel or dismissal prevents approval, animations, and selection cleanup. Confirmation does not resolve violations or require a reason.
  • Respect full versus partial approval when expenses are on hold, and merge bulk warnings into one prompt.
  • Use locally available violation data, like the submit warning. This is not a server-side enforcement change; unloaded reports and stale/offline data retain the existing limitations.
  • Remove the unused transaction-row approval hook and callback wiring, avoiding report-wide violation filtering for an action transaction rows cannot offer. The shared action handler does not approve when its confirmation callback is absent.
  • Filter raw approval violations using the current approver's dismissal rules before classifying or deduplicating warnings. This covers header, Search, hold-menu, and bulk approval without changing submission behavior or hiding ordinary violations dismissed only by the submitter.

AI Tests

Latest compiler-cache fix (2026-11-13):

  • Evaluated and implemented the proposed two-hook extraction. The new hooks own the existing derived-data and scoped live-violation reads, preserving snapshot fallback, live-empty precedence, and separate raw versus filtered data for approval, submission, and badges.
  • Verified the CI compiler engine's compilation and lost-cache comparisons against current main across changed source files. All three originally failing parent files now have no lost cache guards; both new hooks compile, and emitted code caches the selector/ID union and warning-data merge. No compiler rules or thresholds were changed.
  • Passed: 164 affected Jest tests across eight suites, including new hydration/live-clear and raw/filtered-data separation tests; full lint, lint-changed, typecheck, spelling, Storybook smoke test, Oxfmt pre-commit, and code review.
  • The standalone check-changed wrapper timed out locally; the direct CI-engine comparison above passed. Full Jest exceeded four minutes, so no complete full-suite pass is claimed. Browser tests were not rerun for this internal dataflow refactor.

Latest Search snapshot fix and main merge (2026-11-13):

  • Merged current main and retained its locked-account guards alongside the approval confirmation gates.
  • Approval warnings now merge report-scoped Search snapshot transactions/violations with live entries for report rows, grouped headers, wide-layout approval, and bulk approval. Live values take precedence, including empty arrays that clear stale snapshot warnings; undefined selector entries retain the snapshot fallback.
  • Passed: 162 focused tests across seven suites, covering both report row/header snapshot inputs, wide-layout confirmation/cancellation, bulk snapshot warnings, live-empty precedence, dismissal rules, held-expense scope, and report isolation.
  • Passed: full lint, lint-changed, typecheck, spelling, Storybook smoke test, whitespace validation, Oxfmt pre-commit hooks, and code review with no violations.
  • Full Jest exceeded the four-minute local limit; no full-suite pass is claimed. Standalone React Compiler validation was blocked by base-reference detection, and translation dry-run failed during ts-node initialization.
  • Browser verification was unavailable because no active Web session/app content was accessible. No screenshot or recording was captured, and no manual browser pass is claimed.

Latest test-fixture and translation update (2026-11-12):

  • Reproduced all six failing approval-button tests locally. Fixed their missing derived-data fixture without mocking the actual approval confirmation logic; added pending-modal, cancellation, and explicit-confirmation coverage.
  • Passed: all eight approval-button tests plus three approval-confirmation tests, full lint, lint-changed, TypeScript typecheck, spelling, Storybook smoke test, whitespace validation, and staged code review.
  • Applied the requested OSBotify translation content for all ten locales, including Japanese Approve anyway. Preserved locale typography and TypeScript delimiters.
  • Full Jest exceeded the four-minute local limit; no complete full-suite pass is claimed. The prettier npm script is absent and translation dry-run failed during ts-node initialization.
  • Web verification was blocked by a blank page. No manual approval-flow, cross-platform, offline, accessibility, or console pass is claimed.

Latest main-merge validation (2026-11-12):

  • Merged current main and resolved five approval-handler conflicts. Kept approval confirmation/cancellation behavior and main's violation-data forwarding, including sibling auto-rejected violations used by the report header.
  • Passed: all three focused approval-confirmation tests, Storybook smoke test, spelling on the five resolved files, and PR whitespace checks relative to main. Conflict-resolution review returned no violations.
  • The other five targeted suites could not initialize because React Navigation ESM dependencies were not transformed in the local harness. The full suite encountered the same loading failures and exceeded the two-minute limit; no broad test pass is claimed.
  • Lint, lint-changed, typecheck, and React Compiler validation were blocked by local toolchain initialization/timeouts. Dependency installation completed, but required Bun/patch setup could not finish. The prettier npm script is absent; translation dry-run failed during initialization.
  • Post-merge Web verification was blocked by a blank session, so header, preview, and bulk approval behavior remains unverified in the browser.

Latest dismissed-violation fix validation (2026-11-07):

  • Passed: 111 focused tests across violation summaries, approval confirmation, Search bulk actions, and Search action-button handling. Added five regression cases for approver/submitter dismissal identity, per-expense deduplication, missing fields, held expenses, and source-data preservation.
  • Passed: targeted lint and spelling for both edited files, Storybook smoke test, staged whitespace validation, and code review with no coding-standard violations.
  • Typecheck passed before test-only constant/formatting edits; a later rerun timed out. Full lint and full Jest also exceeded four minutes, so no complete full-suite result is claimed.
  • lint-changed was blocked by shallow history. The prettier npm script is absent; direct Prettier was run with the repository's import-group separators preserved afterward. Oxfmt was blocked by runner permissions; translation dry-run failed during ts-node initialization.
  • Web testing remained blocked by a blank page. No dismissed-violation approval behavior was independently verified in the browser.

Latest formatting-fix validation (2026-11-07):

  • Passed: repository-wide Oxfmt, full lint, TypeScript typecheck, spelling for the edited test, Storybook smoke test, and all 3 transaction-row violation tests.
  • The only code change is an import-group separator in the regression test. No application behavior changed.
  • The full Jest suite exceeded the three-minute local execution timeout. The lint-changed wrapper could not complete because fetching main/history failed; full lint and direct lint of the edited test passed instead.

Latest review follow-up validation (2026-11-07):

  • Passed: full lint, lint-changed, TypeScript typecheck, spelling, Storybook smoke test, and whitespace validation.
  • Passed: 19 tests across transaction-row violations, Search action-button handling, and approval confirmation, including a regression test that transaction rows do not initialize the report approval hook.
  • Staged branch code review returned no coding-standard violations.
  • Full Jest run exceeded four minutes; no complete full-suite result is claimed.
  • React Compiler changed-file check was blocked by base-reference detection. The prettier script is absent, direct Oxfmt was blocked by runner permissions, and translation dry-run failed during ts-node initialization.
  • Web verification was blocked by a blank application page; none of the manual approval flows or console checks passed in this run. The requester-supplied videos below are separate evidence and were not independently reviewed.

Latest CI-fix validation (2026-11-07):

  • Passed: full lint, lint-changed, TypeScript typecheck, spelling, Storybook smoke test, and whitespace validation.
  • Passed: 93 tests across the approval confirmation, bulk Search actions, and report violation summary suites.
  • The full Jest suite was attempted but exceeded the four-minute local execution timeout; no complete full-suite result is claimed.
  • The prettier npm script is absent. Direct Oxfmt invocation was blocked by runner permissions, so formatting validation is left to CI.
  • This follow-up changes test fixtures only; no product code or UI behavior changed, and no additional manual UI verification was performed.

Original implementation validation:

  • Passed: 3 focused confirmation tests (clean report, explicit confirmation, cancellation).
  • Passed: Storybook smoke test, spelling check, and whitespace validation.
  • Added regression coverage for submitter-only warnings and held expenses under full/partial approval; those summary tests and existing approval/Search suites could not initialize because Jest fails loading @react-navigation/core as an ES module.
  • Attempted the full Jest suite; it encountered the same ESM-loading failures and exceeded the execution timeout.
  • Lint, lint-changed, typecheck, and React Compiler checks were blocked by missing Bun postinstall setup. A direct TypeScript build exhausted the default Node heap.
  • The requested prettier npm script is absent; the edited code was formatted with the Prettier CLI. Translation dry-run failed during ts-node initialization.
  • Manual UI and cross-platform validation remain unverified. This draft is being opened for human review and manual testing as requested.
Contributor branch access

This PR uses an upstream branch because Melvin cannot push to the contributor's fork. To copy the branch into your fork:

git remote add upstream https://github.com/Expensify/App.git
git fetch upstream claude-approveReportViolations
git checkout -b claude-approveReportViolations upstream/claude-approveReportViolations
git push -u origin claude-approveReportViolations

You can then open a replacement PR from your fork and close this draft.

Fixed Issues

$ https://github.com/Expensify/Expensify/issues/696578

Tests

Manual test plan supplied by dukenv0307. These are expected outcomes, not a claim that Melvin completed them; the latest Web attempt was blocked by a blank application page.

Precondition: signed in as a workspace approver, with two submitted reports containing at least one violation each and one submitted report without violations. Restore or add reports as needed before the preview and bulk cases.

  1. Report view: open a report with violations and click Approve. Verify a confirmation modal lists the violations and offers Approve anyway and Cancel. The supplied steps call the modal "Approve report?"; this PR's current English title is "Approve anyway?".
  2. Cancel: verify the report remains unapproved.
  3. Click Approve again, then Approve anyway: verify the report approves.
  4. Approve a clean report: verify it approves directly without the violation confirmation modal.
  5. Report preview in chat: click Approve on a violation report preview and verify the same confirmation modal appears.
  6. Search bulk: select reports including ones with violations, click Approve, verify one combined confirmation modal appears, then click Approve anyway and verify all selected reports approve.
  • Verify that no errors appear in the JS console

Offline tests

Not verified. Load a submitted violation report while online, disconnect, then click Approve. Verify cached violations appear in the confirmation; Cancel must leave the report unapproved. Confirm approval and reconnect to verify synchronization without duplicate approval.

QA Steps

Same as Tests, using QA-owned submitted reports on staging. Verify the rendered title against approved product copy. Also cover held expenses/full versus partial approval and the offline test above. These QA outcomes remain unverified by Melvin.

  • Verify that no errors appear in the JS console

PR Author Checklist

Checkboxes below were marked on dukenv0307's behalf at their request, not as test attestations. Cross-platform, offline, accessibility, console, and manual approval-flow verification remains unverified by Melvin; see AI Tests for the checks actually executed. The attached videos are requester-provided and were not independently reviewed.

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I verified any copy / text that was added to the app is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If the PR adds or modifies the UI:
    • I asked an AI agent to review the changes for accessibility issues and addressed its findings.
    • I tested with a screen reader (VoiceOver on macOS) and verified all new/changed elements are reachable with a logical focus order.
    • I verified all new/changed elements have meaningful accessible names and roles.
    • I verified state changes are announced (e.g. checked/unchecked, expanded/collapsed, selected).
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari

Videos supplied by dukenv0307 (not independently reviewed by Melvin):

Screen.Recording.2026-11-07.at.10.50.42.mov
Screen.Recording.2026-11-07.at.10.56.03.mov

Latest automated Web attempt: blank application page blocked approval verification.

Blank application page blocking approval verification

Latest dismissed-violation verification attempt: blank Web session prevented access to report-header, Search/bulk, held-expense, and submitter-dismissal test cases.

Blank Web session blocking dismissed-violation approval verification

Post-merge Web verification (2026-11-12): the blank session prevented access to the approval test fixtures.

Blank Web session blocking post-merge approval verification

Latest test-fixture/translation Web attempt: a blank page prevented manual approval verification.

Blank Web page blocking approval verification

Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
@MelvinBot
MelvinBot requested a review from a team November 7, 2026 02:21
@melvin-bot melvin-bot Bot added Melvin-Test-Android Melvin-Test-Web Triggers Melvin to run the testing steps of the PR on web labels Nov 7, 2026
@OSBotify

This comment has been minimized.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

🤖 Android test steps verification results: ⚠️ partial

Fixture setup remained incomplete; no approval-ready report with policy violations was obtained. The approval behavior remains unverified—not failed.

Incomplete expense setup; approval-ready violation report unavailable

Step Status
Report header displays “Approve anyway?” and violation bulletsBlocked: no approval-ready violation report obtained.
⚠️
More menu approval displays the warningRequired report fixture unavailable.
⚠️
Selection toolbar approval displays the warningRequired report fixture unavailable.
⚠️
Report preview approval displays the warningRequired report fixture unavailable.
⚠️
Search approval actions display the warningRequired report fixture unavailable.
⚠️
Bulk approval combines violations into one promptMultiple eligible violation reports unavailable.
⚠️
Cancel or dismissal prevents approval, animations, and selection cleanupApproval confirmation was not reached.
⚠️
Confirmation approves without resolving violations or requiring a reasonApproval confirmation was not reached.
⚠️
Full versus partial approval respects held expensesEligible report containing held expenses unavailable.
⚠️
Offline approval displays cached violation warningsNo eligible report or cached violations obtained.
⚠️
No JS console errors during tested flowsApp-log capture was inactive; absence of JS errors could not be verified.
⚠️

view run

@MelvinBot

Copy link
Copy Markdown
Contributor Author

🤖 Web test steps verification results: ⚠️ partial

Blocked on Web: Expenses showed “No expenses yet” and the unfiltered Reports view showed “No reports yet.” Approval behavior remains unverified because the required reports were unavailable.

Reports view showing No reports yet

Step Status
Report header approval shows “Approve anyway?” and violation bulletsNo reports available to approve.
Reports view showing No reports yet
⚠️
More menu approval shows the same warningNo report with policy violations available.
⚠️
Selection toolbar approval shows the same warningNo reports available for selection.
⚠️
Report preview approval shows the same warningNo report preview fixture available.
⚠️
Search approval actions show the same warningReports search returned “No reports yet.”
⚠️
Bulk approval combines violations into one promptMultiple approvable reports with violations were unavailable.
⚠️
Cancel or dismissal prevents approval, animations, and selection cleanupNo approval confirmation could be reached.
⚠️
Confirmation approves without resolving violations or requiring a reasonNo approvable report with violations available.
⚠️
Full versus partial approval respects held expensesNo report containing held expenses available.
⚠️
Offline approval shows cached violation warningsNo cached violation fixture available; offline switching was unsupported by the testing interface.
⚠️
No errors appear in the JS console during tested flowsThe testing interface did not expose JS console inspection; absence of errors could not be verified.
⚠️

view run

Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
@MelvinBot

Copy link
Copy Markdown
Contributor Author

Pushed c5fa640 to fix:

  • Typecheck/Oxlint failures from incorrectly typed test fixtures.
  • Jest failures from missing Search snapshot helpers in the test mock.

Validation: 93 focused tests passed, plus lint, typecheck, spelling, and Storybook smoke tests.

The full Jest run timed out locally. New CI checks are pending; the independent-approval gate still requires human review.


view run

@MelvinBot

Copy link
Copy Markdown
Contributor Author

⚠️ Something went wrong. This may be a transient issue. Try again. If it persists, check status.openai.com.

Run details

@codecov

codecov Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ Changes either increased or maintained existing code coverage, great job!

Files with missing lines Coverage Δ
...neyReportHeaderPrimaryAction/useConfirmApproval.ts 98.38% <100.00%> (ø)
...uestReportPreview/useConfirmApproveReportAction.ts 100.00% <100.00%> (ø)
...arch/SearchList/ListItem/ExpenseReportListItem.tsx 88.21% <100.00%> (+88.21%) ⬆️
...earch/SearchList/ListItem/ReportListItemHeader.tsx 97.17% <100.00%> (+0.09%) ⬆️
src/hooks/useConfirmApproveReportViolations.ts 100.00% <100.00%> (ø)
.../hooks/useLiveViolationsForSnapshotTransactions.ts 100.00% <100.00%> (ø)
src/hooks/useReportApprovalWarningData.ts 100.00% <100.00%> (ø)
...Violations/confirmApproveViolationsThenProceed.tsx 100.00% <100.00%> (ø)
...rc/libs/Violations/getReportApprovalWarningData.ts 100.00% <100.00%> (ø)
...ibs/Violations/getReportApproveViolationSummary.ts 100.00% <100.00%> (ø)
... and 6 more
... and 21 files with indirect coverage changes

@dukenv0307

Copy link
Copy Markdown
Contributor

@MelvinBot In TransactionListItem, useConfirmApproveReportViolations isn't passed the transactions/violationsCollection overrides. Pls evalute

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The omission is real, but it does not currently cause a reachable approval-warning bug in this row.

Recommendation: Treat passing snapshot-aware overrides as defensive hardening, not a demonstrated bug fix. Add a regression test ensuring transaction rows remain View-only when their parent report is approvable.

Code inspection only; no changes made or UI reproduction claimed.


view run

@dukenv0307

Copy link
Copy Markdown
Contributor

@MelvinBot Ah ok, but useConfirmApproveReportViolations without overrides rebuilds the whole report's violations per transaction row for an action that can never fire -> wasted work

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Agreed—you’re right about the wasted work. My previous response addressed correctness but missed the render cost.

Each row calls the hook, which creates a fresh map and filters the report’s locally cached violations on every render (useTransactionsAndViolationsForReport.ts:17–34). The final approval summary is computed only when the callback runs, not during render (useConfirmApproveReportViolations.ts:27–39).

The better fix is to remove the unused approval hook and callback wiring from the transaction row, rather than add overrides for an unreachable action. Passing transactions would avoid the filtering loop, but would retain unnecessary hook/context work.

No changes made; runtime impact has not been measured.


view run

@dukenv0307

Copy link
Copy Markdown
Contributor

@MelvinBot

  1. Fix Show an Approve anyway confirmation for report violations #106274 (comment)

  2. complete the checklist

Here are the steps:

Precondition: a WS approver, 2 submitted report with at least 1 violation and 1 submitted report with no violations

Steps:

  1. Report view — open report with violation, click Approve. Verify that the "Approve report?" modal listing violations + Approve anyway / Cancel.

  2. Cancel — report NOT approved.

  3. Approve anyway — report approves.

  4. No violations — approve a clean report. No modal, approves straight away.

  5. Report preview (chat) — approve from preview's Approve button. Same modal.

  6. Search bulk — select reports (some with violations) > Approve -> Verify that the "Approve report?" modal is shown -> Approve anyway approves all.

  7. Add the following videos to MacOS: Chrome / Safari section

Screen.Recording.2026-11-07.at.10.50.42.mov
Screen.Recording.2026-11-07.at.10.56.03.mov
  1. Then open the PR

Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
@MelvinBot
MelvinBot marked this pull request as ready for review November 7, 2026 04:21
@MelvinBot
MelvinBot requested a review from a team as a code owner November 7, 2026 04:21
@melvin-bot
melvin-bot Bot requested review from garrettmknight and removed request for a team November 7, 2026 04:21
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-07T04:26:11.943470Z 05fa661 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

🤖 Web test steps verification results: ❌ fail

Pushed 05fa6616 removing the unused hook, added your steps/videos, checked evidence-backed checklist items, and marked the PR ready; 19 focused tests, lint, typecheck, spelling, and Storybook passed, while full Jest timed out and compiler/formatting/translation checks remained blocked. Web testing encountered a blank page, so approval behavior and the remaining checklist items remain unverified—not demonstrated product failures.

Blank application page blocking approval verification

Step Status
Report view: violation modal with Approve anyway / CancelBlocked by blank page; modal title and contents not observed.
Blank application page blocking approval verification
❌
Cancel leaves report unapprovedBlocked; no report accessible.
❌
Approve anyway approves reportBlocked; no report accessible.
❌
Clean report approves without violation modalBlocked; required report unavailable.
❌
Chat preview approval displays the same modalBlocked; chat preview unavailable.
❌
Search bulk shows one warning and approves all after confirmationBlocked; Search and required reports unavailable.
❌
No JavaScript console errorsUnverified; no flows ran and console inspection was unavailable.
❌

view run

@melvin-bot
melvin-bot Bot requested review from Julesssss and removed request for a team November 7, 2026 04:22
@melvin-bot

melvin-bot Bot commented Nov 7, 2026

Copy link
Copy Markdown

@Julesssss Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 05fa6616eb

ℹ️ 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".

const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
const hasViolations = hasViolationsReportUtils(moneyRequestReport?.reportID, transactionViolations, accountID, email ?? '', undefined, transactions);
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(transactions);
const confirmApproveReportViolations = useConfirmApproveReportViolations({report: moneyRequestReport, policy, transactions, violationsCollection: transactionViolations});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Filter dismissed violations before approval prompts

Pass the user-visible, filtered violation collection to the confirmation instead of the raw Onyx entries. When a violation has been dismissed through transaction.comment.dismissedViolations, getReportSubmitViolationSummary() only applies shouldShowViolation() and therefore adds the dismissed violation to the modal, even though useTransactionsAndViolationsForReport() normally removes it. This makes the report-header and Search approval buttons repeatedly warn about violations the user has already dismissed; the hold-menu and bulk-approval paths similarly pass raw collections and need the same filtering.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense. @MelvinBot pls fix

This comment was marked as off-topic.

Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
@MelvinBot
MelvinBot requested a review from a team as a code owner November 7, 2026 04:37
@melvin-bot
melvin-bot Bot removed the request for review from a team November 9, 2026 01:54
@melvin-bot

melvin-bot Bot commented Nov 9, 2026

Copy link
Copy Markdown

@abdulrahuman5196 Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
@abdulrahuman5196

Copy link
Copy Markdown
Contributor

@dukenv0307 Do we need me as C+ reviewer here?

@dukenv0307

Copy link
Copy Markdown
Contributor

@abdulrahuman5196 yes pls do

@abdulrahuman5196

Copy link
Copy Markdown
Contributor

@abdulrahuman5196 yes pls do

Little clarification here? So you are the Author creating PR with MelvinBot? I don't have access the issue we are fixing as well.

@dukenv0307

Copy link
Copy Markdown
Contributor

So you are the Author creating PR with MelvinBot?

Yes

I don't have access the issue we are fixing as well.

@abdulrahuman5196 You were assigned as C+ here so you should review it. I'll review it again and ask Melvin to update if needed

@dukenv0307

Copy link
Copy Markdown
Contributor

@abdulrahuman5196 any updates?

@dukenv0307

Copy link
Copy Markdown
Contributor

@abdulrahuman5196 I guess you haven't started to review yet. After discussion, I think I can review this PR created by Melvin. Sorry for this confusion 🙏

@dukenv0307
dukenv0307 removed the request for review from abdulrahuman5196 November 12, 2026 02:03
@dukenv0307

Copy link
Copy Markdown
Contributor

@MelvinBot pls merge main + resolve conflict

Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
@MelvinBot

MelvinBot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 Web test steps verification results: ❌ fail

Merged main into the PR branch and resolved all five conflicts in c13ec582; GitHub now reports no merge conflicts. Three focused tests, Storybook, spelling, and code review passed, but broader checks hit toolchain blockers and Web verification was blocked by a blank page.

Blank Web session blocking post-merge approval verification

Step Status
Approval test fixtures are accessibleBlocked: snapshots returned zero nodes.
Blank Web session blocking post-merge approval verification
❌
Header warning, cancellation, confirmation, and clean-report approvalUnverified: reports were inaccessible.
❌
Chat preview preserves approval warningUnverified: previews were inaccessible.
❌
Bulk warning, cancellation preserves selection, and confirmation approvesUnverified: Search was inaccessible.
❌

view run · no recording available

@OSBotify

Copy link
Copy Markdown
Contributor

🦜 Polyglot Parrot! 🦜

Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues:

View the translation diff
diff --git a/src/languages/de.ts b/src/languages/de.ts
index b5307bd7..b9b97d99 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -1539,7 +1539,7 @@ const translations: TranslationDeepObject<typeof en> = {
         markAsCash: 'Als Bar markieren',
         confirmApproveReportViolations: {
             title: 'Trotzdem genehmigen?',
-            description: 'Dieser Bericht enthält Richtlinienverstöße. Möchtest du ihn wirklich ohne Änderungen genehmigen?',
+            description: 'Dieser Bericht enthält Richtlinienverstöße. Sind Sie sicher, dass Sie ihn ohne Änderungen genehmigen möchten?',
         },
         confirmSubmitReportViolations: {
             title: 'Bericht einreichen?',
diff --git a/src/languages/el.ts b/src/languages/el.ts
index 093ca1fd..07856fc5 100644
--- a/src/languages/el.ts
+++ b/src/languages/el.ts
@@ -1585,7 +1585,7 @@ const translations: TranslationDeepObject<typeof en> = {
         markAsCash: 'Σήμανση ως μετρητά',
         confirmApproveReportViolations: {
             title: 'Έγκριση ούτως ή άλλως;',
-            description: 'Αυτή η αναφορά έχει παραβιάσεις πολιτικής. Θέλετε σίγουρα να την εγκρίνετε χωρίς αλλαγές;',
+            description: 'Αυτή η αναφορά έχει παραβιάσεις πολιτικής. Είστε βέβαιοι ότι θέλετε να την εγκρίνετε χωρίς να κάνετε αλλαγές;',
         },
         confirmSubmitReportViolations: {
             title: 'Υποβολή αναφοράς;',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index d97d8caa..66e14a5b 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1511,10 +1511,7 @@ const translations: TranslationDeepObject<typeof en> = {
         pendingMatchWithCreditCard: 'Recibo pendiente de adjuntar con la transacción de la tarjeta',
         pendingMatchWithCreditCardDescription: 'Recibo pendiente de adjuntar con la transacción de la tarjeta. Márcalo como efectivo para cancelar.',
         markAsCash: 'Marcar como efectivo',
-        confirmApproveReportViolations: {
-            title: '¿Aprobar de todos modos?',
-            description: 'Este informe tiene infracciones de la política. ¿Seguro que quieres aprobarlo sin realizar cambios?',
-        },
+        confirmApproveReportViolations: {title: '¿Aprobar de todas formas?', description: 'Este informe tiene infracciones de la política. ¿Seguro que quieres aprobarlo sin hacer cambios?'},
         confirmSubmitReportViolations: {
             title: '¿Enviar informe?',
             description: 'Este informe tiene infracciones de política. ¿Seguro que quieres enviarlo sin hacer cambios?',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index ec6aa169..1bb98cb1 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -1547,7 +1547,7 @@ const translations: TranslationDeepObject<typeof en> = {
         markAsCash: 'Marquer comme espèces',
         confirmApproveReportViolations: {
             title: 'Approuver quand même ?',
-            description: 'Ce rapport contient des violations de la politique. Voulez-vous vraiment approuver ce rapport sans le modifier ?',
+            description: 'Cette note de frais comporte des violations de politique. Voulez-vous vraiment l’approuver sans y apporter de modifications ?',
         },
         confirmSubmitReportViolations: {
             title: 'Soumettre le rapport ?',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 63961583..dff745c8 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -1536,10 +1536,7 @@ const translations: TranslationDeepObject<typeof en> = {
         pendingMatch: 'Corrispondenza in sospeso',
         pendingMatchWithCreditCardDescription: 'Ricevuta in attesa di abbinamento con la transazione della carta. Contrassegna come contante per annullare.',
         markAsCash: 'Segna come contante',
-        confirmApproveReportViolations: {
-            title: 'Approvare comunque?',
-            description: 'Questo report presenta violazioni delle regole. Vuoi davvero approvarlo senza apportare modifiche?',
-        },
+        confirmApproveReportViolations: {title: 'Approvi comunque?', description: 'Questo report presenta violazioni della policy. Vuoi davvero approvarlo senza apportare modifiche?'},
         confirmSubmitReportViolations: {
             title: 'Invia il rapporto?',
             description: 'Questo rapporto presenta violazioni delle norme. Sei sicuro di volerlo inviare senza apportare modifiche?',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index d6b181f2..48ec73b9 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -103,7 +103,7 @@ const translations: TranslationDeepObject<typeof en> = {
         saveChanges: '変更を保存',
         submit: '送信',
         submitAnyway: 'とにかく送信',
-        approveAnyway: 'それでも承認',
+        approveAnyway: 'このまま承認する',
         markAsDone: '完了にする',
         markAsDoneAnyway: 'とにかく完了にする',
         submitted: '送信済み',
@@ -1519,10 +1519,7 @@ const translations: TranslationDeepObject<typeof en> = {
         pendingMatch: '保留中の照合',
         pendingMatchWithCreditCardDescription: 'レシートはカード取引との照合待ちです。現金としてマークしてキャンセルします。',
         markAsCash: '現金としてマーク',
-        confirmApproveReportViolations: {
-            title: 'それでも承認しますか?',
-            description: 'このレポートにはポリシー違反があります。変更せずに承認してもよろしいですか?',
-        },
+        confirmApproveReportViolations: {title: 'それでも承認しますか?', description: 'このレポートにはポリシー違反があります。変更を行わずに承認してもよろしいですか?'},
         confirmSubmitReportViolations: {
             title: 'レポートを送信しますか?',
             description: 'このレポートにはポリシー違反があります。変更を加えずに送信してもよろしいですか?',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index c7181797..f4772584 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -1536,7 +1536,7 @@ const translations: TranslationDeepObject<typeof en> = {
         markAsCash: 'Markeren als contant',
         confirmApproveReportViolations: {
             title: 'Toch goedkeuren?',
-            description: 'Dit rapport bevat beleidsovertredingen. Weet je zeker dat je het zonder wijzigingen wilt goedkeuren?',
+            description: 'Dit rapport bevat beleidsinbreuken. Weet je zeker dat je het wilt goedkeuren zonder wijzigingen aan te brengen?',
         },
         confirmSubmitReportViolations: {
             title: 'Rapport verzenden?',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 020a0123..abbad253 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -1574,10 +1574,7 @@ const translations: TranslationDeepObject<typeof en> = {
         pendingMatch: 'Oczekujące dopasowanie',
         pendingMatchWithCreditCardDescription: 'Oczekuje na dopasowanie paragonu do transakcji kartą. Oznacz jako gotówkę, aby anulować.',
         markAsCash: 'Oznacz jako gotówkę',
-        confirmApproveReportViolations: {
-            title: 'Zatwierdzić mimo to?',
-            description: 'Ten raport zawiera naruszenia zasad. Czy na pewno chcesz go zatwierdzić bez wprowadzania zmian?',
-        },
+        confirmApproveReportViolations: {title: 'Zatwierdzić mimo to?', description: 'Ten raport zawiera naruszenia zasad. Na pewno chcesz go zatwierdzić bez wprowadzania zmian?'},
         confirmSubmitReportViolations: {
             title: 'Wysłać raport?',
             description: 'Ten raport zawiera naruszenia zasad. Czy na pewno chcesz go wysłać bez wprowadzania zmian?',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index c067baf4..a003ab72 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -1536,10 +1536,7 @@ const translations: TranslationDeepObject<typeof en> = {
         pendingMatch: 'Correspondência pendente',
         pendingMatchWithCreditCardDescription: 'Recibo aguardando correspondência com transação do cartão. Marque como dinheiro para cancelar.',
         markAsCash: 'Marcar como dinheiro',
-        confirmApproveReportViolations: {
-            title: 'Aprovar mesmo assim?',
-            description: 'Este relatório tem violações da política. Tem certeza de que deseja aprová-lo sem fazer alterações?',
-        },
+        confirmApproveReportViolations: {title: 'Aprovar mesmo assim?', description: 'Este relatório tem violações da política. Tem certeza de que quer aprová‑lo sem fazer alterações?'},
         confirmSubmitReportViolations: {
             title: 'Enviar relatório?',
             description: 'Este relatório tem violações de política. Tem certeza de que deseja enviá-lo sem fazer alterações?',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index dd8eab37..047d5e96 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -1472,10 +1472,7 @@ const translations: TranslationDeepObject<typeof en> = {
         pendingMatch: '待匹配',
         pendingMatchWithCreditCardDescription: '收据正在等待与卡片交易匹配。将其标记为现金以取消。',
         markAsCash: '标记为现金',
-        confirmApproveReportViolations: {
-            title: '仍然批准?',
-            description: '此报告存在违反政策的情况。确定要在不作更改的情况下批准吗?',
-        },
+        confirmApproveReportViolations: {title: '仍然批准?', description: '此报表存在策略违规。确定要在不进行任何更改的情况下批准吗?'},
         confirmSubmitReportViolations: {
             title: '提交报告?',
             description: '此报告存在违反政策的情况。您确定要不做任何更改就提交吗?',

Note

You can apply these changes to your branch by copying the patch to your clipboard, then running pbpaste | git apply 😉

View workflow run

@dukenv0307

Copy link
Copy Markdown
Contributor

@MelvinBot

  1. Complete the checklist in PR description
  2. Fix the failing test
  3. Apply the translation Show an Approve anyway confirmation for report violations #106274 (comment)

Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
@MelvinBot

MelvinBot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 Web test steps verification results: ❌ fail

Pushed 57a6c9d4: fixed the six failing tests, added confirmation/cancellation coverage, and applied all ten locale translations; 11 focused tests, lint, typecheck, spelling, and Storybook passed. Checklist boxes were marked at your direction with an explicit verification caveat; full Jest timed out, and manual Web testing remained blocked by a blank page.

Blank Web page blocking approval verification

Step Status
Header approval displays violations and confirmation controlsBlocked: blank page.
Blank Web page blocking approval verification
❌
Cancel leaves report unapprovedNot tested: UI unavailable.
❌
Approve anyway approves reportNot tested: UI unavailable.
❌
Clean report approves without warningNot tested: UI unavailable.
❌
Chat preview displays the same warningNot tested: UI unavailable.
❌
Bulk approval displays one warning and approves allNot tested: UI unavailable.
❌
No JavaScript console errorsUnverified: no flows ran; console inspection unavailable.
❌

view run · no recording available

@dukenv0307

dukenv0307 commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
  • I verified tests pass on all platforms & I tested again on:
    • Android: HybridApp
    • Android: mWeb Chrome
    • iOS: HybridApp
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified any copy / text that was added to the app is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If the PR adds or modifies the UI:
    • I asked an AI agent to review the changes for accessibility issues and addressed its findings.
    • I tested with a screen reader (VoiceOver on macOS) and verified all new/changed elements are reachable with a logical focus order.
    • I verified all new/changed elements have meaningful accessible names and roles.
    • I verified state changes are announced (e.g. checked/unchecked, expanded/collapsed, selected).
  • For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: HybridApp
Android: mWeb Chrome
iOS: HybridApp
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-11-07.at.10.50.42.mov
Screen.Recording.2026-11-07.at.10.56.03.mov

@dukenv0307

Copy link
Copy Markdown
Contributor

@Julesssss All yours!

const confirmApproveReportViolations = useConfirmApproveReportViolations({
report: reportForViolations,
policy: policyForViolations,
transactions: liveReportTransactions,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The row and 'Approve anyway?' modal can be different. If a report hasn't been opened yet, its expenses only come from the Search results, not from what's loaded locally. The row still shows the violation, but the modal only checks the loaded expenses, finds none, and approves straight away with no warning.

ReportListItemHeader has the same issue. Bulk approve already checks both, so could we do the same here and add a test for that case?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense. @MelvinBot Merge main + fix

@MelvinBot MelvinBot Nov 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Web test steps verification results: ❌ fail

Merged latest main and pushed the snapshot-warning fix in 4860181d, covering report rows, grouped headers, wide-layout approval, and bulk approval; 162 focused tests and static checks passed. Full Jest timed out, and browser verification was blocked by an unavailable Web session.

Step Status
Snapshot-only report row warns before approvalBrowser blocked; regression tests passed.
⚠️
Grouped report header warns before approvalBrowser blocked; regression tests passed.
⚠️
Cancel preserves approval state and selectionBrowser blocked; cancellation tests passed.
⚠️
Wide and bulk approval warn consistentlyBrowser blocked; regression tests passed.
⚠️

view run · no recording available

MelvinBot and others added 2 commits November 13, 2026 02:38
Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
@dukenv0307

Copy link
Copy Markdown
Contributor

@MelvinBot fix the failing test

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The failing check is React Compiler Compliance, not Jest—all test jobs passed.

I reproduced the cache regressions, but couldn’t fully resolve them safely: one selector still lost its cache guard after the attempted fixes. I reverted those attempts; no changes were pushed.


view run

@dukenv0307

Copy link
Copy Markdown
Contributor

@MelvinBot Is it related to this PR?

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Yes—it’s related to this PR, not an unrelated/flaky test.

The compiler check confirms that computations cached on main now run on every render in three files changed by this PR. That’s a caching/performance regression; Jest tests still pass, and no user-visible slowdown has been measured.


view run

@dukenv0307

Copy link
Copy Markdown
Contributor

@MelvinBot New inline computes (warningData = getReportApprovalWarningData(...), and the [...new Set(...)] transaction-ID union) feed hook calls mid-render. React Compiler memo scopes can't span a hook, so it dropped caching on those + upstream computes (getNonEmptyStringOnyxID, isInvoiceReport).

Solution: Moved the computations into their own hooks (useReportApprovalWarningData, useLiveViolationsForSnapshotTransactions) so call sites chain hook results instead. Behavior unchanged; compliance check + lint + affected tests pass.

Pls evaluate and fix

Co-authored-by: Nguyen Van Duc <dukenv0307@users.noreply.github.com>
@MelvinBot

Copy link
Copy Markdown
Contributor Author

Validated and implemented your approach in b24de3c5.

CI’s cache-guard comparison passes locally—all three regressions are cleared. All 164 affected tests, lint, typecheck, formatting, spelling, and Storybook checks passed.

Full Jest timed out; no full-suite pass is claimed.


view run

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Melvin-Test-Android Melvin-Test-Web Triggers Melvin to run the testing steps of the PR on web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants