Skip to content

ref(seer): Type 10 issue/event/agent/PR seer RPC responses#117876

Open
azulus wants to merge 1 commit into
masterfrom
jeremy/seer-rpc-type-issue-event-details
Open

ref(seer): Type 10 issue/event/agent/PR seer RPC responses#117876
azulus wants to merge 1 commit into
masterfrom
jeremy/seer-rpc-type-issue-event-details

Conversation

@azulus

@azulus azulus commented Jun 16, 2026

Copy link
Copy Markdown
Member

Replaces the dict[str, Any] return annotations on the following seer RPC methods with explicit Pydantic models so the seer-side SDK consumer sees declared field shapes:

  • get_issue_detailsIssueDetailsResponse | None
  • get_event_detailsEventDetailsResponse | None
  • get_issue_and_event_details_v2IssueAndEventDetailsResponse | None — single model whose issue-side fields use exclude_unset so they're absent from the wire when include_issue=False or the group lookup failed (matches the pre-typed conditional spread)
  • get_transactions_for_projectTransactionsForProjectResponse
  • get_trace_for_transactionTraceData | EmptyResponse
  • get_profiles_for_traceTraceProfiles | EmptyResponse
  • get_issues_for_transactionTransactionIssues | EmptyResponse — the four project-scoped RPC wrappers above already built the response by calling .dict() on existing Pydantic models, so they just return the model directly now and use EmptyResponse for the {} not-found case
  • bulk_get_project_preferencesBulkProjectPreferencesResponse — bare {project_id_str: pref_dict} map via __root__ passthrough
  • record_pr_attributionPrAttributionResponse
  • update_pr_metricsUpdatePrMetricsSuccessResponse | UpdatePrMetricsErrorResponse discriminated by success: Literal[True|False]

Wire-identical across all paths. The response models that need to be read like dicts by seer or existing test sites carry a small _DictProxyMixin (__getitem__/__contains__/.get) so the typed return doesn't force a rewrite of every consumer in the same change.

Replaces the `dict[str, Any]` return annotations on the following seer RPC
methods with explicit Pydantic models so the seer-side SDK consumer sees
declared field shapes:

- `get_issue_details` → `IssueDetailsResponse | None`
- `get_event_details` → `EventDetailsResponse | None`
- `get_issue_and_event_details_v2` → `IssueAndEventDetailsResponse | None`
  (single model whose issue-side fields use `exclude_unset` so they're
  absent from the wire when `include_issue=False` or the group lookup
  failed — matches the pre-typed conditional spread)
- `get_transactions_for_project` → `TransactionsForProjectResponse`
- `get_trace_for_transaction` → `TraceData | EmptyResponse`
- `get_profiles_for_trace` → `TraceProfiles | EmptyResponse`
- `get_issues_for_transaction` → `TransactionIssues | EmptyResponse`
  (the four project-scoped RPC wrappers above already built the response
  by calling `.dict()` on existing Pydantic models — just return them
  directly and use `EmptyResponse` for the `{}` not-found case)
- `bulk_get_project_preferences` → `BulkProjectPreferencesResponse`
  (bare `{project_id_str: pref_dict}` map via `__root__` passthrough)
- `record_pr_attribution` → `PrAttributionResponse`
- `update_pr_metrics` → `UpdatePrMetricsSuccessResponse | UpdatePrMetricsErrorResponse`
  (discriminated by `success: Literal[True|False]`)

Wire-identical across all paths. The response models that need to be
read like dicts by seer or existing test sites carry a small `_DictProxyMixin`
(`__getitem__`/`__contains__`/`.get`) so the typed return doesn't force
a rewrite of every consumer in the same change.
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Jun 16, 2026
@azulus azulus marked this pull request as ready for review June 16, 2026 23:57
@azulus azulus requested a review from a team as a code owner June 16, 2026 23:57
Comment on lines +516 to +517
def dict(self, **kwargs: Any) -> Any:
return dict(self.__root__)

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.

Bug: The dict() method on BulkProjectPreferencesResponse ignores all keyword arguments, which is inconsistent with other Pydantic models in the codebase and violates the expected API contract.
Severity: LOW

Suggested Fix

Modify the dict method in BulkProjectPreferencesResponse to forward keyword arguments to the parent class's method. Change return dict(self.__root__) to return super().dict(**kwargs) to ensure consistent behavior with other Pydantic models.

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/sentry_data_models.py#L516-L517

Potential issue: The `dict()` method override for the `BulkProjectPreferencesResponse`
Pydantic model does not pass through any keyword arguments (`**kwargs`) to the
underlying implementation. Instead, it returns `dict(self.__root__)`, discarding
arguments like `exclude_unset`. This is inconsistent with other response models in the
same file that correctly forward these arguments to `super().dict(**kwargs)`. While
current usage doesn't pass any arguments, this creates a maintenance risk. Future
refactoring or Pydantic version upgrades could introduce calls that rely on these
arguments, leading to silent failures and unexpected serialization behavior.

Did we get this right? 👍 / 👎 to inform future reviews.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants