Skip to content

[pull] master from getsentry:master#1843

Merged
pull[bot] merged 57 commits into
KingDEV95:masterfrom
getsentry:master
Apr 1, 2026
Merged

[pull] master from getsentry:master#1843
pull[bot] merged 57 commits into
KingDEV95:masterfrom
getsentry:master

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Apr 1, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

jan-auer and others added 13 commits April 1, 2026 13:31
)

Propagates attachment `retention_days` from the ingest consumer to all
places where attachments are written to objectstore. If Relay does not
provide retention days yet, it defaults to the global retention setting
or 30 days if unset, which matches the current behavior.

It is expected that Relay populates the retention setting. In order to
reduce load on the ingest consumer, we're not reading event retention
for every message when constructing `CachedAttachment`, and instead fall
back to the global default.

---------

Co-authored-by: Claude <noreply@anthropic.com>
…access (#109781)

Allow projects to see console-restricted symbol sources in Built-in
Repositories when the organization has console platform access. This
lets e.g. a Unity project add the Nintendo symbol source if the org has
nintendo-switch access.

When console access is revoked, a Celery task removes the corresponding
symbol sources from all projects in the organization.

---

Also updates `BuiltinSymbolSourcesEndpoint` to no longer be accessible
as an endpoint without having Organization auth by changing the class it
inherits from to `OrganizationEndpoint`.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Empty file patches are generated to overwrite previous file patches.
These are rendered as empty changes. We only want to preserve the last
file patch for a file and we need to ensure it is a non empty file
patch.
SSIA

Current impl does `sync_to_async` of `async_to_sync` when ASGI is
enabled. This fixes that.
…es (#111978)

Display the triggered condition details on the issue detail page for
`preprod_size_analysis` issues. New self-gating
`SizeAnalysisTriggeredSection` component renders an `InterimSection`
with a `KeyValueList` showing:

- **Threshold Type** — absolute size, absolute diff, or relative diff
- **Measurement** — platform-aware label derived from
`head.artifact_type` event tag (e.g., "Install Size" for Apple,
"Uncompressed Size" for Android)
- **Query** — shown when a filter query is configured
- **Condition** — human-readable threshold description (e.g., "Above 1
MB")
- **Evaluated Value** — formatted with 2 decimal places and appropriate
units

Action buttons:
- **Open Build** — always shown, links to the head build detail page
- **Open Comparison** — shown for `absolute_diff` / `relative_diff`
threshold types when a base artifact exists

Also adds `getMetricLabelForArtifactType` to the preprod types utils,
exports `formatComparisonValue` and `getConditionDescription` from
mobileBuild/detect.tsx, and adds a space between values and units in
condition descriptions.

Diff Example
<img width="2754" height="488" alt="CleanShot 2026-04-01 at 09 33 35@2x"
src="https://github.com/user-attachments/assets/6502cbe9-a84d-466e-86e2-d157403759f7"
/>

absolute example
<img width="2730" height="490" alt="CleanShot 2026-04-01 at 09 34 23@2x"
src="https://github.com/user-attachments/assets/59a79c73-47d2-46ca-9832-400e36b89fbb"
/>


Refs EME-981

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
#111994)

Adds app name, platform, and bundle ID as a prefix to the evidence
display text in size analysis Slack/Jira notifications. This gives
recipients immediate context about which app triggered the alert without
clicking through.

**Before:** `Install Size, Absolute Diff > 1.0 MB (+1.0 MB)`
**After:** `MyApp android (com.example.app) — Install Size, Absolute
Diff > 1.0 MB (+1.0 MB)`

When metadata is unavailable (e.g. no artifact info), the output is
unchanged.

Builds on #111660.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Allow the use of numbers in the group by (ie. numbers) so we're now
returning the actual events in the groupby instead
- This adds an -if combinator to all the metric functions so that we can
construct equations out of them in the new ui
- Going to port this to the other datasets so we can do more interesting
functions in the long term
- The way this is parsed you can't do a query within a query (see the
last test that checks a 400) which is intentional to keep this
functionality simple
Add API pipeline steps for GitLab integration installation:
InstallationConfigApiStep collects instance URL, group path, OAuth
credentials, and SSL preferences. The OAuth step is late-bound via
OAuth2ApiStep using config from the previous step's state.

build_integration now reads token data from either the legacy
state["identity"]["data"] path or the new state["oauth_data"] path
so both flows work during migration.

Refs VDY-39
@pull pull Bot locked and limited conversation to collaborators Apr 1, 2026
@pull pull Bot added the ⤵️ pull label Apr 1, 2026
@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 1, 2026
kcons and others added 13 commits April 1, 2026 16:01
)

We want to clean this up by date, and we need this index to do it
efficiently.
…962) (#111981)

## What

Filter snapshot-only artifacts out of the size analysis status check so
they no longer show as permanently "processing."

## Why

When a commit comparison has both a size analysis artifact and a
snapshot artifact, the size status check counts the snapshot artifact as
"1 component processing" — even though snapshots never go through the
size analysis pipeline and stay in `UPLOADED` state forever. This makes
the GitHub check look stuck.

Fixes EME-962.

## How

Added a filter in the size status check task (after building
`size_metrics_map`, before the existing SKIPPED filter) that keeps only
artifacts with `artifact_type` set or with size metrics present.
Snapshot artifacts have neither — they have no `artifact_type` and no
`PreprodArtifactSizeMetrics` rows.

This mirrors the pattern already used by the snapshot status check task
(`snapshots/tasks.py:138`), which filters to only artifacts with
`PreprodSnapshotMetrics`.

Existing tests were updated to create `PreprodArtifactSizeMetrics` for
UPLOADING/UPLOADED/FAILED artifacts, matching the production flow where
`create_preprod_artifact` always creates size metrics at artifact
creation time.
Audit pages for layout use so that menus, headers and page contents are
aligned horizontally with each other. Since many layouts use bespoke
styling, this is only the first pass of pages that are easily visible by
going through the list of some top level routes

<img width="854" height="211" alt="CleanShot 2026-03-30 at 13 45 27"
src="https://github.com/user-attachments/assets/b548dd7f-1910-4873-b979-b13796a51ffc"
/>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Priscila Oliveira <priscila.oliveira@sentry.io>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Jonas <JonasBa@users.noreply.github.com>
Users are sometimes confused which Seer feature is which. This makes it
hard to look up the feature in the docs / get the correct support etc.
This changes the sidebar to label the section with 'Seer Autofix' to
make it clearer which feature this is.

Before:
<img width="2884" height="2016" alt="CleanShot 2026-04-01 at 10 20
54@2x"
src="https://github.com/user-attachments/assets/f3831eb7-f2cc-4920-9a4d-600d2a2b5d67"
/>

After:
<img width="2884" height="2016" alt="CleanShot 2026-04-01 at 10 21
16@2x"
src="https://github.com/user-attachments/assets/8f6555c7-6898-41a3-aaae-839e1bc20dba"
/>
Removes border radius from page frame and aligns border

<img width="2392" height="272" alt="CleanShot 2026-04-01 at 09 30 24@2x"
src="https://github.com/user-attachments/assets/9a3fd3d5-a268-491e-b8f7-c51242250fa0"
/>
<img width="1618" height="252" alt="CleanShot 2026-04-01 at 09 30 15@2x"
src="https://github.com/user-attachments/assets/f19d0f20-643b-4921-a00f-cbdf7456462b"
/>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Jonas <JonasBa@users.noreply.github.com>
#111691)

When a coding agent integration (Cursor, Claude Code) is deleted or
marked PENDING_DELETION, Seer's stored automation_handoff preference
still references the old integration_id. On every subsequent automated
autofix run, Seer calls Sentry's trigger_coding_agent_launch RPC with
the stale ID. Sentry validates the integration, finds it gone, and
raises NotFound.

There are two paths that affect this, one is through the seer side root
cause step and the other is after root cause completed first.

To fix the first, I pulled out the NotFound error when returning to Seer
and used an error code to identify it. When this is caught we clear the
handoff preferences. For the second, there has been a matching change
for the calling path in a separate [Seer
PR](getsentry/seer#5504).

Tests were added and I ran it locally to make sure it works.
Adds a new column `date_expires` to event attachments that allows us to
clean them up depending on organization-specific retention settings.

Existing rows default to a sentinel value that will allow us to
backfill. New rows are set to 30 days from now. In a follow-up, we will
fill this with the retention value passed from Relay.

Note: An index on this new column is added as a dedicated post-deploy
migration, since this can take a long time.
…11995)

If root cause ever fail to produce an artifact, there's no reason to
keep the conversation for a re-run. So remove the run id to start a
fresh run.
…onvert_to_async_slack_response (#111930)

Follow up to #111858, now
workers are fully updated it is now safe to update callers to pass the
new parameter
Bump max-old-space-size from 4096 to 8192 in frontend CI workflows to
give the TypeScript checker more headroom.
)

The `TypeError: 'NoneType' object is not a mapping` occurred in the
`OrganizationAutofixAutomationSettingsEndpoint.post` method when
attempting to update autofix automation settings.

The root cause was that `bulk_get_project_preferences()` could return
`None` for projects that did not have existing preferences in the Seer
API. When `existing_preferences.get(project_id_str, {})` was called for
such a project, it would correctly retrieve the `None` value (as the key
existed, but its value was `None`), rather than the default `{}`.
Subsequently, attempting to unpack this `None` value using the `**`
operator (`**existing_pref`) resulted in the `TypeError`.

This fix changes the problematic line from `existing_pref =
existing_preferences.get(project_id_str, {})` to `existing_pref =
existing_preferences.get(project_id_str) or {}`. This ensures that if
`existing_preferences.get(project_id_str)` returns `None`,
`existing_pref` will be assigned an empty dictionary `{}`, allowing the
dictionary unpacking to proceed safely without error. This aligns with
the defensive pattern already used elsewhere in the codebase for similar
scenarios.

<!--

  Sentry employees and contractors can delete or ignore the following.

-->

### Legal Boilerplate

Look, I get it. The entity doing business as "Sentry" was incorporated
in the State of Delaware in 2015 as Functional Software, Inc. and is
gonna need some rights from me in order to utilize my contributions in
this here PR. So here's the deal: I retain all rights, title and
interest in and to my contributions, and by keeping this boilerplate
intact I confirm that Sentry can use, modify, copy, and redistribute my
contributions, under Sentry's choice of terms.

Fixes SENTRY-5FNP

---------

Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
Co-authored-by: srest2021 <sofia.rest@sentry.io>
…mit (#111889)

Add a modal in the `/_admin/` customer details page that allows staff to
change the `dashboardsAsyncQueueParallelLimit` org option, which
controls
how many dashboard widget queries can run in parallel per org.

This option was previously only settable via the API directly
(`PUT /api/0/organizations/{org}/`). The new action appears in the admin
customer details actions dropdown alongside existing options like
"Toggle Console Platforms" and "Update Retentions".
<img width="363" height="585" alt="image"
src="https://github.com/user-attachments/assets/fea7a42d-17d8-416e-bf96-48bf9f420525"
/>

<img width="854" height="607" alt="image"
src="https://github.com/user-attachments/assets/3ce6e3b8-838d-4994-9a56-033350158218"
/>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
dashed and others added 29 commits April 1, 2026 13:33
…1352)

This adds the ability to specify a replacement callback when defining a regex for the parameterizer. For example, a regex can now be defined like this:


    ParameterizationRegex(
        name="dog",
        raw_pattern=r"some pattern",
        replacement_callback=lambda orig_value: "<dog>" if some_condition else orig_value,
    )

When the parameterizer finds a matching value, instead of just reflexively replacing it with the regex's name, it'll pass the original value to the callback, and let it decide what the replacement value will be. (This is going to be necessary for us to fix our IPv6 parameterization.)
)

Replace GroupList in SupergroupDetailDrawer with a custom paginated list
that shows already-loaded groups from GroupStore immediately while
fetching remaining groups from the API. Matched groups (from the current
search) are sorted to the top and highlighted with an accent border.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Upgrade eslint-plugin-boundaries from 5.3.1 to 6.0.2 to resolve a
security vulnerability in the transitive handlebars dependency (4.7.8 →
4.7.9).

Migrate config to v6 conventions:
- Rename boundaries/element-types rule to boundaries/dependencies
- Update message templates from ${...} to {{...}} Handlebars syntax
- Update all eslint-disable-next-line comments to reference new rule
name

This should clear up all the `handlebars` dependabot alerts. Although
the vulnerability is critical, this is in non-production code, so
_probably_ less urgent. Still would be good to clean up dependabot
alerts though.

Co-authored-by: Claude <noreply@anthropic.com>
Unused, no use expected, safe to remove.
Add a DELETE method to the `OrganizationPreprodSnapshotEndpoint` so
snapshot artifacts can be deleted via the API.

The endpoint validates that the artifact exists, belongs to the
organization, and is actually a snapshot (has `PreprodSnapshotMetrics`).
It then uses the existing `delete_artifacts_and_eap_data` helper to
clean up the artifact, associated files, size metrics, and EAP data in a
single call. Analytics are recorded and structured logging captures the
deletion details.

Feature-gated behind `organizations:preprod-snapshots`.

---------

Co-authored-by: Claude Opus 4.6 <noreply@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…recurring basis (#111958)

This adds in a framework that allows us to set up a beat task that
schedules a task for all rows in a given queryset. It stripes the task
over the schedule period to keep load evened out.

The initial usecase for this is to schedule a daily repo sync for all
active integrations.

<!-- Describe your PR here. -->
…112018)

adds `sentry deletions list` and `sentry deletions run` commands so you
can manage and execute scheduled deletions synchronously in local dev
instead of waiting for the task to run.

includes tests for both subcommands covering listing, filtering, and
running deletions by id/model/all.

wanted this for uninstalling integrations


<img width="758" height="167" alt="image"
src="https://github.com/user-attachments/assets/90e325b1-639f-407c-806b-caf52cbeb809"
/>


<img width="496" height="198" alt="image"
src="https://github.com/user-attachments/assets/7db99d8e-6b7d-4f02-be1d-9a8a3bedec55"
/>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This cleans up and adds some test cases to our email and URL parameterization tests.

- Clarify case names.

- Move broken case to known issues test.

- Stop using `email.com` for URL examples, especially the ones involving the `@` sign, because it's unnecessarily confusing.

- Add tests for different email address and URL formats.
Set `date_expires` explicitly when creating `EventAttachment` records
during event ingestion, using `retention_days` from the
`CachedAttachment`. This ensures each new attachment row carries an
accurate expiry derived from the project's configured retention rather
than relying on the sentinel value added in #111881.
…111948)

In #111352, we added the ability for a `ParameterizationRegex` to use a callback for its replacement value, rather than just always replacing the original value with `<regex type>`. One thing this will let us do is make the replacement conditional, by having the callback return the original value if it decides the replacement shouldn't be made. (This is how our improved IPv6 parameterization is going to work, so that we can let Python's built-in `ipaddress` functions have the final word on whether or not an ip-like string is a valid IPv6 address.)

That's all very well and good in cases where the callback agrees that the original value should be replaced. When it decides _not_ to replace the value, though, we've created a problem for ourselves. Continuing with the IP example, say we encounter a string like `11:21:99`, which looks vaguely IPv6-ish, but isn't in fact a valid IP.

Before the aforementioned PR, when we were strictly using a `named_pattern_1 | named_pattern_2 | named_pattern_3`-type regex for replacement, parameterization looked like this: 
  - The regex engine tests the string against the `ip` pattern, sees that it doesn't actually match, and keeps trying alternatives. 
  - The regex engine tests the string against the `int` pattern, finds three matches, and makes the replacements.
  - Final result: `<int>:<int>:<int>` (Yay, the right answer!)

With that change in place, though, once the `ip` pattern uses regex to find  IP-like strings and then confirms the match using a callback, parameterization will look like this:
  - The regex engine tests the string against the `ip-like` pattern, finds a match, and passes it to the callback.
  - The callback tests the string, finds it's not actually a valid IPv6 address, and returns the original string as the "replacement" value.
  - As far as the regex engine is concerned, a match has been found, so no other patterns are tried.
  - Final result: `11:21:99` (Boo, the wrong answer.)

To be clear, even with that change in place, we're not actually running into this problem in prod (yet), because the IP regex hasn't yet had the callback added to it. But we will unless we fix the problem, which is what this PR does. In cases where detect such a false positive, we'll now fall back to checking each pattern individually. Essentially, we're just taking control of whether or not to continue checking patterns away from the regex engine, and always forcing every pattern to be checked. While this double-parameterization does take more time, a) we expect this to be a fairly uncommon edge case, b) we recently saved a bunch of time by caching parameterization results, so we have a little wiggle room, and c) we're talking an extra half-millisecond on average, so it'll still be quite fast.

Note: There's not yet a test for this behavior, because testing it requires having something to test. Rather than more or less recreating everything the upcoming IP change will include, I decided to just hold off adding a test until that PR (which is now up at #111979). For now, since there are no live callbacks, all we really need to know is that this change doesn't crash the normal running of the parameterizer, which is amply demonstrated by the fact that every other parameterization test still works.
…to original field (#111934)

Context in linear ticket:
[DAIN-1417](https://linear.app/getsentry/issue/DAIN-1417/visualize-drag-and-drop-shows-wrong-cursor-and-ghost-position)

the drag and drop ghost field was always shifted a lot further to the
right than the original field. This happened because the widget builder
slideout has transitions applied to it already which then applies to all
nested components. This means that the drag and drop context was
applying the transformation calculations on top of the exisiting x/y
values but we need it to apply to when x/y=0. I've added in a modifier
function to adjust the x and y coordinates of the drag overlay so that
the drag button aligns with the cursor.

Here's working proof:


https://github.com/user-attachments/assets/b02d887c-cb0c-4ab5-a047-0aa4b32344e4
#112035)

For logs/discover/issues, `enableAiSearch` is = this flag being on. The
combobox components are never shown unless enableAiSearch (condition
right above usePollingEndpoint), so the !usePollingEndpoint is a dead
branch. In general this FF is a killswitch for the whole ai search
feature, not a polling variant. The polling toggle only works for spans,
the only dataset that has a sync implementation
With getsentry/sentry-options-automator#7061
we're starting to roll the Ask Seer feature out to EA for
logs/issues/discover, and it's now considered beta
Follow-up to #111881. Backfills all existing rows with that sentinel to
`date_added + 30 days`, aligning them with the default attachment
retention period. New rows will be written with a date_expires.

---------

Co-authored-by: Claude <noreply@anthropic.com>
…111972)

Adds objectstore cleanup to the artifact deletion path in
`delete_artifacts_and_eap_data`.

Previously, only DB records and EAP trace data were cleaned up when
deleting preprod artifacts. Snapshot images, manifests, comparison
manifests, and diff masks stored in objectstore were left to expire via
30-day TTL — meaning deleted snapshot data remained accessible for up to
a month.

Now, before the DB cascade runs, we read each snapshot's manifest to
discover all associated objectstore keys (individual images by content
hash, the manifest itself, comparison manifests, and diff mask PNGs),
deduplicate them, and delete them in parallel using
`ContextPropagatingThreadPoolExecutor(max_workers=8)`. Individual key
deletion failures are logged but non-blocking since TTL expiration
serves as the fallback.

The implementation is split into three module-level functions:
- `_collect_snapshot_objectstore_keys` — queries snapshot metrics and
comparisons, reads manifests to enumerate all keys
- `_delete_objectstore_key` — thread worker that deletes a single key
- `_delete_snapshot_objectstore_data` — orchestrator that deduplicates
keys and dispatches parallel deletes

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@example.com>
Currently GitHub Copilot coding agent handoff is a permission set at the
user-level as users must choose to connect their github account.
However, after some discussion we think copilot integration should have
to be allowed at the organization admin in line with how cursor and
claude operate. Since copilot does not need an api key or any
credentials, this PR creates a DirectEnableIntegration which skips the
pop up stage and enables the integration. Only if this is enabled are
users within the org provided access to "Setup/Send to GitHub Copilot"
option for the handoff dropdown.

This is an intermediate fix for now. There are several changes planned
for coding integration settings that would likely make this unnecessary.
Additionally, we only launched EA of copilot in the last couple of
weeks, this should not be merged or put out until we decide how we would
like to inform our current users that this will break their setup
(minimally).

This backend PR will be followed by a frontend one. 


https://github.com/user-attachments/assets/24f3c665-0ae8-4a4b-8347-5c92752f3d56

---------

Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
…prompts (#111957)

Extends the `/dashboard/generate` endpoint to accept a current dashboard
parameter as json. When a dashboard is provided, the seer run is
prompted to edit the existing dashboard.
Adds a fallback function to fill in missing attributes from generated
dashboards from seer. Currently applies a default layout, limit, and
minH if missing. These attributes are marked as required by the artifact
schema, but Seer does not always create them
Improve the loading state by using loading text instead of the ghost to
make it more obvious we're still in a loading state.

# Screenshots

## Drawer

| Root Cause | Plan | Code Changes |
| ----------- | ----- | -------------- |
| <img width="1130" height="590" alt="image"
src="https://github.com/user-attachments/assets/aecf3536-4a0b-4c31-9cb1-c79ea78124e9"
/> | <img width="1130" height="402" alt="image"
src="https://github.com/user-attachments/assets/4e462a27-ebf2-47e7-85b9-c40c5735cbff"
/> | <img width="1130" height="402" alt="image"
src="https://github.com/user-attachments/assets/e5d177d9-0ff5-43ae-bf56-99bf2937601f"
/> |

## Sidebar

| Root Cause | Plan | Code Changes |
| ----------- | ----- | -------------- |
| <img width="554" height="132" alt="image"
src="https://github.com/user-attachments/assets/82d074d7-763d-44ea-be8f-310cc4f2ef78"
/> | <img width="554" height="130" alt="image"
src="https://github.com/user-attachments/assets/7a8eed65-f9f8-4ae2-bb9a-1f32f0461055"
/> | <img width="554" height="130" alt="image"
src="https://github.com/user-attachments/assets/f5c92318-7c45-49a7-9cd6-8b21d7ee587e"
/> |
…111925)

Follow up to #111760 to create
and update `DetectorWorkflow`s in the `BaseDetectorTypeValidator` rather
than in a separate `BulkDetectorWorkflowsValidator` mainly for the
purpose of having correct API docs (the `workflow_ids` param is not
listed in the detector POST and PUT docs) but this also makes the code a
bit simpler.
…111975)

Create `NEEDS_APPROVAL` records in the snapshot status check task when
visual changes are detected, so artifacts requiring review are tracked
before a user explicitly acts. Clean up these records when approvals
arrive via the GitHub check run webhook.

ALSO: Reorders the task so approval/change-detection logic runs
**before** the repository/client lookup — NEEDS_APPROVAL records are now
persisted even when the VCS integration lookup fails.

Also removes NEEDS_APPROVAL creation from the size status check task —
approvals only apply to snapshots.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Closes EME-991

## Summary
- Pass the `display` query parameter to the builds API from the Mobile
Builds settings page
- The Size Analysis section sends `display=size` and the Build
Distribution section sends `display=distribution`
- This filters out snapshot-only builds from both lists, matching the
filtering already used on the explore/releases page

Previously both sections fetched all builds without any display
filtering, so snapshot builds would appear in the size and distribution
lists.
Turn the React Aria missing textValue warning into a hard Jest failure
and add the text values exercised by the affected UI tests

---------

Co-authored-by: Codex <codex@openai.com>
@pull pull Bot merged commit 3cae93f into KingDEV95:master Apr 1, 2026
1 of 4 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

⤵️ pull 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.