Skip to content

feat: Cross-location finding merge#148

Merged
dcramer merged 5 commits intomainfrom
feat/cross-location-merge
Feb 17, 2026
Merged

feat: Cross-location finding merge#148
dcramer merged 5 commits intomainfrom
feat/cross-location-merge

Conversation

@dcramer
Copy link
Member

@dcramer dcramer commented Feb 17, 2026

Merge findings that describe the same root cause at different code locations
into a single finding with additionalLocations.

When a skill reports the same issue found in multiple places (e.g. the same
anti-pattern repeated across files), Warden now uses Haiku to identify groups
and collapses them into one finding per root cause. This reduces noise in PR
comments and GitHub checks while preserving all location details.

What changes:

  • mergeCrossLocationFindings in src/sdk/extract.ts calls Haiku to group
    related findings, then merges each group into a primary finding with
    additional locations attached
  • The full rendering pipeline (terminal, GitHub checks, PR comments, stale
    detection, dedup) handles the new additionalLocations field
  • Cross-location merge runs once in runSkillTask, not again in the poster
  • Shared findingLine / compareFindingPriority utilities in types/index.ts

Design decisions:

  • mergeGroupLocations returns a shallow copy (no input mutation)
  • Overlapping LLM groups skip already-absorbed findings
  • Additional locations are deduplicated by path:startLine:endLine

@vercel
Copy link

vercel bot commented Feb 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
warden Ready Ready Preview, Comment Feb 17, 2026 8:24pm

Request Review

Copy link
Contributor

@sentry-warden sentry-warden bot left a comment

Choose a reason for hiding this comment

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

🟠 [Q9Q-QGN] onSkillUpdate receives uniqueFindings instead of mergedFindings (src/cli/output/tasks.ts:387) (high confidence)

Line 387 passes uniqueFindings to onSkillUpdate callback while the report uses mergedFindings. This causes the terminal UI (via completedItems in ink-runner.tsx) to display pre-merge finding counts, inconsistent with the actual report findings.

Identified by Warden via notseer

When multiple findings describe the same root cause at different code
locations, use Haiku LLM to identify groups and merge them into a single
finding with additionalLocations. Updates the full rendering pipeline
(terminal, GitHub checks, PR comments, stale detection, dedup) to
handle the new field.

Key design decisions:
- mergeGroupLocations returns a shallow copy (no input mutation)
- Overlapping LLM groups skip already-absorbed findings
- Additional locations are deduplicated by path:startLine:endLine
- Shared findingLine/compareFindingPriority utilities in types/index.ts
- Cross-location merge runs once in runSkillTask, not again in poster

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix three bugs in cross-location finding merge:

1. When overlapping LLM groups share the same winner, the replacement map
   was overwritten, losing locations from prior groups. Now uses the
   existing accumulated replacement as the merge base.

2. Duplicate indices from LLM responses could cause a winner to appear in
   the absorbed/dropped set, silently removing it from output. Now deduplicates
   group indices before processing.

3. onSkillUpdate callback was emitting pre-merge uniqueFindings instead of
   the final mergedFindings, causing inconsistent state for consumers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Seed the dedup set in mergeGroupLocations with the winner's own
primary location so losers sharing that same path:startLine:endLine
don't produce a redundant self-reference in additionalLocations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a finding that won a previous merge group later becomes a loser in
a subsequent group, its accumulated additionalLocations were lost because
only the winner's replacement was substituted. Now substitutes replacements
for all findings in the group before merging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

After substituting replacements into the sorted array for merging,
the loser-tracking loop was adding replacement objects to absorbed/dropped
sets. The final filter checks original references from the findings array,
so originals slipped through, producing duplicates. Now tracks original
finding references for absorption.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dcramer dcramer merged commit 4f908a4 into main Feb 17, 2026
13 checks passed
@dcramer dcramer deleted the feat/cross-location-merge branch February 17, 2026 20:51
dcramer added a commit that referenced this pull request Feb 17, 2026
#153)

Extract duplicated merge-group processing into a single
`applyMergeGroups` function.

Both `consolidateBatchFindings` (dedup.ts) and
`mergeCrossLocationFindings` (extract.ts) contained the same loop for
processing LLM-returned merge groups: deduplicating indices, filtering
absorbed findings, substituting prior replacements, and calling
`mergeGroupLocations`. This extracts that logic into one shared function
in extract.ts.

Also adds a small `locationKey` helper to replace repeated inline string
construction, and removes `pickAndMergeWinner` which was a thin wrapper
around `mergeGroupLocations`.

Net: -21 lines, no behavior change.

Follow-ujp to #148

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

1 participant

Comments