Skip to content

feat(night-shift): Trigger autofix for fixable candidates and add dry run mode#113056

Merged
trevor-e merged 8 commits intomasterfrom
feat/night-shift-autofix-trigger
Apr 15, 2026
Merged

feat(night-shift): Trigger autofix for fixable candidates and add dry run mode#113056
trevor-e merged 8 commits intomasterfrom
feat/night-shift-autofix-trigger

Conversation

@trevor-e
Copy link
Copy Markdown
Member

@trevor-e trevor-e commented Apr 15, 2026

Night shift triage now triggers autofix automation for candidates identified as fixable by the agentic triage strategy. Each autofix run carries a dedicated NIGHT_SHIFT referrer (AutofixReferrer.NIGHT_SHIFT + auto_run_source="night_shift") so this cohort can be tracked and evaluated separately from the regular post-process/alert automation flow.

Per candidate, we check for an existing autofix run and resolve the user's configured stopping point before dispatching _trigger_autofix_task. Unlike the regular automation flow, we skip the fixability-score-based stopping point since night shift already performed its own agentic assessment — only the user's project preference is honored as an upper bound. Quota and feature flag checks are handled downstream by trigger_autofix/trigger_autofix_explorer.

Also adds a dry run toggle to the Seer admin page (/_admin/seer/). When enabled, night shift runs triage and logs candidates as usual but skips autofix triggering — useful for evaluating triage quality without side effects like autofix run timestamps that prevent re-runs.

Changes

  • issue_summary.py: Wire NIGHT_SHIFT into auto_run_source_map and referrer_map. Extract _get_user_stopping_point_preference helper and add get_user_stopping_point for callers that need just the user preference without fixability scoring.
  • cron.py: Add _trigger_autofix_for_candidate() helper, loop in run_night_shift_for_org, accept dry_run kwarg, use get_user_stopping_point for stopping point.
  • admin_night_shift_trigger.py: Pass dry_run flag through to the task.
  • seerAdminPage.tsx: Add dry run checkbox to the night shift trigger form.

… run mode

Night shift triage now triggers autofix automation for candidates
identified as fixable. Each autofix run uses a dedicated NIGHT_SHIFT
referrer so this cohort can be tracked separately from the regular
automation flow.

Also adds a dry run toggle to the Seer admin page so staff can run
triage without triggering actual autofixes, useful for evaluating
triage output without side effects like autofix run timestamps.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions bot added Scope: Frontend Automatically applied to PRs that change frontend components Scope: Backend Automatically applied to PRs that change backend components labels Apr 15, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🚨 Warning: This pull request contains Frontend and Backend changes!

It's discouraged to make changes to Sentry's Frontend and Backend in a single pull request. The Frontend and Backend are not atomically deployed. If the changes are interdependent of each other, they must be separated into two pull requests and be made forward or backwards compatible, such that the Backend or Frontend can be safely deployed independently.

Have questions? Please ask in the #discuss-dev-infra channel.

@sentry
Copy link
Copy Markdown
Contributor

sentry bot commented Apr 15, 2026

Sentry Snapshot Testing

Name Added Removed Modified Renamed Unchanged Status
sentry-frontend
sentry-frontend
0 0 0 0 204 ✅ Unchanged

⚙️ sentry-frontend Snapshot Settings

Comment thread src/sentry/tasks/seer/night_shift/cron.py Outdated
@github-actions
Copy link
Copy Markdown
Contributor

Backend Test Failures

Failures on 6a9d2cb in this run:

tests/sentry/seer/endpoints/test_admin_night_shift_trigger.py::SeerAdminNightShiftTriggerTest::test_trigger_night_shiftlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/seer/endpoints/test_admin_night_shift_trigger.py:31: in test_trigger_night_shift
    mock_task.apply_async.assert_called_once_with(args=[self.organization.id])
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/unittest/mock.py:989: in assert_called_once_with
    return self.assert_called_with(*args, **kwargs)
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/unittest/mock.py:977: in assert_called_with
    raise AssertionError(_error_message()) from cause
E   AssertionError: expected call not found.
E   Expected: apply_async(args=[4557972797915168])
E     Actual: apply_async(args=[4557972797915168], kwargs={'dry_run': False})

trevor-e and others added 2 commits April 15, 2026 12:04
…lity

Night shift already performs its own agentic assessment of fixability,
so the stopping point should honor the user's configured preference
without also applying the fixability score as a lower bound.

Extract _get_user_stopping_point_preference helper and add
get_user_stopping_point for callers that need just the preference.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Comment thread src/sentry/seer/autofix/issue_summary.py Outdated
Thread the preferences dict already loaded by _get_eligible_projects
through to the autofix trigger loop instead of re-fetching per
candidate. Also move autofix triggering after the candidates_selected
log statement.

Co-Authored-By: Claude <noreply@anthropic.com>
trevor-e and others added 2 commits April 15, 2026 12:16
This was an HTTP call to Seer per candidate. The downstream autofix
trigger handles duplicate runs, so the pre-flight check is unnecessary
overhead for the small candidate counts night shift produces.

Co-Authored-By: Claude <noreply@anthropic.com>
Use auto_run_source_map and referrer_map instead of magic strings
and direct enum references, consistent with how run_automation does it.

Co-Authored-By: Claude <noreply@anthropic.com>
- test_triggers_autofix_for_fixable_candidates: verifies autofix task
  is dispatched with correct referrer for AUTOFIX candidates
- test_dry_run_skips_autofix: verifies dry run saves candidates to DB
  but does not dispatch autofix
- test_skips_autofix_for_non_autofix_candidates: verifies root_cause_only
  candidates do not trigger autofix
- Fix _get_eligible_projects test to unpack the new tuple return

Co-Authored-By: Claude <noreply@anthropic.com>
…_point

Inline the preference-reading logic back into get_automation_stopping_point
to keep the diff minimal. Night shift reads the stopping point from the
already bulk-loaded preferences dict so this helper is not needed.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@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.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1b5add6. Configure here.

"night_shift.autofix_trigger_failed",
extra={"group_id": group.id, "organization_id": organization.id},
)
return False
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing existing autofix run check before triggering

Medium Severity

_trigger_autofix_for_candidate dispatches _trigger_autofix_task without first checking whether an autofix run already exists for the group. The regular automation flow in run_automation calls get_autofix_state(group_id=..., organization_id=...) and returns early if a run exists. The PR description states "Per candidate, we check for an existing autofix run" but this guard is absent from the implementation. This can cause duplicate autofix runs for the same group, wasting resources and potentially creating conflicting state.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1b5add6. Configure here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

There's slight potential for a race condition but not a big deal right now. Our issues query checks that the field is null.

Copy link
Copy Markdown
Contributor

@chromy chromy left a comment

Choose a reason for hiding this comment

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

lgtm

autofix_triggered = 0
if not dry_run:
for c in candidates:
if c.action == TriageAction.AUTOFIX:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Did we want to handle ROOT_CAUSE_ONLY or leave it out for now?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yea spoke offline and going to ignore for now.

@trevor-e trevor-e marked this pull request as ready for review April 15, 2026 18:56
@trevor-e trevor-e requested a review from a team as a code owner April 15, 2026 18:56
@trevor-e trevor-e merged commit 5aa127c into master Apr 15, 2026
61 checks passed
@trevor-e trevor-e deleted the feat/night-shift-autofix-trigger branch April 15, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants