fix(autofix): Fall back to code mappings when preference has empty repos#113077
fix(autofix): Fall back to code mappings when preference has empty repos#113077
Conversation
read_preference_from_sentry_db now always returns a SeerProjectPreference instead of None, removing the has_configured_options gate that could incorrectly treat mechanically-written default options as "configured". _resolve_project_preference now checks preference.repositories instead of just truthiness — when repos are empty it falls through to the code mapping fallback while preserving the user's existing stopping point and handoff settings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend Test FailuresFailures on
|
| if pref: | ||
| repo_definitions = pref.repositories | ||
| if pref.automation_handoff: | ||
| auto_create_pr = pref.automation_handoff.auto_create_pr |
There was a problem hiding this comment.
This renaming stuff is due to mypy. read_preference_from_sentry_db guarantees SeerProjectPreference but get_project_seer_preferences can return None. I'll just rename the Seer API call result since it'll get removed soon.
| underlying read path (Sentry DB or Seer API).""" | ||
| if features.has("organizations:seer-project-settings-read-from-sentry", organization): | ||
| return bulk_read_preferences_from_sentry_db(organization.id, project_ids) | ||
| return bulk_read_preferences_from_sentry_db(organization.id, project_ids) # type: ignore[return-value] |
There was a problem hiding this comment.
Again mypy. Return type here is dict[int, SeerProjectPreference] so I think it's ok to override mypy
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| for key in SEER_PROJECT_PREFERENCE_OPTION_KEYS | ||
| } | ||
|
|
||
| result: dict[int, SeerProjectPreference | None] = {} | ||
| result: dict[int, SeerProjectPreference] = {} | ||
| for project in projects: | ||
| has_configured_options = any( | ||
| project_options[key][project.id] is not None | ||
| for key in SEER_PROJECT_PREFERENCE_OPTION_KEYS | ||
| ) | ||
| if project.id not in repo_definitions_by_project and not has_configured_options: | ||
| result[project.id] = None | ||
| continue | ||
|
|
||
| def _get_project_option(key: str) -> Any: | ||
| value = project_options[key][project.id] |
There was a problem hiding this comment.
Bug: When the feature flag is on, the fallback to populate repositories from code mappings never runs because the if not existing_pref: check is always false.
Severity: MEDIUM
Suggested Fix
The logic should be updated to check if the repositories key within the existing_pref dictionary is empty, rather than checking the existence of existing_pref itself. This will correctly trigger the fallback to get_autofix_repos_from_project_code_mappings when a project's preferences do not specify any repositories.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: src/sentry/seer/autofix/utils.py#L787-L794
Potential issue: When the `organizations:seer-project-settings-read-from-sentry` feature
flag is enabled, the `bulk_read_preferences_from_sentry_db` function returns a
`SeerProjectPreference` object for every project, which is then converted to a
dictionary. As a result, the `existing_pref` variable in
`configure_seer_for_existing_org` is always a non-empty dictionary. This causes the `if
not existing_pref:` check to always evaluate to false, preventing the intended fallback
logic that populates repositories from code mappings when a project has no repositories
configured in its preferences. Consequently, projects without configured repositories
will incorrectly end up with an empty repository list instead of using the code mapping
data.
Did we get this right? 👍 / 👎 to inform future reviews.
The Sentry DB project preference read helpers had a
has_configured_optionsgate that returnedNonefor projects with no repos and no non-default options. This was problematic because the gate could treat a pref with no repos and explicitly set default options as unconfigured and return None, and_resolve_project_preferencewould then create a new pref using code mapping repos.In this PR we:
has_configured_optionsgate entirely.read_preference_from_sentry_dbandbulk_read_preferences_from_sentry_dbnow always return aSeerProjectPreference(neverNone).if preference.repositoriesin_resolve_project_preferenceinstead ofif preference:. When repos are empty, it falls through to the code mapping fallback while preserving the user's existing stopping point and handoff settings (instead of overwriting them with org defaults).if preference:guards on the Sentry DB read path, since it can no longer returnNone.The night shift cron job is unaffected — it already filters on
pref.repositoriesandpref.autofix_automation_tuning != OFF, so receiving a default preference instead ofNonedoesn't change which projects are selected.