Skip to content

feat(preprod): Add Size Analysis detector#108208

Merged
chromy merged 1 commit intomasterfrom
chromy/2026-03-12-add-grouptype
Feb 20, 2026
Merged

feat(preprod): Add Size Analysis detector#108208
chromy merged 1 commit intomasterfrom
chromy/2026-03-12-add-grouptype

Conversation

@chromy
Copy link
Contributor

@chromy chromy commented Feb 13, 2026

Add PreprodSizeAnalysisGroupType (type_id=11003) with detector handler
and validators that integrate with the workflow engine to emit issues
when build size thresholds are exceeded.

  • PreprodSizeAnalysisDetectorHandler: evaluates DataPackets from size
    comparisons and produces IssueOccurrences
  • PreprodSizeAnalysisDetectorValidato validate detector creation via the API
  • Register the GroupType import in preprod/grouptype.py

PRs:

Design doc

This stack of PRs is missing a handful of important features:

  • Filters
  • Detailed data on the occurrence
  • Some UI polish

but it works end to end.

@chromy chromy requested review from a team as code owners February 13, 2026 11:32
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Feb 13, 2026
@github-actions
Copy link
Contributor

This PR has a migration; here is the generated SQL for src/sentry/preprod/migrations/0027_size_analysis_subscription.py

for 0027_size_analysis_subscription in preprod

--
-- Create model SizeAnalysisSubscription
--
CREATE TABLE "sentry_sizeanalysissubscription" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "date_updated" timestamp with time zone NOT NULL, "date_added" timestamp with time zone NOT NULL, "project_id" bigint NOT NULL);
ALTER TABLE "sentry_sizeanalysissubscription" ADD CONSTRAINT "sentry_sizeanalysiss_project_id_41e3355e_fk_sentry_pr" FOREIGN KEY ("project_id") REFERENCES "sentry_project" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_sizeanalysissubscription" VALIDATE CONSTRAINT "sentry_sizeanalysiss_project_id_41e3355e_fk_sentry_pr";
CREATE INDEX CONCURRENTLY "sentry_sizeanalysissubscription_project_id_41e3355e" ON "sentry_sizeanalysissubscription" ("project_id");

@scttcper scttcper requested a review from a team February 17, 2026 21:32
Copy link
Contributor

@saponifi3d saponifi3d left a comment

Choose a reason for hiding this comment

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

the workflow engine code lgtm -- added a few notes for myself on abstractions that should probably live on the base class.

class PreprodSizeAnalysisDetectorHandler(
BaseDetectorHandler[SizeAnalysisValue, SizeAnalysisEvaluation]
):
def evaluate_impl(self, data_packet: SizeAnalysisDataPacket) -> GroupedDetectorEvaluationResult:
Copy link
Contributor

Choose a reason for hiding this comment

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

🙏 -- this is more or less what the eventual base abstraction will look like too. i'll update this once we start working on the non-Stateful abstraction.

Comment on lines +74 to +93
def _evaluate_conditions(
self, value: SizeAnalysisEvaluation
) -> tuple[ProcessedDataConditionGroup | None, DetectorPriorityLevel | None]:
if not self.condition_group:
metrics.incr("workflow_engine.detector.skipping_invalid_condition_group")
return None, None

condition_evaluation, _ = process_data_condition_group(self.condition_group, value)
if not condition_evaluation.logic_result.triggered:
return None, None

priorities = [
condition_result.result
for condition_result in condition_evaluation.condition_results
if isinstance(condition_result.result, DetectorPriorityLevel)
]
if not priorities:
return None, None

return condition_evaluation, max(priorities)
Copy link
Contributor

Choose a reason for hiding this comment

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

note for myself -- this feels like another top level abstraction we should pull out as part of the ABC

SizeAnalysisEvaluation: TypeAlias = int | float


class PreprodSizeAnalysisDetectorHandler(
Copy link
Contributor

Choose a reason for hiding this comment

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

outside of evaluate_impl and _evaluate_conditions -- was there anything else you felt like should live in the base class? i can take a look at updating everything there.

event_data = {
"event_id": uuid4().hex,
"project_id": self.detector.project_id,
"platform": "android",
Copy link
Contributor

Choose a reason for hiding this comment

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

Bug: The PreprodSizeAnalysisDetectorHandler hardcodes the platform as "android", which will cause incorrect platform attribution for issues generated from iOS/Apple builds.
Severity: MEDIUM

Suggested Fix

Modify the data pipeline to include platform information in the DataPacket[SizeAnalysisValue] sent to the detector. This could involve adding a platform field to the SizeAnalysisValue TypedDict or looking up the artifact type from an identifier within the packet. The handler should then use this dynamic platform value instead of the hardcoded "android" string.

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/preprod/size_analysis/grouptype.py#L158

Potential issue: The `create_occurrence` method in the new
`PreprodSizeAnalysisDetectorHandler` hardcodes the `platform` to "android". This is
incorrect because the platform should be determined dynamically based on the artifact
type, as is done in the existing `diff_to_occurrence` function. The data packet
(`SizeAnalysisValue`) passed to the handler does not currently contain the necessary
artifact type or platform information. If this detector is activated for iOS builds,
which use the `XCARCHIVE` artifact type, any generated issues will be incorrectly
attributed to the Android platform, impacting platform-specific filtering and metrics.

Copy link
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.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

return self._extract_head(data_packet) - self._extract_base(data_packet)
case "relative_diff":
base = self._extract_base(data_packet)
return (self._extract_head(data_packet) - base) / base
Copy link
Contributor

Choose a reason for hiding this comment

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

Division by zero when base size is zero

Medium Severity

In extract_value, the relative_diff case computes (head - base) / base. If base is 0 (e.g., a new measurement category that previously had no size), this raises a ZeroDivisionError. The _extract_base method only validates that the value is not None, so a zero value passes validation and reaches the division.

Fix in Cursor Fix in Web

@chromy chromy merged commit 303786a into master Feb 20, 2026
78 checks passed
@chromy chromy deleted the chromy/2026-03-12-add-grouptype branch February 20, 2026 14:48
@github-actions github-actions bot locked and limited conversation to collaborators Mar 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

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