fix(accessibility): match the dashboard's issue count and keep the report link intact by Aaryan430 · Pull Request #500 · browserstack/mcp-server · GitHub
Skip to content

fix(accessibility): match the dashboard's issue count and keep the report link intact - #500

Merged
gaurav-singh-9227 merged 13 commits into
mainfrom
fix/a11y-scan-exclude-duplicates
Oct 22, 2026
Merged

gaurav-singh-9227 merged 13 commits into
mainfrom
fix/a11y-scan-exclude-duplicates

Conversation

@Aaryan430

@Aaryan430 Aaryan430 commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Replaces #494, which was opened from a fork. Same three commits, now on a branch in this repo so the follow-up PRs can stack on it and show only their own changes.

Three fixes to what startAccessibilityScan and fetchAccessibilityIssues tell the agent.

1. The count matches the dashboard: no duplicates

Both tools counted every row of the issues export. In a grouped report each repeated occurrence is its own row with a "Duplicate Issue of" link to its main issue, and the dashboard leaves those out of its count. So a scan the dashboard shows as 79 issues ("Excluded 43 duplicated issues") came back from the tool as "We found 122 issues".

The parser now returns main issues only and folds each duplicate into the issue its link points at (duplicate_count on that issue). A duplicate whose link matches no main issue, or more than one, is never attributed to a specific issue. Reports without the "Duplicate Issue of" column keep every row.

2. The count matches the dashboard: no hidden issues

Every export also lists issues hidden in the dashboard ("Issue status" = hidden), which the dashboard leaves out of its count. A Workflow Analyzer report the dashboard shows as 771 issues exports 1,231 rows, 123 of them hidden. A hidden issue is now left out with every occurrence of it, including duplicates.

The answer states what was left out. The duplicates note says "folded … (see duplicate_count)" only for duplicates actually matched to an issue (this addresses the CodeRabbit comment on the earlier wording):

This report groups repeated occurrences: 337 duplicate occurrences are folded into their main issue (see duplicate_count) and are not included in the total.
122 issues hidden in the dashboard are not included, as the dashboard leaves them out of its count too.

3. The report link no longer breaks

The tools return one text block per message, and a client that joins blocks with no separator (Claude Code does) ran the CSV link into the next sentence: …&Key-Pair-Id=KWDR32L2KWU1BWe found 122 issues. The key pair id is opaque, so an agent copying the link takes the W along and the download fails with 403 InvalidKey; the same link without it downloads fine. Each block now ends with a newline.

Verification

Input Result
Real scan export through this branch's build Total 79, 43 duplicates folded, the dashboard's count; no hidden note (none hidden)
A fresh scan through startAccessibilityScan 81 issues + 43 duplicates, matching that run's export
The dashboard's export of a 1,231-row Workflow Analyzer report Total 771, 337 duplicates folded, 122 hidden left out, exactly the dashboard's 771 / 122

New tests cover grouped, link-less and ungrouped reports, hidden main issues with their duplicates, hidden rows in an ungrouped report, the note's wording for matched / unmatched duplicates, and the report link surviving a no-separator join. npm run build (lint, format, 1310 tests, tsc) passes.

The public API's Workflow Analyzer export does not carry "Duplicate Issue of" today (the dashboard's export does), so for those reports only hidden issues are left out until the API adds the column. That is being fixed in the accessibility repo.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Accessibility scan results now distinguish primary issues from duplicates, unlinked duplicates, and hidden issues.
    • Reports explain which repeated or hidden issues are excluded from dashboard totals.
    • Exclusion details appear in both paginated issue results and completed-scan responses.
    • Accessibility report parsing now supports grouped CSV reports and more accurately links duplicate issues.
  • Bug Fixes

    • Improved formatting consistency by separating text blocks with newlines in successful responses.
  • Tests

    • Added coverage for grouped reports, hidden issues, duplicate handling, and scan-result messaging.

Aaryan430 and others added 5 commits October 19, 2026 15:00
The issues export has a row for every occurrence. In a grouped report each
repeated occurrence carries a "Duplicate Issue of" link to its main issue, and
the dashboard leaves those rows out of its issue count. startAccessibilityScan
and fetchAccessibilityIssues counted every row, so a scan the dashboard shows
as 79 issues was reported as "We found 122 issues".

The parser now returns main issues only, folds each duplicate into the issue
its link points at (duplicate_count), and returns how many duplicates it left
out; both tools state that number next to the total. A duplicate whose main
issue cannot be identified is counted only there. Reports without the
"Duplicate Issue of" column are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The scan and issue tools return one text block per message. A client that
joins the blocks with no separator (Claude Code does) runs the report link
into the next block's first word: "...&Key-Pair-Id=KWDR32L2KWU1BWe found 122
issues". The key pair id is opaque, so an agent copying the link takes the
"W" with it and the download fails with 403 InvalidKey. Each block now ends
with a newline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t was left out

The dashboard counts neither duplicate occurrences nor issues hidden in it,
but the export lists both, and every export carries an "Issue status"
column. Hidden issues were counted: a Workflow Analyzer report the
dashboard shows as 771 issues exports 1,231 rows, 123 of them hidden.

A hidden issue is now left out with every occurrence of it, and the total
is the dashboard's: on the dashboard's export of that report, 771 issues,
337 duplicate occurrences folded and 122 hidden issues left out. The
answer says how many hidden issues it left out.

The duplicates note no longer says every duplicate was folded: duplicates
that could not be matched to a main issue are named as such, and
duplicate_count is pointed at only when some were matched.

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

fetchAccessibilityIssues read only Website Scanner runs, so an agent that ran
an SDK test with accessibility on, or was handed a Workflow Analyzer report,
had no way to read its issues. The API already exports both the same way as a
scan run: start a CSV export, poll the same route with the task id, download
the link. Only the route and its parameter names differ.

The tool now takes exactly one source: scanId with scanRunId, buildId (the
Accessibility build id, thBuildId in the report link), or workflowReportId.
The fetcher builds each source's export URLs; the parser, duplicate folding
and paging are unchanged. A build the API does not find (the Automate build
id is one) gets a message naming the id to pass instead, and the next-page
hint repeats the source's own arguments.

Rows now carry affected_page, since builds and Workflow Analyzer reports span
several pages, and source_test when the export has a "Source test" column
(Automated Tests builds).

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

An agent handed a dashboard report link had to find the ids itself, and
fetchAccessibilityIssues returned parsed issues but not the CSV. Both
now go through the tool.

reportUrl takes a Website Scanner or Automated Tests report link. An
Automated Tests link carries its build id. A Website Scanner link carries
one run's thBuildId, which only the scan list can map to ids: each scan
there carries its latest run's link, so the newest scans are walked
(15 pages) for a match. A link to an older run is reported as such, with
the scan's id, rather than guessed at. The list is walked at its default
page size: at limit=50 or 100 its cursor skips scans.

Every answer now includes the CSV's download link, as startAccessibilityScan
already does. When a link was resolved the answer says to what, and the
next-page hint uses the ids, so later pages skip the lookup.

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

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

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: 1069dc40-d584-41e0-b9e2-c581d5160288

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Central YAML (base), Organization UI (inherited), Workspace UI (inherited)
  • Review profile: ASSERTIVE
  • Plan: Enterprise
  • Run ID: e76241da-1da5-4532-9811-a4c97108753f
📥 Commits

Reviewing files that changed from the base of the PR and between eade3c0 and 06ed055.

📒 Files selected for processing: 4
  • src/tools/accessibility.ts
  • src/tools/accessiblity-utils/report-parser.ts
  • tests/tools/accessibilityReport.test.ts
  • tests/tools/accessibilityScanOutput.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 8 remain after this review.

📜 Recent review details
🔇 Additional comments: 4
src/tools/accessiblity-utils/report-parser.ts: 1

12-13: LGTM!

Also applies to: 27-52, 64-70, 82-144, 153-153, 162-162, 179-183

tests/tools/accessibilityReport.test.ts: 1

1-231: LGTM!

src/tools/accessibility.ts: 1

71-79: LGTM!

Also applies to: 172-201, 211-219, 230-230, 411-418, 460-468, 479-479

tests/tools/accessibilityScanOutput.test.ts: 1

1-183: LGTM!

📝 Walkthrough

Accessibility CSV parsing now separates visible main issues from duplicate and hidden rows, and reports the applicable counts. Paginated issue responses and completed-scan responses include notes about excluded issues.

Changes: Accessibility report exclusions

Layer / File(s) Summary
Grouped report parsing
src/tools/accessiblity-utils/report-parser.ts, tests/tools/accessibilityReport.test.ts
The parser detects grouped reports, excludes hidden rows, and matches duplicate rows to visible main issues by exact issue-link equality. It returns visible issue records and applicable duplicate and hidden-issue counts. Tests cover grouped and ungrouped reports, including missing or ambiguous links.
Exclusion notes in accessibility responses
src/tools/accessibility.ts, tests/tools/accessibilityScanOutput.test.ts
Paginated issue and completed-scan responses include available exclusion notes. Success text blocks end with newlines. Tests check count messages and signed report-link preservation.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant AccessibilityTool
  participant parseAccessibilityReportFromCSV
  participant excludedIssuesNote
  participant createSuccessResponse
  AccessibilityTool->>parseAccessibilityReportFromCSV: request issue records and exclusion counts
  parseAccessibilityReportFromCSV-->>AccessibilityTool: return records and counts
  AccessibilityTool->>excludedIssuesNote: format available exclusion details
  excludedIssuesNote-->>AccessibilityTool: return notes
  AccessibilityTool->>createSuccessResponse: provide scan result and notes
  createSuccessResponse-->>AccessibilityTool: return newline-separated text blocks
Loading

Suggested reviewers: saviobs629

Merge Risk: ⚪ Minimal · up to 06ed0

No actionable issue is established; the change is ready for normal merge checks.

Security architecture risk: ⚪ Minimal · up to 06ed0

The changes affect which accessibility issues are displayed and how exclusions are explained. The inspected changes introduce no new access privileges, network destinations, or shared persistent state, and no material security concern was identified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed exposure is confined to issue selection, attribution, counts, and response formatting for the requested report. The inspected comparison adds no tenant selector, credential authority, or externally registered tool.

Trust Boundaries and Controls

  • observed — CSV-derived record JSON continues to pass through wrapUntrusted at both response paths. New exclusion prose interpolates numeric counters rather than raw CSV text. This preserves the existing response-boundary handling without establishing that it prevents every possible instruction-injection attack.

Resilience and Maintainability Implications

  • inferred — The new maps and counters are allocated per invocation and returned only after aggregation. Download or parsing failure does not partially publish those counters, and concurrent calls do not share the new aggregation state. No new persistent transition or recovery protocol is introduced.
Pre-merge checks: Passed 4
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the two primary changes: aligning accessibility issue counts with the dashboard and preserving report links.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

A rabbit checks the rows at dawn,
And counts the hidden, duplicates gone.
Main issues hop into the light,
Notes join the scan results just right.
Newlines guide each block along.

Comment @coderabbitai help to get the list of available commands.

Aaryan430 and others added 6 commits October 22, 2026 11:08
… budget

Every client loads tool descriptions at connect time, so the prompt is back under 200
characters including the handoff sentence, and each argument's description under 120:
what each id is lives in its own describe(), and where ids come from in the answers
and errors. buildId is a regex (40 lowercase letters and digits) rather than prose. A
test now holds every accessibility tool to the budget.

Also: a dashboard link whose scan has no completed run is refused, instead of asking
the API for scan_run_id=undefined.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ading its issues

An agent that fetched an SDK build's issues right after the test run got 14
issues, called final ("All issues retrieved"); the build completed minutes
later with 27. After the tests end a build stays "finalizing" (advanced
issue processing, for an advanced scan) and the export serves whatever
exists so far.

fetchAccessibilityIssues now reads the report's status first: a scan run's
status endpoint, a Workflow Analyzer report's summary, and for a build its
project's build list, since the build overview carries no status. While it
is queued, running, processing or finalizing, a first read waits, polling
every 10 s for up to 5 min with progress notifications, then reads the
issues and says it waited. If processing outlasts the wait, the answer
says the issues are only those found so far and to fetch again, instead of
"All issues retrieved". A later page does not wait again, and a status
that cannot be read is not waited on.

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

A build whose suite is still running can take as long as the suite; blocking the first
read for five minutes and then returning partial results anyway serves nobody. The wait
now covers only the post-run advanced-issue processing ("finalizing"), which ends
within minutes. A run in progress is read as it is, with the note that the issues are
those found so far.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…build-and-workflow-issues

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1y-wait-for-processing

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SavioBS629
SavioBS629 previously approved these changes Oct 22, 2026
feat(accessibility): wait for a report to finish processing before reading its issues
…orkflow-issues

feat(accessibility): fetch issues of builds, Workflow Analyzer reports and dashboard links, with the CSV link
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