Skip to content

[Due for payment 2026-11-05] Chat - Action pill appears and disappears when sending messages after creating expense. #92663

Open

Description

@applause-bot

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 9.3.99-0
Reproducible in staging?: Yes
Reproducible in production?: N/A - new feature, doesn't exist in prod
If this was caught during regression testing, add the test name, ID and link from BrowserStack: #87212
Email or phone of affected tester (no customers): ibellicotest+2766@gmail.com
Issue reported by: Applause Internal Team
Bug source: Exploratory - Significant User Experience Deterioration
Device used: Motorola MotoG60 / Android 12 (Hybrid app) - Windows 11 / Chrome
App Component: Chat Report View

Action Performed:

Prerequisite: Account has at least one workspace.

  1. Open the staging.new.expensify.com wesbite.
  2. Open any workspace chat.
  3. Create a manual expense.
  4. Send a message below the just created expense.
  5. Note that a "Submit" pill appears and disappears on top of chat.
  6. Keep sending messages.
  7. Note that "Submit" pill keeps appearing and disappearing until expense is no longer visible. At that point, pill remains displayed.

Expected Result:

"Submit" pill should appear and remain visible when messages are sent below a created report.

Actual Result:

When sending messages below a created expense, "Submit" pill appears and disappears until expense is no longer visible. Pill remains displayed only when expense can´t be seen anymore.

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome Safari

Screenshots/Videos

Bug7171445_1780569402986.Action_Pill.mp4

View all open jobs on GitHub

Applause Internal Information
Exported by: Julia Ponikarchuk
Bug ID: 7171445

Issue OwnerCurrent Issue Owner: @aimane-chnaif

Activity

  1. added
    DeployBlockerCashThis issue or pull request should block deployment
    BugSomething is broken. Auto assigns a BugZero manager.
    on Jun 4, 2026
  2. applause-bot commented on Jun 4, 2026

    @applause-bot
    Author

    While Applause doesn't embed attachments for this bug, here are the links for quick view:
    https://platform.applause.com/services/links/v1/external/27027a0cf1e0d0cd392eba0ecc077e4bd8b229879a27f73e5c9ada54b0648104

  3. melvin-bot commented on Jun 4, 2026

    @melvin-bot

    You have been assigned to this deploy blocker because you recently merged this PR: #87212

  4. melvin-bot commented on Jun 4, 2026

    @melvin-bot

    💬 A slack conversation has been started in #expensify-open-source

  5. github-actions commented on Jun 4, 2026

    @github-actions
    Contributor

    👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:

    1. Identify the pull request that introduced this issue and revert it.
    2. Find someone who can quickly fix the issue.
    3. Fix the issue yourself.
  6. MelvinBot commented on Jun 4, 2026

    @MelvinBot
    Contributor

    Proposal

    What is the root cause of that problem?

    The "Submit" floating pill (added in #87212) is shown when isActionBadgeAboveViewport is true, i.e. when the target expense action sits above the visible window. That flag is computed in useReportUnreadMessageScrollTracking.ts:146-155 by comparing the target's numeric index against the max visible index:

    const isAbove = isInverted ? badgeTargetIndex > maxIndex : badgeTargetIndex < minIndex;

    The flicker comes from a stale-index recompute. Every time you send a message, a new action is prepended at index 0 of the inverted list, so every older action — including the expense — shifts up by one. actionBadgeTargetIndex is recomputed (+1) in ReportActionsList.tsx:311-317. That change fires this effect, which manually recomputes visibility using the previous viewable items:

    useReportUnreadMessageScrollTracking.ts:173-176

    useEffect(() => {
        ref.current.actionBadgeTargetIndex = actionBadgeTargetIndex;
        onViewableItemsChanged({viewableItems: ref.current.previousViewableItems, changed: []});
    }, [onViewableItemsChanged, actionBadgeTargetIndex]);

    At that moment previousViewableItems still holds the old indexes (FlatList hasn't re-reported viewability yet), so maxIndex is the pre-shift value while badgeTargetIndex is the post-shift (+1) value. Once the expense reaches the top edge of the viewport, badgeTargetIndex (old+1) > maxIndex (old) evaluates true → pill appears. A beat later FlatList fires the real onViewableItemsChanged with fresh indexes; the expense is still visible, so it flips back to false → pill disappears. Repeat on every message. When the expense finally scrolls off-screen for real, the steady-state value is correctly true, so the pill stays — exactly the reported behavior.

    Why the index comparison is the wrong primitive here

    The unread-marker path has the same manual-recompute pattern but is index-based too; the action-badge path is more fragile because the target is a fixed, old action whose index monotonically increases as you chat, guaranteeing it eventually lines up with the viewport edge where the off-by-one transient triggers. ViewToken indexes are inherently unstable across list mutations, while ViewToken key/item (the reportActionID) is stable and survives index shifts.

    What changes do you think we should make in order to solve the problem?

    Stop deriving "is the target above the viewport" from raw numeric indexes that go stale on every message. Instead determine visibility by the target reportActionID (stable) against the viewable items' keys:

    • Pass actionTargetReportActionID into the hook instead of (or alongside) actionBadgeTargetIndex.
    • In onViewableItemsChanged, set isActionBadgeAboveViewport = true only when the target ID is not among the currently viewable item keys (viewableItems.some(v => v.key === targetID) is false). Because the target's ID is unaffected by index shifts, the manual recompute with stale previousViewableItems stays consistent with the freshly computed target, eliminating the transient.

    A lighter-touch alternative: in the actionBadgeTargetIndex effect, skip the manual onViewableItemsChanged recompute and let FlatList's own viewability callback own the value — but that still leaves an index-based comparison that can misfire on other mutations, so the ID-based approach is the more robust fix.

    What alternative solutions did you explore? (Optional)

    I could not fully rule out churn in the ONYXKEYS.DERIVED.REPORT_ATTRIBUTES value (actionTargetReportActionID briefly going undefined would also toggle the pill), but the index-shift mechanism above is directly evidenced by the code and matches every detail of the repro (flicker on each send; pill stable once the expense leaves the viewport), so it is the primary root cause.

    Related

    Next Steps for Contributor+ team:
    To accept: @MelvinBot implement [this](https://github.com/Expensify/App/issues/92663) to create a draft PR.
    To refine: @MelvinBot <your feedback>
    To reject: Explain why you are rejecting Melvin's proposal.

  7. aimane-chnaif commented on Jun 4, 2026

    @aimane-chnaif
    Contributor

    This feature is gated behind production so we can demote this.
    And PR was already deployed to production.

    actionBadge={!isProduction && isActionBadgeAboveViewport ? reportAttributes?.actionBadge : undefined}
    actionBadgeBrickRoadStatus={!isProduction && isActionBadgeAboveViewport ? reportAttributes?.brickRoadStatus : undefined}

  8. added and removed
    DeployBlockerCashThis issue or pull request should block deployment
    on Jun 4, 2026
  9. 34 remaining items

  10. changed the title [-]Chat - Action pill appears and disappears when sending messages after creating expense.[/-] [+][Due for payment 2026-11-05] Chat - Action pill appears and disappears when sending messages after creating expense.[/+] on Oct 29, 2026
  11. melvin-bot commented on Oct 29, 2026

    @melvin-bot

    @aimane-chnaif / @mkhutornyi

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.24-8 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

    If no regressions arise, payment will be issued on 2026-11-05. 🎊

    The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]

  12. mkhutornyi commented on Oct 30, 2026

    @mkhutornyi
    Contributor

    Contributor+ Checklist:

    • [Contributor] The offending PR and associated issue have been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake.

      Link to the comment on the PR:
      Link to the comment on the Issue:

    • [Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.

      Link to discussion:

    • [Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.

    Regression Test Proposal

    Test:

    1. Create new account and new workspace
    2. Open workspace chat.
    3. Create a manual expense.
    4. Send a message below the just created expense.
    5. Keep sending messages.
    6. Verify that "Submit" pill doesn't briefly appear until expense preview is no longer visible.
    7. Verify that pill shows and remains displayed after preview is no longer visible.

    Do we agree 👍 or 👎

  13. mkhutornyi commented on Oct 30, 2026

    @mkhutornyi
    Contributor

    Reproducible in production?: N/A - new feature, doesn't exist in prod
    If this was caught during regression testing, add the test name, ID and link from BrowserStack: #87212

    False positive because this bug was reported after #87212 was already deployed to production

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

Metadata

Metadata

Labels

BugSomething is broken. Auto assigns a BugZero manager.EngineeringWeeklyKSv2

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions