Summary
Automatic scan-history matching can drop earlier occurrences when the same stable finding ID appears in more than one previous scan.
Root cause
matchCompletedScan() materializes eligible historical findings in a map keyed only by findingId:
const historical = new Map<string, { scanId: string; finding: Finding }>();
...
historical.set(findingId, { scanId, finding });
When the same finding is present in several earlier scans, each later set() replaces the previous occurrence. This happens before the stable-identity fast path and before semantic comparison.
The later fast path therefore has at most one prior occurrence available:
const previous = historical.get(finding["findingId"] as string);
...
beforeOccurrenceIds: [previous.finding.occurrenceId],
That contradicts the matcher prompt's existing requirement to include every earlier occurrence when several historical scans contain the same issue.
Expected behavior
Keep every eligible { scanId, finding } for a stable finding ID. When the current scan has the same stable identity, save one confirmed match containing all earlier occurrence IDs, then project that match into each relevant before-scan comparison.
Unmatched historical findings should likewise all remain available to semantic comparison.
Impact
Repeated findings can remain unmatched in older scan pairs even though a later scan contains the exact same stable findingId. This makes history less complete and can affect downstream fixed/rediscovered status derived from saved comparisons.
Suggested fix
Store an array of historical occurrences per findingId, flatten it only where the semantic matcher needs a list, and add a regression with one stable finding observed in two earlier scans and the current scan.
Summary
Automatic scan-history matching can drop earlier occurrences when the same stable finding ID appears in more than one previous scan.
Root cause
matchCompletedScan()materializes eligible historical findings in a map keyed only byfindingId:When the same finding is present in several earlier scans, each later
set()replaces the previous occurrence. This happens before the stable-identity fast path and before semantic comparison.The later fast path therefore has at most one prior occurrence available:
That contradicts the matcher prompt's existing requirement to include every earlier occurrence when several historical scans contain the same issue.
Expected behavior
Keep every eligible
{ scanId, finding }for a stable finding ID. When the current scan has the same stable identity, save one confirmed match containing all earlier occurrence IDs, then project that match into each relevant before-scan comparison.Unmatched historical findings should likewise all remain available to semantic comparison.
Impact
Repeated findings can remain unmatched in older scan pairs even though a later scan contains the exact same stable
findingId. This makes history less complete and can affect downstream fixed/rediscovered status derived from saved comparisons.Suggested fix
Store an array of historical occurrences per
findingId, flatten it only where the semantic matcher needs a list, and add a regression with one stable finding observed in two earlier scans and the current scan.