Skip to content

[Payment due @brunovjk] Surface RuleBot in the Agent rules section#94131

Merged
puneetlath merged 8 commits into
mainfrom
yuwen-647929-rulebot-rules-surface
Jun 25, 2026
Merged

[Payment due @brunovjk] Surface RuleBot in the Agent rules section#94131
puneetlath merged 8 commits into
mainfrom
yuwen-647929-rulebot-rules-surface

Conversation

@yuwenmemon

@yuwenmemon yuwenmemon commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

@puneetlath @brunovjk please review
cc @shawnborton

Explanation of Change

When an admin creates their first Agent rule, the backend provisions a "RuleBot" agent and adds it to the workspace, but nothing ties that bot to the rules it enforces — so it feels disconnected.

This surfaces RuleBot in Workspace > Rules: under the Agent rules header, a line reads "Agent rules are enforced by [RuleBot]", where RuleBot is rendered as a UserPill (avatar + name) built from the actual agent stored on the policy (policy.ruleBotAccountID). The line appears once a RuleBot has been provisioned (i.e. after the first Agent rule); before that, only the section subtitle shows.

Depends on https://github.com/Expensify/Auth/pull/22411, which sends ruleBotAccountID to the client on a full OpenApp/ReconnectApp load — that should deploy first. Until then the field only arrives incrementally on the device that created the rule.

Fixed Issues

$ https://github.com/Expensify/Expensify/issues/647929
PROPOSAL: N/A (internal)

Tests

  1. As an admin with the Agent rules (customAgent) beta, open a workspace and go to Rules.
  2. Before any Agent rule exists, confirm the Agent rules section shows only its subtitle — no RuleBot line.
  3. Create an Agent rule (this provisions RuleBot).
  4. Confirm a line "Agent rules are enforced by" followed by a RuleBot pill (avatar + name) appears directly under the subtitle.
  5. Confirm the pill avatar/name match the RuleBot agent shown in Account > Agents.
  6. Reload the app and confirm the line persists.
  • Verify that no errors appear in the JS console

Offline tests

  1. With an Agent rule already created and the app loaded, go offline.
  2. Open Workspace > Rules and confirm the "Agent rules are enforced by [RuleBot]" line still renders from already-synced data.

QA Steps

Same as Tests (requires the customAgent beta on the account).

  • 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.
Screenshot 2026-06-22 at 1 28 51 PM Screenshot 2026-06-22 at 1 28 58 PM

Empty state does not show this UI:
Screenshot 2026-06-22 at 1 32 05 PM

@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 a45d36e6027..8c54084ed69 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -7464,7 +7464,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
             agentRules: {
                 title: 'Agentenregeln',
                 subtitle: 'Legen Sie Regeln fest, wie KI-Agenten mit Ausgaben in diesem Workspace umgehen.',
-                enforcedBy: 'Agentenregeln werden durchgesetzt von',
+                enforcedBy: 'Agentregeln werden erzwungen durch',
                 ruleBotName: 'RuleBot',
                 addRule: 'Agentenregel hinzufügen',
                 findRule: 'Agentenregel finden',
@@ -9720,7 +9720,6 @@ Hier ist ein *Testbeleg*, um dir zu zeigen, wie es funktioniert:`,
         pdfFailedBody: 'Your file could not be generated. Try again, or reach out to Concierge for help.',
         readyPartialBody: ({count, total}: {count: number; total: number}) =>
             `${count} of ${total} reports exported. If it didn't automatically download, use the button below. See which reports failed in <concierge-link>Concierge</concierge-link>.`,
-
         close: 'Close',
     },
     domain: {
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 805ca98ce21..a846c2c164f 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -7357,7 +7357,7 @@ ${amount} para ${merchant} - ${date}`,
             agentRules: {
                 title: 'Reglas del agente',
                 subtitle: 'Configura reglas para cómo los agentes de IA gestionan los gastos en este espacio de trabajo.',
-                enforcedBy: 'Las reglas de agente son aplicadas por',
+                enforcedBy: 'Las reglas del agente se aplican mediante',
                 ruleBotName: 'RuleBot',
                 addRule: 'Añadir regla de agente',
                 findRule: 'Encontrar regla de agente',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 52ac3d9e667..be90897653b 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -7491,7 +7491,7 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
             agentRules: {
                 title: 'Règles d’agent',
                 subtitle: 'Définissez des règles pour déterminer comment les agents IA gèrent les dépenses dans cet espace de travail.',
-                enforcedBy: 'Les règles d’agent sont appliquées par',
+                enforcedBy: 'Les règles des agents sont appliquées par',
                 ruleBotName: 'RuleBot',
                 addRule: 'Ajouter une règle d’agent',
                 findRule: 'Rechercher une règle d’agent',
@@ -9752,7 +9752,6 @@ Voici un *reçu test* pour vous montrer comment ça fonctionne :`,
         pdfFailedBody: 'Your file could not be generated. Try again, or reach out to Concierge for help.',
         readyPartialBody: ({count, total}: {count: number; total: number}) =>
             `${count} of ${total} reports exported. If it didn't automatically download, use the button below. See which reports failed in <concierge-link>Concierge</concierge-link>.`,
-
         close: 'Close',
     },
     domain: {
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 019cd933b85..1e0ea7cab36 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -7449,7 +7449,7 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
             agentRules: {
                 title: 'Regole agente',
                 subtitle: 'Imposta le regole su come gli agenti IA gestiscono le spese in questo spazio di lavoro.',
-                enforcedBy: 'Le regole dell’agente sono applicate da',
+                enforcedBy: 'Le regole degli agenti sono applicate da',
                 ruleBotName: 'RuleBot',
                 addRule: 'Aggiungi regola agente',
                 findRule: 'Trova regola agente',
@@ -9708,7 +9708,6 @@ Ecco una *ricevuta di prova* per mostrarti come funziona:`,
         pdfFailedBody: 'Your file could not be generated. Try again, or reach out to Concierge for help.',
         readyPartialBody: ({count, total}: {count: number; total: number}) =>
             `${count} of ${total} reports exported. If it didn't automatically download, use the button below. See which reports failed in <concierge-link>Concierge</concierge-link>.`,
-
         close: 'Close',
     },
     domain: {
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 2fd321c57ad..068a3e82bab 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -7364,7 +7364,7 @@ ${reportName}`,
             agentRules: {
                 title: 'エージェントルール',
                 subtitle: 'このワークスペースで AI エージェントが経費を処理する方法のルールを設定します。',
-                enforcedBy: 'エージェントルールの適用者:',
+                enforcedBy: 'エージェントルールは次によって適用されます',
                 ruleBotName: 'RuleBot',
                 addRule: 'エージェントルールを追加',
                 findRule: 'エージェントルールを検索',
@@ -9585,7 +9585,6 @@ ${reportName}`,
         pdfFailedBody: 'Your file could not be generated. Try again, or reach out to Concierge for help.',
         readyPartialBody: ({count, total}: {count: number; total: number}) =>
             `${count} of ${total} reports exported. If it didn't automatically download, use the button below. See which reports failed in <concierge-link>Concierge</concierge-link>.`,
-
         close: 'Close',
     },
     domain: {
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 4bab008c3ef..d6056034b1a 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -9674,7 +9674,6 @@ Hier is een *proefbon* om je te laten zien hoe het werkt:`,
         pdfFailedBody: 'Your file could not be generated. Try again, or reach out to Concierge for help.',
         readyPartialBody: ({count, total}: {count: number; total: number}) =>
             `${count} of ${total} reports exported. If it didn't automatically download, use the button below. See which reports failed in <concierge-link>Concierge</concierge-link>.`,
-
         close: 'Close',
     },
     domain: {
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index c459c60173c..73df8a8c7da 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -7416,7 +7416,7 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
             agentRules: {
                 title: 'Zasady agenta',
                 subtitle: 'Ustaw zasady dotyczące tego, jak agenci AI obsługują wydatki w tym obszarze roboczym.',
-                enforcedBy: 'Reguły agenta są egzekwowane przez',
+                enforcedBy: 'Zasady agenta są egzekwowane przez',
                 ruleBotName: 'RuleBot',
                 addRule: 'Dodaj regułę agenta',
                 findRule: 'Znajdź regułę agenta',
@@ -9659,7 +9659,6 @@ Oto *paragon testowy*, żeby pokazać Ci, jak to działa:`,
         pdfFailedBody: 'Your file could not be generated. Try again, or reach out to Concierge for help.',
         readyPartialBody: ({count, total}: {count: number; total: number}) =>
             `${count} of ${total} reports exported. If it didn't automatically download, use the button below. See which reports failed in <concierge-link>Concierge</concierge-link>.`,
-
         close: 'Close',
     },
     domain: {
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index fd8aea647ea..1e4ff576e59 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -7418,7 +7418,7 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
             agentRules: {
                 title: 'Regras do agente',
                 subtitle: 'Defina regras para como os agentes de IA lidam com despesas neste workspace.',
-                enforcedBy: 'As regras de agente são aplicadas por',
+                enforcedBy: 'As regras do agente são aplicadas por',
                 ruleBotName: 'RuleBot',
                 addRule: 'Adicionar regra de agente',
                 findRule: 'Encontrar regra de agente',
@@ -9663,7 +9663,6 @@ Aqui está um *comprovante de teste* para mostrar como funciona:`,
         pdfFailedBody: 'Your file could not be generated. Try again, or reach out to Concierge for help.',
         readyPartialBody: ({count, total}: {count: number; total: number}) =>
             `${count} of ${total} reports exported. If it didn't automatically download, use the button below. See which reports failed in <concierge-link>Concierge</concierge-link>.`,
-
         close: 'Close',
     },
     domain: {
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index a8c8cd803bb..7197edde494 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -7223,7 +7223,7 @@ ${reportName}`,
             agentRules: {
                 title: '代理规则',
                 subtitle: '为此工作区设置 AI 代理处理报销的规则。',
-                enforcedBy: '代理规则的执行者:',
+                enforcedBy: '代理规则强制执行者:',
                 ruleBotName: 'RuleBot',
                 addRule: '添加代理规则',
                 findRule: '查找代理规则',
@@ -9403,7 +9403,6 @@ ${reportName}`,
         pdfFailedBody: 'Your file could not be generated. Try again, or reach out to Concierge for help.',
         readyPartialBody: ({count, total}: {count: number; total: number}) =>
             `${count} of ${total} reports exported. If it didn't automatically download, use the button below. See which reports failed in <concierge-link>Concierge</concierge-link>.`,
-
         close: 'Close',
     },
     domain: {

Note

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

View workflow run

@yuwenmemon yuwenmemon marked this pull request as ready for review June 22, 2026 17:57
@yuwenmemon yuwenmemon requested review from a team as code owners June 22, 2026 17:57
@melvin-bot melvin-bot Bot requested review from brunovjk and trjExpensify June 22, 2026 17:57
@melvin-bot

melvin-bot Bot commented Jun 22, 2026

Copy link
Copy Markdown

@brunovjk 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 request for a team and trjExpensify June 22, 2026 17:57
@yuwenmemon yuwenmemon changed the title Surface RuleBot in the Agent rules section [HOLD AUTH#22411] Surface RuleBot in the Agent rules section Jun 22, 2026
renderTitle={renderTitle}
subtitle={translate('workspace.rules.agentRules.subtitle')}
subtitleMuted
renderSubtitle={renderSubtitle}

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.

❌ CLEAN-REACT-PATTERNS-1 (docs)

This migrates the consumer from the subtitle string prop to the renderSubtitle render-function prop. Render-function props are configuration disguised as flexibility — Section must own the slot and manage the fallback between renderSubtitle() and the default subtitle. The rule calls out renderSubtitle explicitly as a Case 5 anti-pattern, and each new consumer cements the config-heavy API and makes a future compositional refactor harder. New consumers of config-heavy APIs should be flagged at the same severity as the creator.

Prefer composing the subtitle as a child block rather than passing a render function, e.g.:

<Section isCentralPane renderTitle={renderTitle} childrenStyles={[styles.gap3]}>
    <Section.Subtitle>
        <Text style={[styles.textNormal, styles.colorMuted]}>{translate('workspace.rules.agentRules.subtitle')}</Text>
        {!!ruleBotAccountID && (
            <View style={[styles.flexRow, styles.alignItemsCenter, styles.gap2]}>
                <Text style={[styles.textNormal, styles.colorMuted]}>{translate('workspace.rules.agentRules.enforcedBy')}</Text>
                <UserPill accountID={ruleBotAccountID} avatar={ruleBot?.avatar} displayName={ruleBotDisplayName} email={ruleBot?.login} />
            </View>
        )}
    </Section.Subtitle>
    {/* ...rest of section content... */}
</Section>

If Section does not yet expose subtitle composition, advocate for a compositional sub-component instead of adopting the render-function prop.


Reviewed at: 4f4a045 | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

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.

(Yuwen's Agent) Keeping renderSubtitle here for consistency — the sibling IndividualExpenseRulesSection in this same folder uses the identical renderSubtitle={() => (…)} pattern, and Section only exposes subtitle/renderSubtitle (there's no compositional subtitle slot). Adopting a Section.Subtitle API would be a separate Section refactor, out of scope for this PR.

</View>
);

const renderSubtitle = () => (

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.

❌ CLEAN-REACT-PATTERNS-4 (docs)

renderSubtitle is an internal helper that builds a deeply nested JSX tree inline (nested Views, two Text nodes, a conditional {!!ruleBotAccountID && ...} block, and a UserPill), hiding the real render tree from the return statement. Internal functions that return non-trivial nested JSX should be extracted into their own focused component with explicit props.

Extract this into a dedicated component (e.g. AgentRulesSubtitle) that receives ruleBotAccountID, ruleBot, and ruleBotDisplayName (or fetches them itself), and render it directly in the JSX tree:

function AgentRulesSubtitle({ruleBotAccountID, ruleBot, ruleBotDisplayName}: AgentRulesSubtitleProps) {
    const styles = useThemeStyles();
    const {translate} = useLocalize();
    return (
        <View style={[styles.mt2, styles.gap2]}>
            <Text style={[styles.textNormal, styles.colorMuted]}>{translate('workspace.rules.agentRules.subtitle')}</Text>
            {!!ruleBotAccountID && (
                <View style={[styles.flexRow, styles.alignItemsCenter, styles.gap2]}>
                    <Text style={[styles.textNormal, styles.colorMuted]}>{translate('workspace.rules.agentRules.enforcedBy')}</Text>
                    <UserPill accountID={ruleBotAccountID} avatar={ruleBot?.avatar} displayName={ruleBotDisplayName} email={ruleBot?.login} />
                </View>
            )}
        </View>
    );
}

This keeps the section's render tree visible and makes the subtitle independently testable and memoizable by React Compiler.


Reviewed at: 4f4a045 | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

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.

(Yuwen's Agent) Leaving the subtitle inline to match the sibling IndividualExpenseRulesSection, which builds its renderSubtitle the same way. The tree here is small (one conditional row with a UserPill), so a one-off extracted component would diverge from the established pattern in this folder. Happy to revisit if we standardize subtitle extraction across the rules sections.

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

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

Files with missing lines Coverage Δ
src/pages/workspace/rules/AgentRulesSection.tsx 95.34% <100.00%> (+0.75%) ⬆️
... and 12 files with indirect coverage changes

@brunovjk

Copy link
Copy Markdown
Contributor

Reviewing ASAP.

<View style={[styles.mt2, styles.gap2]}>
<Text style={[styles.textNormal, styles.colorMuted]}>{translate('workspace.rules.agentRules.subtitle')}</Text>
{!!ruleBotAccountID && (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.gap2]}>

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.

Instead of gap2, which is 8px, we might want to try gap1.5 to give us 6px? Not sure if that exists, but it might feel a little better.

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.

@shawnborton here it is with 6px - is this moving the needle for ya? Maybe we put it in line with the above description, or at the bottom of the card?

Screenshot 2026-06-22 at 5 58 38 PM

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.

That looks good to me 👍

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.

Okay great!

@yuwenmemon yuwenmemon requested a review from a team as a code owner June 23, 2026 00:59
@brunovjk

brunovjk commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

I noticed two details:

  • After creating the rule, the phrase "Agent rules are enforced by [RuleBot]" takes a little while to appear.
  • When I delete the only existing rule, the phrase "Agent rules ..." remains there.
Screen.Recording.2026-06-23.at.12.15.34.mov

@yuwenmemon is this expected? Thanks.

@yuwenmemon yuwenmemon changed the title [HOLD AUTH#22411] Surface RuleBot in the Agent rules section Surface RuleBot in the Agent rules section Jun 24, 2026
@yuwenmemon

Copy link
Copy Markdown
Contributor Author

@brunovjk yeah, I think both are fine.

@brunovjk

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 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 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 and each prop has a /** comment above it */
    • The file is named correctly
    • 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
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • 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 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 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
94131_android_native.mov
Android: mWeb Chrome
94131_android_web.mov
iOS: HybridApp
94131_ios_native.mov
iOS: mWeb Safari
94131_ios_web.mov
MacOS: Chrome / Safari
94131_web_chrome.mov

@brunovjk brunovjk 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, taking into account the points mentioned here. @yuwenmemon do you think we should update the PR description to take these details into account? Thanks.

I asked to confirm the translation here.

@melvin-bot melvin-bot Bot changed the title Surface RuleBot in the Agent rules section [Payment due @brunovjk] Surface RuleBot in the Agent rules section Jun 25, 2026
@melvin-bot

melvin-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

🎯 @brunovjk, thanks for reviewing and testing this PR! 🎉

A payment issue will be created for your review once this PR is deployed to production.
E/E issue linked to the PR - https://www.github.com/Expensify/Expensify/issues/647929.

If payment is not needed (e.g., regression PR review fix etc), react with 👎 to this comment to prevent the payment issue from being created.

@puneetlath puneetlath merged commit d088a4f into main Jun 25, 2026
40 checks passed
@puneetlath puneetlath deleted the yuwen-647929-rulebot-rules-surface branch June 25, 2026 20:08
@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.

@github-actions

Copy link
Copy Markdown
Contributor

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

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/puneetlath in version: 9.4.20-0 🚀

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

@MelvinBot

Copy link
Copy Markdown
Contributor

📚 Help site review

Yes — a small help site update is warranted. This PR surfaces RuleBot directly in the Agent rules section under Workspace > Rules (the new Agent rules are enforced by [RuleBot] line). The existing Agent Rules articles already document that RuleBot is created automatically and enforces Agent Rules, but they didn't mention that the section now visually surfaces the RuleBot agent.

Draft PR: #94636

I added one sentence to Create-Agent-Rules.md (under What happens after an Agent Rule is created) noting that the Agent rules section displays the Agent rules are enforced by RuleBot line once RuleBot exists, and that it isn't shown before the first Agent Rule. I referenced the exact UI labels from src/languages/en.ts per HELPSITE_NAMING_CONVENTIONS.md, and made no other changes since the rest of the RuleBot behavior is already documented.


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

@mitarachim

Copy link
Copy Markdown

Deploy Blocker #94642 was identified to be related to this PR.

@mitarachim

Copy link
Copy Markdown

Deploy Blocker #94643 was identified to be related to this PR.

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to production by https://github.com/blimpich in version: 9.4.20-1 🚀

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

Bundle Size Analysis (Sentry):

@melvin-bot

melvin-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

🤖 Payment issue created: #94734

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.

7 participants