Skip to content

Commit 35eb4af

Browse files
Merge pull request #317 from browserstack/fix/rca-require-explicit-fix-approval
fix(rca): require explicit user approval before applying RCA fix suggestions
2 parents 33ca653 + c785846 commit 35eb4af

4 files changed

Lines changed: 74 additions & 2 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ Similar to the app testing, you can use the following prompts to test your **web
8585
Auto-analyze, diagnose, and even fix broken test scripts right in your IDE or LLM. Instantly fetch logs, identify root causes, and apply context-aware fixes. No more debugging loops.
8686
Below are few example prompts to run/debug/fix your automated tests on BrowserStack's [Test Platform](https://www.browserstack.com/test-platform).
8787

88+
> **Note:** When fetching Root Cause Analysis (RCA) for a test, the server returns the suggested fix as a proposal only. It never applies code changes automatically — your assistant must present the suggestion and wait for your explicit approval before editing any files.
89+
8890
```bash
8991
#Port test suite to BrowserStack
9092
"Setup test suite to run on BrowserStack infra"

src/tools/rca-agent-utils/format-rca.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ export function formatRCAData(rcaData: any): string {
66

77
let output = "## Root Cause Analysis Report\n\n";
88

9+
// Track whether any test case carries a fix suggestion so we can append the
10+
// approval-gate directive only when it is relevant.
11+
let hasFixSuggestion = false;
12+
913
rcaData.testCases.forEach((testCase: any, index: number) => {
1014
// Show test case ID with smaller heading
1115
output += `### Test Case ${index + 1}\n`;
@@ -29,7 +33,8 @@ export function formatRCAData(rcaData: any): string {
2933
}
3034

3135
if (rca.possible_fix) {
32-
output += `**Recommended Fix:**\n${rca.possible_fix}\n\n`;
36+
hasFixSuggestion = true;
37+
output += `**Suggested Fix (proposal only — do not apply without explicit user approval):**\n${rca.possible_fix}\n\n`;
3338
}
3439
} else if (testCase.rcaData?.error) {
3540
output += `**Error:** ${testCase.rcaData.error}\n\n`;
@@ -40,5 +45,12 @@ export function formatRCAData(rcaData: any): string {
4045
output += "---\n\n";
4146
});
4247

48+
if (hasFixSuggestion) {
49+
output +=
50+
"> **Action required:** The fixes above are suggestions only. " +
51+
"Present them to the user and apply code changes ONLY after the user " +
52+
"explicitly approves. Do not modify any files automatically.\n";
53+
}
54+
4355
return output;
4456
}

src/tools/rca-agent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export default function addRCATools(
144144

145145
tools.fetchRCA = server.tool(
146146
"fetchRCA",
147-
"Retrieves AI-RCA (Root Cause Analysis) data for a BrowserStack Automate and App-Automate session and provides insights into test failures.",
147+
"Fetch AI Root Cause Analysis for failed BrowserStack Automate/App-Automate tests. Suggests fixes only; never auto-apply, require explicit user approval.",
148148
FETCH_RCA_PARAMS,
149149
async (args) => {
150150
try {

tests/tools/formatRCAData.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { describe, it, expect } from "vitest";
2+
import { formatRCAData } from "../../src/tools/rca-agent-utils/format-rca";
3+
4+
describe("formatRCAData", () => {
5+
it("returns a no-data message when there are no test cases", () => {
6+
expect(formatRCAData(null)).toBe("No RCA data available.");
7+
expect(formatRCAData({ testCases: [] })).toBe("No RCA data available.");
8+
});
9+
10+
it("labels a suggested fix as a proposal and appends the approval-gate directive", () => {
11+
const output = formatRCAData({
12+
testCases: [
13+
{
14+
id: 101,
15+
state: "failed",
16+
rcaData: {
17+
rcaData: {
18+
root_cause: "Selector changed",
19+
possible_fix: "Update the locator to the new data-testid",
20+
},
21+
},
22+
},
23+
],
24+
});
25+
26+
// The fix is framed as a proposal, not an instruction to apply.
27+
expect(output).toContain("Suggested Fix (proposal only");
28+
expect(output).toContain("do not apply without explicit user approval");
29+
30+
// The approval-gate directive must be present so consuming agents do not
31+
// auto-apply code changes.
32+
expect(output).toContain("Action required");
33+
expect(output).toContain(
34+
"apply code changes ONLY after the user explicitly approves",
35+
);
36+
expect(output).toContain("Do not modify any files automatically");
37+
});
38+
39+
it("omits the approval-gate directive when no fix is suggested", () => {
40+
const output = formatRCAData({
41+
testCases: [
42+
{
43+
id: 102,
44+
state: "failed",
45+
rcaData: {
46+
rcaData: {
47+
root_cause: "Network timeout",
48+
},
49+
},
50+
},
51+
],
52+
});
53+
54+
expect(output).toContain("Network timeout");
55+
expect(output).not.toContain("Action required");
56+
expect(output).not.toContain("Suggested Fix");
57+
});
58+
});

0 commit comments

Comments
 (0)