Skip to content

[NoQA] feat: implement mergeReports() action#95182

Merged
marcochavezf merged 24 commits into
Expensify:mainfrom
dmkt9:feat/mergeReports-action
Jul 16, 2026
Merged

[NoQA] feat: implement mergeReports() action#95182
marcochavezf merged 24 commits into
Expensify:mainfrom
dmkt9:feat/mergeReports-action

Conversation

@dmkt9

@dmkt9 dmkt9 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Explanation of Change

Add the constants and command types that the merge action and bulk-action menu depend on.

  • CONST.SEARCH.BULK_ACTION_TYPES.MERGE_REPORTS — namespaced under SEARCH, matching the existing bulk-action constants.
  • WRITE_COMMANDS.MERGE_REPORTS: 'MergeReports' in src/libs/API/types.ts.
  • MergeReportsParams in WriteCommandParameters:
    • destinationReportID: string
    • sourceReportIDs: string[] (a real array, derived as selected minus destination — not a JSON-stringified string)

Add the mergeReports() action that fires WRITE_COMMANDS.MERGE_REPORTS with optimistic data.

  • Reuse the optimistic-data helpers from changeTransactionsReport() in src/libs/actions/Transaction.ts rather than reimplementing "move + delete empty" in Report.ts. That function already moves transactions, updates source totals/counts, manages transaction threads, and tracks staleReportIDs.
  • Optimistic data: move every transaction from each source report into the destination, then mark each emptied source report as deleted (comments included).
  • Include ONYXKEYS.COLLECTION.SNAPSHOT updates.

Fixed Issues

$ #94872
PROPOSAL:

Tests

  • Verify that no errors appear in the JS console

Offline tests

QA Steps

// TODO: These must be filled out, or the issue title must include "[No QA]."

  • Verify that no errors appear in the JS console

PR Author Checklist

  • 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 followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and 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 followed the guidelines as stated in the Review Guidelines
  • 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 any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • 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.
  • 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

@dmkt9 dmkt9 changed the title feat: implement mergeReports() action [NoQA] feat: implement mergeReports() action Jul 2, 2026
@dmkt9

dmkt9 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@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: 69689fffa5

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

Comment thread src/libs/actions/Report/index.ts Outdated
@dmkt9

dmkt9 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@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: 2683e7334e

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

Comment thread src/libs/actions/Report/index.ts
Comment thread src/libs/actions/Report/index.ts
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

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.

Files with missing lines Coverage Δ
src/CONST/index.ts 94.81% <ø> (ø)
src/libs/API/types.ts 100.00% <ø> (ø)
src/libs/ReportUtils.ts 87.04% <83.33%> (-0.03%) ⬇️
src/libs/actions/Transaction.ts 75.76% <92.30%> (+0.76%) ⬆️
src/libs/actions/Report/index.ts 71.65% <93.26%> (+1.00%) ⬆️
... and 8 files with indirect coverage changes

@dmkt9

dmkt9 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@dmkt9

dmkt9 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@MelvinBot review

@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: d9ddc0ed44

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

Comment thread src/libs/actions/Report/index.ts Outdated
Comment thread src/libs/actions/Report/index.ts Outdated
@MelvinBot

Copy link
Copy Markdown
Contributor

🤖 Code review — overall this is a clean, well-tested implementation. The refactor that extracts getChangeTransactionsReportOnyxData correctly preserves the original !transactionsMoved early-return behavior (Transaction.ts:1655), reuses the existing move helper per the issue's guidance, and the success/failure/snapshot tests are thorough. A few things to address:

1. allReports is passed but never used (shadowed by the module global) 🐞

MergeReportsProps declares allReports and callers/tests pass it, but the mergeReports destructuring omits it, so every allReports?.[...] in the body reads the module-global allReports, not the prop. The tests only pass because Onyx populates the global. A caller that passes a scoped/fresh allReports (e.g. a stale search context) would have it silently ignored.

Fix: either destructure allReports from props and use it (and pass it into getChangeTransactionsReportOnyxData instead of the global), or drop it from MergeReportsProps. Note changeTransactionsReport itself already honors its allReports param via allReportsParam ?? allReports, so destructuring is the consistent choice.

2. transactionIDToReportActionAndThreadData can serialize to undefined ⚠️

When no transactions move, getChangeTransactionsReportOnyxData returns undefined, the ?? {} leaves this field undefined, and JSON.stringify(undefined) returns the JS value undefined (not "{}") — yet the command still fires and deletes the source reports. Please confirm merging empty reports is impossible upstream; otherwise default it to {} (or bail out early).

3. Dead guard in the changeTransactionsReport wrapper (nit)

if (!transactionsMoved) return; is unreachable — getChangeTransactionsReportOnyxData already returns undefined in that case, which the earlier if (!changeTransactionsReportOnyxData) return; catches. Harmless, but can be removed for clarity.

4. Multi-source shared parent chat (worth a sanity check)

clearChatIOUReportID is called once per source report. When several sources share the same policy-expense chat, hasOutstandingChildRequest is recomputed each iteration from the pre-merge global chatReport, without accounting for the previously-processed source already being removed. Likely fine (same computed value, MERGE), but please verify the >1 source, same chat case.

Minor / non-blocking
  • Snapshot on success: source reports get pendingAction: DELETE in the optimistic snapshot but aren't removed from SNAPSHOT on success (only the REPORT/REPORT_ACTIONS collections are nulled). This mirrors deleteAppReport, so it presumably relies on search hiding pending-delete rows or a backend snapshot refresh — flagging only for confirmation.

None of these are blockers except possibly #1. Nice work on the refactor and test coverage.


Reply with @MelvinBot <feedback> to refine this review.

@dmkt9

dmkt9 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@dmkt9

dmkt9 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@MelvinBot review

@MelvinBot

Copy link
Copy Markdown
Contributor

🤖 Re-review (head beb63d2) — thanks for the quick turnaround. All four actionable items from my previous review are resolved:

  1. allReports now honoredmergeReports destructures allReports: allReportsParam and uses const reports = allReportsParam ?? allReports consistently, including passing allReports: reports into getChangeTransactionsReportOnyxData.
  2. Empty-move edge case — an early if (!changeTransactionsReportOnyxData) return; now bails before building delete data / serializing params, so no more JSON.stringify(undefined) or deleting source reports when nothing moved.
  3. Dead guard removed — the redundant if (!transactionsMoved) return; is gone from the changeTransactionsReport wrapper.
  4. Multi-source shared chat — nicely handled by making clearChatIOUReportID take the full source-report array and extending hasOutstandingChildRequest to accept an array and exclude every source report. The signature change is backward-compatible (string / single-report callers behave as before).

Two minor, non-blocking notes:

  • clearChatIOUReportID failure key when no chat is found: failureData is pushed unconditionally to ${REPORT}${chatReport?.reportID}, so if chatReport is ever undefined it writes to the report_undefined key. Shouldn't happen for merged expense reports (they always have a parent chat), but a chatReport guard around the failure push would make it bulletproof.
  • Snapshot not cleared on success: source reports get pendingAction: DELETE in the optimistic snapshot but aren't removed from SNAPSHOT on success. This matches deleteAppReport's pattern, so it's consistent — flagging only in case backend snapshot refresh isn't relied on here.

LGTM overall — clean refactor and solid test coverage. 👍


Reply with @MelvinBot <feedback> to refine this review.

@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: beb63d2436

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

Comment thread src/libs/actions/Report/index.ts
@dmkt9

dmkt9 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@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: 8293411130

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

Comment thread src/libs/actions/Report/index.ts Outdated
Comment thread src/libs/actions/Report/index.ts
@MelvinBot

Copy link
Copy Markdown
Contributor

Review

Solid, well-factored PR. Checks are green (typecheck, ESLint, knip, tests all pass) and the refactor of changeTransactionsReportgetChangeTransactionsReportOnyxData + the shared buildOptimisticDeleteParentReportAction / clearChatIOUReportID helpers is a clean way to reuse the existing "move + delete empty" logic instead of reimplementing it. A few things worth confirming before merge — the first is the only one I'd consider a blocker:

1. Silent behavior change in deleteAppReport's failure rollback ⚠️

Extracting the chat-pointer logic into clearChatIOUReportID changes what deleteAppReport restores on failure. On main the failure data restored report?.hasOutstandingChildRequest — i.e. the deleted expense report's value written onto the chat report's key. The refactor now restores chatReport.hasOutstandingChildRequest (the chat's own prior value).

The new value looks more correct to me, but this is a semantic change to an existing flow that's unrelated to the merge feature. Please confirm it's intentional and that deleteAppReport's failure-rollback path is covered by a test so this doesn't silently regress.

2. New symbols have no callers yet

mergeReports() and CONST.SEARCH.BULK_ACTION_TYPES.MERGE_REPORTS aren't referenced anywhere in src/ (only in the new test). That's expected for a foundational PR, but worth stating explicitly in the description that the UI/bulk-action wiring lands in a follow-up so reviewers don't look for it here.

Other things I checked (no action needed)
  • changeTransactionsReport's if (!changeTransactionsReportOnyxData) return; is not dead code — getChangeTransactionsReportOnyxData returns undefined via if (!transactionsMoved) return;. mergeReports correctly guards this with changeTransactionsReportOnyxData ?? {} and default = [], so an empty-report merge still deletes the sources. 👍
  • skippedReportIDs correctly prevents the move logic from writing report-action/total updates to source reports that the delete logic then SETs to null — no conflicting writes.
  • Snapshot successData — no cleanup of the optimistic pendingAction: DELETE on the snapshot, but this mirrors the existing deleteAppReport pattern (L6398), so it's consistent.
  • getMockFetch helper in ReportTest.ts is a nice way to drop 8 no-unsafe-type-assertion seatbelt entries (58 → 50).

I can't run the app to exercise the merge flow end-to-end (there's no UI entry point in this PR), so the review is code-level only. Since the PR is [NoQA] and purely adds the action + optimistic data, that's appropriate — but manual verification will be needed once the bulk-action UI is wired up.

@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: 6055da4b47

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

key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
value: {
hasOutstandingChildRequest: hasOutstandingChildRequest(chatReport, reports, currentUserEmailParam, currentUserAccountIDParam, allTransactionViolations, bankAccountList),
...(shouldClearChatIOUReportID ? {iouReportID: null} : {}),

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 Preserve the destination report pointer when merging

When mergeReports deletes a source report that is currently stored as the policy chat's iouReportID, this helper always clears the pointer to null. In a merge, however, the expenses are moved into destinationReportID, so the chat still has an active outstanding report; clearing the pointer makes optimistic/offline state behave as if there is no active expense report until server data comes back. Pass the destination report through the merge path and set iouReportID to that report instead of always nulling it for source-report merges.

Useful? React with 👍 / 👎.

@MelvinBot

Copy link
Copy Markdown
Contributor

Regression scan

No functional regressions found in the success paths — the refactor is backward-compatible by construction. I traced every existing caller of the two touched shared functions:

  • changeTransactionsReport (11 callers: SearchTransactionsChangeReport, IOURequestEditReport, useReportSelectionActions, etc.) all use the public wrapper, which reproduces the original API.write params and the if (!transactionsMoved) return; early-exit. Every new skippedReportIDs guard is a no-op when the arg is omitted — the new Set(skippedReportIDs ?? []) is empty for existing callers, so none of the continues fire. ✅
  • hasOutstandingChildRequest — the new array overload is logically identical to the old code for the string and Report-object inputs. All 7 existing callers (PayMoneyRequest, DeleteMoneyRequest, RejectMoneyRequest, ReportWorkflow) pass a string or a Report; only the new merge code passes an array. For strings, excludedReportIDSet.has(iouReportID) ≡ the old iouReportID === iouReportOrID; for objects the set is empty, matching the old typeof === 'string' guard. ✅

⚠️ One behavior change to an existing flow — deleteAppReport failure rollback (untested)

Pulling the chat-pointer logic into clearChatIOUReportID changes deleteAppReport's failure data in two ways:

  1. Restored value changed. On main the failure rollback wrote hasOutstandingChildRequest: report?.hasOutstandingChildRequest — the deleted expense report's field — onto the chat report's key. It now restores chatReport.hasOutstandingChildRequest (the chat's own prior value). The new value is the correct one to roll back to, so this reads as an incidental bug fix, not a regression — but it's an unannounced change to an unrelated flow.
  2. Now conditional. The failure entry is only pushed when chatReport is truthy (previously unconditional). This avoids a stray write to a report_undefined key when the chat isn't cached — also an improvement.

Risk: low, but unverified — the deleteAppReport test block has three cases and none simulate a failure (mockFetch.fail()), so this rollback change isn't covered. The new mergeReports failure path is tested (handles failure case...), so the gap is only on the pre-existing delete flow the refactor touched.

Recommendation: confirm the deleteAppReport rollback change is intended and add a failure-path test asserting the chat report's hasOutstandingChildRequest (and iouReportID) roll back correctly. Everything else is a safe, mechanical extraction.

How I checked

Checked out the PR branch and compared each extracted helper against origin/main line-by-line, then grepped all callers of changeTransactionsReport and hasOutstandingChildRequest in src/ to confirm none exercise the new array/skippedReportIDs code paths. Inspected the deleteAppReport describe block for mockFetch.fail() coverage (none present). All CI checks (typecheck, ESLint, knip, 8 test shards) are green.

Comment thread src/libs/actions/Transaction.ts
@situchan

situchan commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

mergeReports() is not called anywhere so NAB but please address above review comments in next PR.

@melvin-bot

melvin-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

We did not find an internal engineer to review this PR, trying to assign a random engineer to #94872 as well as to this PR... Please reach out for help on Slack if no one gets assigned!

@melvin-bot
melvin-bot Bot requested a review from marcochavezf July 9, 2026 21:20
@marcochavezf

Copy link
Copy Markdown
Contributor

Conflicts

@dmkt9

dmkt9 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

Conflicts

Thanks. Conflicts resolved

@marcochavezf

Copy link
Copy Markdown
Contributor

Oops conflicts again

@dmkt9

dmkt9 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

@marcochavezf This is ready for review again. Thank you.

marcochavezf
marcochavezf previously approved these changes Jul 14, 2026

@marcochavezf marcochavezf left a comment

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.

LGTM, thanks!

@dmkt9

dmkt9 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@marcochavezf This PR is still waiting to be merged.

@marcochavezf
marcochavezf merged commit f9a66a1 into Expensify:main Jul 16, 2026
35 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🚧 marcochavezf has triggered a test Expensify/App build. You can view the workflow run here.

@OSBotify

Copy link
Copy Markdown
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/marcochavezf in version: 9.4.36-0 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

@MelvinBot

Copy link
Copy Markdown
Contributor

🤖 Help site review: no changes required.

This PR adds internal plumbing for a merge-reports capability and does not change any documented, user-facing behavior:

  • A new WRITE_COMMANDS.MERGE_REPORTS command and MergeReportsParams type
  • A CONST.SEARCH.BULK_ACTION_TYPES.MERGE_REPORTS constant
  • The mergeReports() action with optimistic data (reusing helpers from changeTransactionsReport())
  • A refactor of hasOutstandingChildRequest to accept an array of reports
  • Unit tests for the new action

There's no new UI, copy, menu label, or settings surface shipped here — it's foundational action-layer code that the merge action and bulk-action menu will depend on later. The one existing merge-related help article, How to Merge Duplicate Expenses, covers merging duplicate expenses/transactions, which is a distinct, already-documented feature and is unaffected by this change.

If a follow-up PR wires up a user-facing "merge reports" flow (e.g. a bulk-action menu item or button), that would be the right time to add or update help site articles.

No draft PR was created since no documentation updates are needed.

@dmkt9, please confirm this assessment. If you believe a user-facing behavior here does warrant a help site update, let me know and I'll create the draft PR.

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.

6 participants