Skip to content

Remove broken-card task and RBR after a 90-day grace period while keeping the error#93523

Merged
MariaHCD merged 21 commits into
Expensify:mainfrom
wildan-m:wildan/91451-broken-card-90-day-grace
Jul 10, 2026
Merged

Remove broken-card task and RBR after a 90-day grace period while keeping the error#93523
MariaHCD merged 21 commits into
Expensify:mainfrom
wildan-m:wildan/91451-broken-card-90-day-grace

Conversation

@wildan-m

@wildan-m wildan-m commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Explanation of Change

A personal or company card whose connection has broken keeps prompting the user indefinitely: the time-sensitive home task and the red dot (RBR) pointing at the broken connection stay forever, no matter how long the connection has gone unresolved. Both surfaces are driven by a single derived signal that only looks at the latest connection status — there is no notion of how long the connection has been failing, so a years-old broken connection nags exactly as much as one that broke yesterday.

This adds a 90-day grace period to that single signal: once a connection has been broken and unresolved for 90 days, it stops feeding the task and the red dots. The age is measured from the connection's last successful refresh, which does not advance while the connection is failing, so it accurately reflects how long the connection has been broken (and if that timestamp is missing we keep prompting, to stay on the safe side). The error stored on the card is deliberately left alone, so the card still shows as broken on its own page and stays fixable — under 90 days nothing changes, and past 90 days only the proactive prompting goes away.

Fixed Issues

$ #91451
PROPOSAL: #91451 (comment)

Tests

This change only affects shared logic (no platform-specific code), so it behaves the same on web, mWeb, iOS, and Android.

A broken card connection can't be created through normal use on demand — use the Mock Bank test feed (available on staging or a dev build):

  1. In a workspace you're an admin of, go to Company cards → Add cards → United States → Direct feed → Mock Bank, then assign one of the mock cards to yourself.
  2. Open the card's details and tap "Break connection (Testing)" to break the feed.
  3. While broken under 90 days (existing behaviour): confirm it surfaces — a "Fix … company card connection" task on Home (in the Time sensitive section), and on the workspace Company cards page a red "Card feed connection is broken…" banner plus red dots on the Company cards menu row and the Workspaces tab.
  4. Once broken for 90+ days (the change): age the connection's last successful update to 90 or more days ago (script below), then confirm the task, banner, and all those red dots are gone — but the card is still listed and still fixable (Update card still works). Only the prompting is removed, not the error.
  5. With a broken connection that has no last-update timestamp, it keeps surfacing (fail-safe).
  6. Personal cards behave the same: after 90 days the Home task and the Wallet row's red dot are removed, while the card keeps its own broken state (its row in the Wallet list and the "Your card connection is broken." / Fix card action on its detail page stay).
  7. No JS console errors.

Aging a broken connection past 90 days (dev build — there's no UI to backdate it). Paste this in the browser JS console; it sets every broken card's last update to 100 days ago, and also updates the workspace feed list that the company-card surfaces read:

(async () => {
    const IGNORED = [200, 434, 531, 530, 500, 666]; // CONST.COMPANY_CARDS.BROKEN_CONNECTION_IGNORED_STATUSES
    const d = new Date(Date.now() - 100 * 864e5), p = (n) => String(n).padStart(2, '0');
    const old = `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
    const cards = (await Onyx.get('cardList')) ?? {};
    for (const [id, c] of Object.entries(cards)) {
        if (!c?.lastScrapeResult || IGNORED.includes(c.lastScrapeResult)) continue;
        await Onyx.merge('cardList', {[id]: {lastScrape: old}});
        if (c.fundID && c.fundID !== '0') await Onyx.merge(`cards_${c.fundID}_${c.bank}`, {[id]: {lastScrape: old}});
    }
})();

On mWeb the same console works; on native use the React Native debugger (same Onyx), a connection genuinely 90+ days old, or temporarily set CONST.COMPANY_CARDS.BROKEN_CONNECTION_DISMISS_AFTER_DAYS to 0.

Verified locally on web with a real Mock Bank feed: the Home task, the "Card feed connection is broken" banner, and the red dots all show while broken under 90 days, and all disappear at 100 days while the card stays listed with its broken state intact — confirmed for both the company and personal paths.

Offline tests

This change only gates a value derived from already-local card data and the device date — no network is involved. It behaves identically offline: a connection broken past the 90-day window stays unprompted, and one within the window keeps prompting, whether online or offline.

QA Steps

This change only affects how long a broken card connection keeps prompting the user, so please treat it as a regression test around the card feature. The behaviour is the same on all platforms (web, mWeb, iOS, Android), so any one platform is fine.

  1. With a card whose bank connection is broken and was last updated recently (under 90 days), confirm it still surfaces as before — the "Fix … company card connection" task on Home, and the red "Card feed connection is broken" banner + red dots on the workspace Company cards page (and, for a personal card, the red dot on the Wallet row). This is unchanged and must keep working.
  2. With a card whose bank connection has been broken for 90 days or more (last successfully updated 90+ days ago — this needs a test account/connection set up that way), confirm the task, banner, and red dots are gone, while the card is still listed and still fixable (its broken state is kept, not deleted).
  3. Confirm the rest of the card feature is unaffected — assigning, unassigning, updating, and healthy (non-broken) cards all behave exactly as before.

If a 90-days-broken connection isn't available as test data, the after-90-days removal is also covered by automated unit tests; the essential manual checks are step 1 (recently-broken connections still prompt) and step 3 (no regressions elsewhere in the card feature).

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 shown in the product is localized by adding it to src/languages/* files and using the translation method
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • 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)
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • 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)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • 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.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • 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
Kapture.2026-06-26.at.04.33.41.mp4

@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

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

Files with missing lines Coverage Δ
src/CONST/index.ts 94.81% <ø> (ø)
src/libs/CardUtils.ts 82.50% <100.00%> (+0.15%) ⬆️
...libs/actions/OnyxDerived/configs/cardFeedErrors.ts 95.50% <100.00%> (ø)
... and 7 files with indirect coverage changes

@wildan-m wildan-m marked this pull request as ready for review June 25, 2026 21:42
@wildan-m wildan-m requested review from a team as code owners June 25, 2026 21:42
@melvin-bot melvin-bot Bot requested review from heyjennahay and jayeshmangwani and removed request for a team June 25, 2026 21:42
@melvin-bot

melvin-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

@jayeshmangwani 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]

@melvin-bot melvin-bot Bot removed the request for review from a team June 25, 2026 21:42

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

ℹ️ 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/OnyxDerived/configs/cardFeedErrors.ts
wildan-m added 3 commits June 26, 2026 05:39
…nection grace

CARD_FEED_ERRORS depends on the current date via isBrokenConnectionPastDismissThreshold,
but its Onyx dependencies were only card/feed keys. A connection crossing the 90-day
threshold while the app stayed open with no card/feed update would not recompute, so the
home task/RBR could linger. Add CURRENT_DATE (day-granularity) as a trigger-only dependency
so the value re-derives when the day changes; the compute body already reads the live clock.
Update compute() test call sites for the resulting 4-tuple input.

Addresses Codex automated-review feedback on PR Expensify#93523.
# Conflicts:
#	src/CONST/index.ts
#	tests/unit/CardUtilsTest.ts
@jayeshmangwani

Copy link
Copy Markdown
Contributor

@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: 96096444cc

ℹ️ 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/CardUtils.ts Outdated
if (!isCardConnectionBroken(card) || !card.lastScrape) {
return false;
}
return DateUtils.getDifferenceInDaysFromNow(new Date(card.lastScrape)) >= CONST.COMPANY_CARDS.BROKEN_CONNECTION_DISMISS_AFTER_DAYS;

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 Parse lastScrape with the app date parser

When lastScrape uses the existing backend/fixture format like 2024-11-27 11:00:53, relying on new Date(card.lastScrape) is not portable across the supported JS engines; if it produces an invalid date, differenceInDays returns NaN and the comparison is always false, so broken connections older than 90 days keep showing the task/RBR. The card detail pages already parse this field via getLocalDateFromDatetime, so this threshold check should use the same normalized parsing instead of the native parser.

Useful? React with 👍 / 👎.

dependencies: [ONYXKEYS.CARD_LIST, ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST, ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER],
// CURRENT_DATE (day-granularity) is a trigger-only dependency: it makes this value recompute when the day rolls over so the
// 90-day broken-connection grace period (isBrokenConnectionPastDismissThreshold) is re-evaluated even if no card/feed data changes.
dependencies: [ONYXKEYS.CARD_LIST, ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST, ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER, ONYXKEYS.CURRENT_DATE],

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 Recompute the grace period on native day changes

This CURRENT_DATE dependency only advances where setCurrentDate is actually called; I checked the wiring and it is started from the web platform setup, while src/setup/platformSetup/index.native.ts is a no-op. On iOS/Android, if a broken card crosses the 90-day boundary while the app remains open and no card/feed data changes, the derived value never recomputes, so the Home task and RBR can persist until a restart or unrelated data update.

Useful? React with 👍 / 👎.

@jayeshmangwani

Copy link
Copy Markdown
Contributor

@wildan-m, I'm trying to test this using the provided steps, but the console log doesn't work for me, it doesn't do anything. I'm not sure if I need to update something in the code first.

Also, what do you think about the suggestions #93523 (comment) and #93523 (comment) above?

wildan-m added 3 commits July 1, 2026 19:54
card.lastScrape uses the Expensify DB datetime format ("yyyy-MM-dd HH:mm:ss"). Relying on
new Date() for that non-ISO string is not portable across JS engines (Safari/JSC, Hermes) and
can produce an invalid date, making getDifferenceInDaysFromNow return NaN so the 90-day grace
would never dismiss the task/RBR. Parse explicitly with date-fns and guard against an
unparseable value (fail-safe: keep surfacing the task). Also adds an unmocked test that
exercises the real parsing. Addresses Codex review feedback on PR Expensify#93523.
Follow-up to the lastScrape parse fix: the derived-value grace-period tests used a
date-only 'yyyy-MM-dd' lastScrape, which the stricter parse('yyyy-MM-dd HH:mm:ss')
now treats as unparseable (NaN guard -> not dismissed). Use the real DB format so the
past-grace company and personal card tests exercise a valid parse.
@wildan-m

wildan-m commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@wildan-m, I'm trying to test this using the provided steps, but the console log doesn't work for me, it doesn't do anything. I'm not sure if I need to update something in the code first.

@jayeshmangwani have you toggle on "use staging server"? have you checked my browser video?

@wildan-m

wildan-m commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @jayeshmangwani!

Suggestion 1 (date parsing) — agree, real bug, fixed in 1969d61acd8. lastScrape is the DB format (2024-11-27 11:00:53); new Date() on that non-ISO string isn't portable across engines (Safari/JSC, Hermes), and an invalid parse makes the diff NaN so it would never dismiss. Now uses parse(lastScrape, 'yyyy-MM-dd HH:mm:ss', new Date()) with a NaN guard (fail-safe), plus an unmocked test covering the real parse. (Used date-fns parse rather than getLocalDateFromDatetime, which needs locale + timezone this util doesn't have.)

Suggestion 2 (native day-change recompute) — valid, but this should be a separate change. It's right that CURRENT_DATE only ticks on web (startCurrentDateUpdater → DOM events in platformSetup/index.ts; index.native.ts is a no-op). But that's the existing, accepted behavior of CURRENT_DATE — several shipped features already rely on it (ReportActionItemDate, useResetIOUType, SubmitDetailsPage, useReceiptScanDrop), so making it tick on native would change behavior for all of them and belongs in its own PR rather than being scoped into this card fix. On native the derived value still recomputes on app foreground/reconnect (AppState → reconnectApp refreshes CARD_LIST) and on restart, so the only gap is a card crossing day 90 while the app stays continuously foregrounded with no data change — a rare, self-healing edge for what is a nag removal.

@jayeshmangwani

jayeshmangwani commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

have you toggle on "use staging server"? have you checked my browser video?

Yes, @wildan-m , I have enabled Use Staging Server and also followed the steps in your video, but it's still not working for me.

I'm attaching a video below showing the exact steps I'm following.

console-copy-paste.mov

wildan-m added 2 commits July 6, 2026 10:52
# Conflicts:
#	src/libs/CardUtils.ts
#	src/libs/actions/OnyxDerived/configs/cardFeedErrors.ts
#	tests/unit/CardUtilsTest.ts
@wildan-m

wildan-m commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@jayeshmangwani I've tried multiple times locally and everything works as expected. Could you please check out the fix branch again, stop the current webpack instance, and restart webpack cleanly?

# Conflicts:
#	tests/unit/CardUtilsTest.ts
@jayeshmangwani

Copy link
Copy Markdown
Contributor

Let me try again after doing a clean restart of everything.

@jayeshmangwani

Copy link
Copy Markdown
Contributor

@wildan-m Have you tested the script against the latest code? I think the error data is coming from the cards_ onyx, while the script is looping through the cardList data.

@jayeshmangwani

Copy link
Copy Markdown
Contributor

For me, this script is working.

(async () => {
    const d = new Date(Date.now() - 100 * 864e5), p = (n) => String(n).padStart(2, '0');
    const old = `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
    await Onyx.merge('cards_22551001_oauth.mockbank.com', { '5710640066021610': { lastScrape: old } });
})();

@jayeshmangwani

jayeshmangwani commented Jul 9, 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 proper code patterns were followed (see Reviewing the code)
    • 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 verified that this PR follows the guidelines as stated in the Review Guidelines
  • 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 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 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.
  • 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.mov
Android: mWeb Chrome
mweb-chrome.mov
iOS: HybridApp
ios.mov
iOS: mWeb Safari
mweb-safati.mov
MacOS: Chrome / Safari
web.mov

Note: On the web, I ran the script from the browser console to test the PR by modifying the date to more than 90 days in the past. On the other platforms, I ran the Onyx code when the page rendered and then refreshed the app to test the PR with the same past-date data.

@jayeshmangwani jayeshmangwani 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 🚀

@melvin-bot melvin-bot Bot requested a review from MariaHCD July 9, 2026 18:13
@MariaHCD MariaHCD merged commit 62b37ab into Expensify:main Jul 10, 2026
35 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🚧 MariaHCD 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.

@mvtglobally

Copy link
Copy Markdown

@MariaHCD @jayeshmangwani Would you like to setup special accounts for us to run QA on as this requires some backend validations. Or you are able to QA internally?

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/MariaHCD in version: 9.4.33-0 🚀

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

@MelvinBot

Copy link
Copy Markdown
Contributor

Help site review — docs update needed ✅

Yes, this change affects the help site. The PR adds a 90-day grace period after which the broken-card Home task, the "Card feed connection is broken" banner, and the red dots (RBR) are removed — while the card stays broken and fixable. Two existing articles document exactly those surfaces without mentioning that they disappear after the grace period, so they're now incomplete.

I created a draft docs PR adding an FAQ entry to each:

📝 Docs PR: #95841

The HelpDot label is applied and PullerBear is requested as reviewer.

⚠️ I couldn't auto-assign you to the docs PR — wildan-m isn't an assignable collaborator on Expensify/App (the assignee API returns 404). Please self-assign it if you can.

@wildan-m, please review the linked help site PR and confirm it reflects the current behavior. Then mark the linked help site PR Ready for review

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