Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
getAutofixArtifactFromSection,
getOrderedAutofixSections,
getPollInterval,
getSingleRunStop,
hideErroredPrIteration,
isCodeChangesArtifact,
isCodingAgentsArtifact,
Expand Down Expand Up @@ -704,6 +705,45 @@ describe('getOrderedAutofixSections', () => {
);
});

it('keeps why the run stopped on the root cause section', () => {
const sections = getOrderedAutofixSections(
makeSingleRun([
makeBlock({message: {metadata: {step: 'single_run'}}}),
makeBlock({
artifacts: [
{
key: 'stop',
reason: 'stop',
data: {reason: 'R', suggestion: 'N'},
},
],
}),
])
);

expect(getSingleRunStop(sections[0]!)).toEqual({reason: 'R', suggestion: 'N'});
});

it('drops the stop once the run has code changes', () => {
const sections = getOrderedAutofixSections(
makeSingleRun([
makeBlock({message: {metadata: {step: 'single_run'}}}),
makeBlock({
artifacts: [
{
key: 'stop',
reason: 'stop',
data: {reason: 'R', suggestion: 'N'},
},
],
merged_file_patches: [makePatch('org/repo', 'a.py')],
}),
])
);

expect(getSingleRunStop(sections[0]!)).toBeNull();
});

it('has only a root cause section without patches', () => {
const sections = getOrderedAutofixSections(
makeSingleRun([
Expand Down
27 changes: 25 additions & 2 deletions static/app/components/events/autofix/useExplorerAutofix.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,24 @@ export function isRootCauseArtifact(
);
}

export interface SingleRunStop {
reason: string;
suggestion: string;
}

function isSingleRunStopArtifact(value: unknown): value is Artifact<SingleRunStop> {
return (
isArtifact(value) &&
value.key === SINGLE_RUN_STOP_KEY &&
isString(value.data?.reason) &&
isString(value.data?.suggestion)
);
}

export function getSingleRunStop(section: AutofixSection): SingleRunStop | null {
return section.artifacts.findLast(isSingleRunStopArtifact)?.data ?? null;
}

export interface SolutionStep {
description: string;
title: string;
Expand Down Expand Up @@ -474,6 +492,7 @@ function buildSection(
*/
export const SINGLE_RUN_FEATURE_ID = 'autofix_single_run';
const SINGLE_RUN_ROOT_CAUSE_KEY = 'single_run_root_cause';
const SINGLE_RUN_STOP_KEY = 'stop';

export function isSingleRunAutofix(runState: ExplorerAutofixState | null): boolean {
return runState?.feature_id === SINGLE_RUN_FEATURE_ID;
Expand Down Expand Up @@ -503,12 +522,17 @@ function getSingleRunSections(
}
);

const patches = mergeFilePatches(blocks);
const stops = patches.length
? []
: collectArtifacts(blocks).filter(isSingleRunStopArtifact);

const sections: AutofixSection[] = [
{
index: 0,
step: 'root_cause',
blocks,
artifacts: rootCauses,
artifacts: [...rootCauses, ...stops],
status: rootCauses.length
? 'completed'
: runState.status === 'error'
Expand All @@ -519,7 +543,6 @@ function getSingleRunSections(
},
];

const patches = mergeFilePatches(blocks);
if (patches.length) {
sections.push({
index: 0,
Expand Down
22 changes: 22 additions & 0 deletions static/app/components/events/autofix/v3/autofixCards.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,28 @@ describe('ArtifactCard', () => {
expect(screen.getByText('Click button')).toBeInTheDocument();
});

it('shows why a single run stopped instead of the failure text', () => {
const stop = {
key: 'stop',
reason: 'stop',
data: {reason: 'R', suggestion: 'N'},
};

render(
<RootCauseCard
autofix={mockAutofix}
groupId="1"
section={makeSection('root_cause', 'completed', [stop])}
/>
);

expect(screen.getByText('R')).toBeInTheDocument();
expect(screen.getByText('N')).toBeInTheDocument();
expect(
screen.queryByText(/Seer failed to generate a root cause/)
).not.toBeInTheDocument();
});

it('renders card shell when artifact data is null', () => {
const artifact = makeRootCauseArtifact(null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ describe('RootCausePreview', () => {
expect(screen.getByText('Finding the root cause…')).toBeInTheDocument();
});

it('shows why a single run stopped instead of the failure text', () => {
const stop = {
key: 'stop',
reason: 'stop',
data: {reason: 'R', suggestion: 'N'},
};

render(<RootCausePreview section={makeSection('root_cause', [stop])} />);

expect(screen.getByText('R')).toBeInTheDocument();
expect(
screen.queryByText(/Seer failed to generate a root cause/)
).not.toBeInTheDocument();
});

it('handles null data', () => {
const artifact: Artifact<RootCauseArtifact> = {
key: 'root-cause',
Expand Down
4 changes: 4 additions & 0 deletions static/app/components/events/autofix/v3/autofixPreviews.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
import {
collectPatches,
getAutofixArtifactFromSection,
getSingleRunStop,
isCodeChangesArtifact,
isCodingAgentsArtifact,
isPullRequestsArtifact,
Expand All @@ -42,6 +43,7 @@ export function RootCausePreview({section}: ArtifactPreviewProps) {
const sectionArtifact = getAutofixArtifactFromSection(section);
return isRootCauseArtifact(sectionArtifact) ? sectionArtifact : null;
}, [section]);
const stop = getSingleRunStop(section);

return (
<ArtifactCard icon={<IconBug />} title={t('Root Cause')}>
Expand All @@ -52,6 +54,8 @@ export function RootCausePreview({section}: ArtifactPreviewProps) {
</Flex>
) : artifact?.data ? (
<SeerMarkdown raw={artifact.data.one_line_description} />
) : stop ? (
<SeerMarkdown raw={stop.reason} />
) : (
<Text variant="muted">
{t(
Expand Down
13 changes: 13 additions & 0 deletions static/app/components/events/autofix/v3/rootCauseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {Text} from '@sentry/scraps/text';

import {
getAutofixArtifactFromSection,
getSingleRunStop,
isRootCauseArtifact,
isSingleRunAutofix,
type AutofixSection,
Expand Down Expand Up @@ -40,6 +41,15 @@ export function RootCauseCard({autofix, groupId, section}: RootCauseCardProps) {
const sectionArtifact = getAutofixArtifactFromSection(section);
return isRootCauseArtifact(sectionArtifact) ? sectionArtifact : null;
}, [section]);
const stop = getSingleRunStop(section);
const stopDetails = stop ? (
<ArtifactDetails>
<Text bold>{t('Why Seer stopped')}</Text>
<SeerMarkdown raw={stop.reason} />
<Text bold>{t('Suggestion')}</Text>
<SeerMarkdown raw={stop.suggestion} />
</ArtifactDetails>
) : null;

const {copy} = useCopyToClipboard();
const openSingleRunChat = useOpenSingleRunChat();
Expand Down Expand Up @@ -137,7 +147,10 @@ export function RootCauseCard({autofix, groupId, section}: RootCauseCardProps) {
</Flex>
</ArtifactDetails>
)}
{stopDetails}
</Fragment>
) : stopDetails ? (
stopDetails
) : (
<ArtifactDetails>
<Text>
Expand Down
Loading