Skip to content

fix(rca): resolve build ids for TRA and Automate tools - #559

Merged
Dave3130 merged 20 commits into
browserstack:mainfrom
SavioBS629:fix/build-lookup-resolver
Nov 6, 2026
Merged

Dave3130 merged 20 commits into
browserstack:mainfrom
SavioBS629:fix/build-lookup-resolver

Conversation

@SavioBS629

@SavioBS629 SavioBS629 commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Build ids were the most common failure point in the Automate and Test Reporting & Analytics (TRA) tools. Users have a dashboard build name, a build number, a dashboard link or an Automate build id. The tools accepted only the exact build name the SDK sent, and only for the latest run. This PR resolves what the user has into the right id, and lets each tool accept either kind of id.

Behaviour changes

listBuildId / getBuildId

Each lookup is at most one request, with no paging:

  • TRA build id: returned as is.
  • Automate or App Automate build link or id: mapped to its TRA build (see below).
  • Project + build name: the latest run, through /ext/v1/builds/latest. This matches the build name from browserstack.yml. When it misses, the error explains that and asks for the build number or dashboard link, rather than searching.
  • Build number, or a dashboard project link (.../projects/<project>/builds/<name>/<number>, on the TRA or the Automate dashboard): one call to the TRA capability get_build_id_from_build_coordinates, made by the tool itself through the capability registry, so the tool returns the build id directly and the endpoint stays defined only in the capability index. If the capability registry is disabled, the tool returns a clear error.
  • Which build name: without a build number, the name must be the one from browserstack.yml (what /builds/latest matches). With a build number, it must be the name shown on the dashboard, which TRA may shorten. A dashboard link avoids the difference, and the field descriptions and errors say which name is expected.
  • getBuildId: it is no longer limited to the caller's builds. A build-name lookup tries the caller's builds first, then anyone's. The tool description says so.

Automate build ids in TRA tools

  • Mapping: an Automate or App Automate build id maps to its TRA build when it is the latest run of its build name, and the match is confirmed before it is returned.
    • Automate can group several TRA runs of the same name under one build. In that case, the latest run is returned, as on the dashboard.
    • Older runs get an error that points to listBuildId with the build number.
  • Tools that accept Automate ids: fetchBuildInsights (which also returns session_type), listTestIds and fetchSelfHealedSelectors. They map the id when TRA returns 404 for it.
  • listTestIds: status is now optional.

Sessions and logs

  • listSessions: accepts a TRA or Automate build id for either product. For builds whose results were uploaded (e.g. JUnit reports), it explains why there are no sessions.
  • getFailureLogs product check: it checks which product a session ran on.
  • getFailureLogs log types: sessionLogs and appiumLogs are swapped across products, with a note. Other log types that don't exist for that product are reported as unavailable. A different kind of log is never returned.

Errors and retries

  • Product fallback: only a 404 means a build or session belongs to the other product. Other failures (429, 5xx) surface as errors and are never read as an unknown or mismatched id.
  • Not-found detection: uses the HTTP status (HttpError, or axios errors), not the error text.
  • Retries: a dropped connection is retried once, for GET requests only.

Tool descriptions

  • Updated for listBuildId, getBuildId, listSessions, listTestIds, fetchBuildInsights, getFailureLogs and fetchSelfHealedSelectors, all within the description length budget.

Testing

Unit: npm run build passes: lint, format, 142 test files / 2,087 tests, and tsc. New tests cover:

  • link parsing;
  • each lookup path;
  • Automate dashboard project links;
  • build-number lookups through the capability, including a disabled registry;
  • one request per name lookup;
  • 404-only fallback, including outage cases;
  • log-type handling;
  • retries.

Live: run against the live API through a real MCP client. All cases passed: build lookups by every input above, Automate id mapping, insights, sessions, test ids and log-type correction. API behaviours this change relies on, confirmed that way:

  • The build-number capability matches the dashboard name. It is case-insensitive and accepts spaces or +. The build name the SDK sent returns 404.
  • Cross-product session lookups return 404. An App Automate session asked on Automate, and an Automate session asked on App Automate, both return 404, so falling through to the other product only on 404 is safe.
  • The TRA build endpoints return 404 for an Automate build id. The fallback only runs on a 404. It mapped an Automate id end to end in fetchBuildInsights and listTestIds. fetchSelfHealedSelectors uses the same check but was not exercised live.

🤖 Generated with Claude Code

SavioBS629 and others added 3 commits November 6, 2026 14:01
listBuildId / getBuildId
- Find a build by SDK name, dashboard name, build number or dashboard link
  (TRA or Automate), searching the project's builds from the last year.
- Suggest close matches and similar project names instead of a bare 404.
- Fall back to Automate and App Automate builds by name for runs that never
  reported to Test Reporting & Analytics; return the TRA id when one exists.

Automate to TRA mapping
- Map an Automate or App Automate build id to its TRA build, including older
  runs of the same build name, confirmed before it is returned.
- fetchBuildInsights, listTestIds and fetchSelfHealedSelectors accept
  Automate build ids and map them.

Sessions and logs
- listSessions accepts either id kind and either product, and explains
  builds whose results were uploaded and have no sessions.
- getFailureLogs detects the product a session ran on and fetches the
  equivalent log type.
- Retry dropped connections once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the walk over older runs: it costs many requests per lookup, and
clients retry failed lookups. An older run now gets a direct error that
points to listBuildId with the build number.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each build search reads one page (the newest builds), the project lookup
at most 5 pages, and the Automate name search one page per product.
Clients retry failed lookups, so a wrong name now costs a few requests
instead of a deep walk. Errors say what was searched and suggest the
TRA build id for older runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Central YAML (base), Organization UI (inherited), Workspace UI (inherited); Enforced overrides: Organization
  • Review profile: ASSERTIVE
  • Plan: Enterprise
  • Run ID: 8b3753da-9a0b-4652-9a9d-45ecda155844

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

SavioBS629 and others added 5 commits November 6, 2026 15:28
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tatus

- Automate and App Automate dashboard links that name a project are matched
  by build name in that product, not in TRA. Several runs with the same name
  return candidates instead of a guess, since build numbers are not exposed.
- fetchBuildInsights keeps session_type when it maps an Automate build id.
- 404s are detected from the HTTP status (HttpError, axios) rather than the
  error text.
- Shorter listBuildId description; drop date handling the builds API does
  not support.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Automate dashboard serves TRA build pages at
/projects/<project>/builds/<name>/<number>, with TRA's dashboard name and
build number, so these links resolve through the TRA lookup again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Automate builds API returns no creation date, so matches cannot be ordered across products.

@sarve-shreyas sarve-shreyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the full diff against main (merge-base cd4989a6) at aa11473f.

Local checks: npm run build, tsc --noEmit and eslint on the changed files are clean, and all 2088 vitest tests pass (141 files). Prettier flags tests/tools/getFailureLogs.test.ts and tests/tools/list-session-ids.test.ts, but both were already flagged on main.

Findings outside the diff / general:

  • The PR description is empty. For a +2.2k change to tool contracts (all listBuildId/getBuildId params are now optional, getBuildId falls back to other users' builds, getFailureLogs swaps log types, listSessions/listTestIds/fetchBuildInsights/fetchSelfHealedSelectors map ids across products), please add a summary of the behaviour changes and how they were tested against a live account.
  • Questions I couldn't check from the code: (a) does /ext/v1/projects/:id/builds take date_range in epoch ms (${start},${end} uses Date.now())? (b) do the TRA builds/:id, quality-gates/:id, test-runs and self-heal endpoints really return 404 for an Automate hashed id? The hashed→TRA fallback in listTestIds, fetchBuildInsights and fetchSelfHealedSelectors only fires on 404, so a 400/422 there would skip it. The tests mock both of these.

The inline comments are marked blocking or non-blocking.

.join(", ")}.`
: "";
throw new BuildLookupError(
`No TRA project named "${projectName}" found.${hint} Use the project name shown on the dashboard, or pass the TRA build id.`,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: findProject stops after MAX_PROJECT_PAGES = 5 pages of /ext/v1/projects (tra-builds.ts:29), but this message says the project doesn't exist.

Scenario: an account with more projects than 5 pages hold passes a TRA link (.../projects/<p>/builds/<name>/<n>) or a project name plus buildNumber. Those paths skip /builds/latest and go straight to findProject. If the project is past page 5, the user gets No TRA project named "X" found, which is false, and the model is told to use a different name.

Suggestion: if the loop exits because of the page cap (and not because has_next is false), say the search covered only the first N projects and ask for the TRA build id. Better, use a name filter on the projects API if one exists. Please also add a test for the page-cap case.

params: { limit: 1 },
raise_error: false,
});
if (!response.ok) return undefined;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: every non-OK response (401/403/429/5xx) is treated as "this id is not on this product". If both products fail this way, resolveTraBuildIdFromHashed throws TraBuildNotFoundError(..., unknownToAutomate = true).

Scenario: listBuildId gets an Automate build link while api.browserstack.com returns 5xx/429. resolveFromHashed (resolve-build.ts:169) returns { buildId: <hashed id> } as a success with no note, so the model passes an Automate id to listTestIds/fetchRCA as if it were a TRA id. In mapHashedToTra the same case becomes "No TRA build has this id", which is also wrong. A temporary outage looks like a bad id.

Suggestion: move on to the other product only on 404 (as listSessionIds does with UnknownBuildError). For any other status, throw an HttpError and let it surface.

Comment thread src/tools/get-failure-logs.ts Outdated
const EQUIVALENT_LOG_TYPE: Partial<Record<LogType, LogType>> = {
[AutomateLogType.SessionLogs]: AppAutomateLogType.AppiumLogs,
[AutomateLogType.ConsoleLogs]: AppAutomateLogType.DeviceLogs,
[AutomateLogType.NetworkLogs]: AppAutomateLogType.DeviceLogs,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: some of these mappings return logs the caller didn't ask for. networkLogs → deviceLogs and crashLogs → sessionLogs aren't equivalent: a HAR request answered with device logcat, or a crash request answered with Selenium logs, can lead the model to a wrong root cause. The note helps, but it comes after the content. I'd keep sessionLogs ↔ appiumLogs and return an error ("not available for sessions") for the rest.

Comment thread src/tools/rca-agent.ts Outdated
tools.getBuildId = server.tool(
"getBuildId",
"Get the BrowserStack build ID for a given project and build name, scoped to the current user's builds.",
"Like listBuildId, but prefers the caller's own builds. Finds a build id from project + build name, build number or link.",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: this changes getBuildId's behaviour. It used to return only the caller's builds (user_name filter, error otherwise). Now it falls back to anyone's latest run, and with buildNumber/buildUrl it ignores the user entirely (resolveInProject has no user filter). That's probably fine, but the two tools are now nearly the same. Please mention it in the PR description, or consider having getBuildId call listBuildId so the model doesn't have to choose between two near-identical tools.

SavioBS629 and others added 2 commits November 6, 2026 17:04
- When the project list is cut off by the page cap, say only the first 50
  projects were searched instead of reporting the project as missing.
- Only a 404 means a build or session belongs to the other product. Other
  failures (429, 5xx) now surface as errors instead of returning an
  Automate id as if it were a TRA id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… scope

- getFailureLogs swaps only sessionLogs and appiumLogs across products.
  Other log types that do not exist for the session's product are reported
  as unavailable instead of returning a different kind of log. Notes now
  come before the logs.
- getBuildId's description says the caller's builds are tried first only
  for build-name lookups.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@sarve-shreyas sarve-shreyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed aa11473f..f383d32e (aa3f0a0a and f383d32e). tsc --noEmit and eslint on the changed files are clean, and all 2092 vitest tests pass.

Resolved:

  • Project search page cap: findProject now returns truncated, and the error says the search was partial instead of saying the project doesn't exist. There's a test for it.
  • Non-404 handling: readAutomateBuild, the session-detail lookup, resolveBuildIdFromSession, the confirmation step and mapHashedToTra now fall through only on 404. Other statuses surface as HttpError.
  • getFailureLogs now swaps only sessionLogs ↔ appiumLogs, reports other mismatched types as errors, and puts the notes before the logs.
  • getBuildId's description now states its user scope.

Still open:

  • The PR description is still empty (body is empty via the API). The behaviour-change list and the live checks (date_range in ms, 404 for hashed ids on the TRA endpoints) haven't been added yet.
  • PROJECTS_SEARCHED = MAX_PROJECT_PAGES * 10 assumes /ext/v1/projects returns 10 projects per page. Was that page size checked against the live API? If it's different, the "first 50 projects" message is wrong. Counting the rows actually seen would avoid the assumption.

One inline comment below: the name-only Automate fallback still swallows errors.

first.hashedBuildId,
first.sessionType,
config,
).catch((): BuildLookupResult => ({ buildId: first.hashedBuildId }));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking (same issue as the last round, on a path the fix didn't cover): this .catch swallows every error, including the HttpErrors that resolveFromHashed now throws on 5xx/429.

Scenario: listBuildId({ browserStackBuildName: "nightly" }) with no project falls through to searchAutomateBuilds. If Automate returns 503 during the mapping, this returns the hashed Automate id as a success, noted as "Found automate build ... by name". The model then passes it to listTestIds/fetchRCA as a TRA id.

Suggestion: drop the catch so HttpError propagates (resolveFromHashed already turns TraBuildNotFoundError into a result). Or catch only TraBuildNotFoundError. Separately and non-blocking: findAutomateBuildsByName (.catch(() => undefined) / !response?.ok → break) turns an outage into "None of the latest Automate builds is named X", the same kind of misleading not-found message.

SavioBS629 and others added 7 commits November 6, 2026 17:14
…s seen

- The name-only Automate fallback no longer turns a failed TRA mapping or
  builds-list error into a success. Products the account cannot access
  (401/403/404) are skipped; other failures surface.
- The partial project search message reports how many projects were
  actually checked instead of assuming 10 per page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
listBuildId and getBuildId now make at most one lookup request:
- A TRA id is returned as is; an Automate build id is mapped as before.
- Project + build name returns the latest run via /builds/latest. A miss
  explains that the name must be the one from browserstack.yml and asks
  for the build number or dashboard link.
- A build number, or a TRA / Automate dashboard project link, returns a
  ready invokeCapability call for get_build_id_from_build_coordinates, so
  that endpoint is defined only in the TRA capability index.

Removes the project search, the project build listing, close-match lists
and the Automate builds name search.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A 429 or 5xx while trying the id as a TRA build is now returned as an
error instead of "no build has this id".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The TRA-to-Automate step now reads only the first page of a build's test
runs. If that page has no session but more pages exist, it says so and
asks for the Automate build link instead of paging on. A build with no
sessions at all is still reported as uploaded results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
listBuildId and getBuildId call get_build_id_from_build_coordinates
themselves, through the capability registry's invoke path, and return the
build id in one tool call. The endpoint stays defined only in the TRA
capability index. When the registry is disabled or its index is missing,
the tools return a clear error instead of pointing at a tool the client
may not have.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The helper now reads only the index of the product it calls (TRA, about
1.2 MB) instead of every product index, cached per product.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the first page of a build's test runs has no session but more pages
exist, one call to the TRA capability get_build_summary_stats reads the
build's session count. Zero means uploaded results; otherwise, or if the
count cannot be read, the tools ask for the Automate build link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sarve-shreyas
sarve-shreyas previously approved these changes Nov 6, 2026
@SavioBS629 SavioBS629 changed the title Fix/build lookup resolver fix(rca): resolve build ids for TRA and Automate tools Nov 6, 2026
@Dave3130
Dave3130 merged commit 6b9be4c into browserstack:main Nov 6, 2026
2 checks passed
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.

3 participants