Repository navigation
feat(events)!: Convert event automation identifiers to filters - #2442
sentry-junior[bot] wants to merge 8 commits into
Conversation
Each plugin can now turn its saved identifiers into the filters that select the same events (`identifierMatch` in plugin-api). Core uses it to save new and edited event automation triggers with no identifier, and the heartbeat converts saved rows one at a time through the locked, versioned save. A trigger converts only when every selected event gets the same filters, the filters agree with saved filters, and the result passes the catalog check. Otherwise the row keeps its identifier and keeps running, so no trigger gets broader. Slack channel automations now save a `channelId` filter for their destination channel. Sentry project identifiers do not convert for metric alert events, because those events can leave out `projects`. An omitted `match` on update now keeps the saved filters. Watches keep exact identifiers. The identifier column stays for slice D. Refs #2362 Co-Authored-By: David Cramer <david@sentry.io>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Sentry Evalsjunior-behavioral
Base commit junior-guardian
Base commit junior-integration
Base commit junior-router
Base commit |
A trigger that cannot convert to filters now saves the reason in
`identifierReason` through the same locked, versioned save. The heartbeat
checks at most 50 rows per tick that have an identifier and no saved
reason, so it checks each row once. It skips rows whose identifier column
and saved trigger disagree, because a save would make them broad. Edits
that change the trigger set the reason again.
The trigger description shows the reason as a note, not a problem, in the
dashboard details, Slack details, and listEventAutomations. Rows that keep
their identifier stay active.
The update tool description now says plainly that leaving out match keeps
the saved filters, and only `{}` removes them.
Refs #2362
Co-Authored-By: David Cramer <david@sentry.io>
This comment has been minimized.
This comment has been minimized.
Updates now change match filters key by key. A left-out filter keeps its saved value and null removes it, so an update cannot drop the scope that a conversion moved into match. A write whose saved filter never matches its identifier is rejected instead of saved as a trigger that never runs. Move the heartbeat backfill of saved rows to a follow-up, because no release can read rows with no identifier yet. Drop the Sentry converter, because the plugin has no saved install org to check identifiers against. Pass the one pull request to the lazy GitHub gate, mark identifierMatch as temporary, and test identifiers that do not rebuild and events that need different filters. Refs #2362 Co-Authored-By: David Cramer <david@sentry.io>
The version schema accepts editedBy "junior" and the dashboard shows Junior as the editor. Nothing writes it yet. The reader ships first, so the follow-up that converts saved triggers can roll back to this release and keep version history readable. Refs #2362 Co-Authored-By: David Cramer <david@sentry.io>
|
4 screenshot changes — 4 changed · 0 added · 0 removed Review screenshots in Frameshift
|
A repository identifier and a repo filter now save the same trigger with no identifier, so the eval checks the saved trigger. Refs #2362
|
the pr description is far too technical and it doesnt explain to me what we're actually doing, what the actual final interface/configurations look like, and what might break |
|
is there value in supporting the identifier the way we are? like since its just duplicating matches and it'd be legacy? rying to understand the API interface. maybe we tihnk the simplicity is required to prevent agent errors or something? what about idempotency keys and deduplication how will that function? |
Since #2440 (`15ee5c130`), an automation run no longer writes its saved visibility to the Destination row. Only a live Slack signal does. A run into a channel with no row stores `unknown`, and readers treat it as private. In production, the Slack thread where a person created the Automation records the channel. The eval fixture inserted Automations without that thread, so their channels stayed `unknown`. The fixture reads results as `WEB_VIEWER_EMAIL`, who is not a participant. So `readConversationAccessFromSql` returned `canViewPrivateContent: false`, and the reporting API hid tool payloads for every scheduled and event automation run. Tool calls came back with no input and no output (`result null [4B]` on every tool). `finishAutomationRun` results and tool arguments were empty. This broke these cases on unrelated branches (#2435, #2442, fix/flaky-behavioral-evals, chore/remove-slash-command): - Integration: `Event automation delivery` (no-match silence ×2, blocked automation) and `Scheduled Delivery` (no message outcome) - Behavioral: `Scheduled Delivery` (post in this channel, provider that Junior does not have) and `Sentry Skill Workflows` (creator-bound scheduled Sentry work) There is no product change. Fail-closed `unknown` is intended (#2440). Automations are created from a live Slack turn in their channel, so production channels have a known visibility. ## Fix `packages/junior-evals/src/fixture/insert.ts`: `insertScheduledAutomation` and `insertEventAutomation` now store the creation thread through the Conversation store with `visibility: "public"`, as the live Slack event would. No assertions, cases, or timeouts change. ## Checks - `pnpm lint`, `pnpm typecheck`, `pnpm --filter @sentry/junior-evals test` pass. - A throwaway harness check (not committed) used the real insert functions. A dispatch-shaped write into a bare `slackChannel()` was redacted (`unknown`). Channels from either insert function were readable (`public`). - The 7 affected eval cases did not run locally: the sandbox has no `cloudflared` for eval egress. CI must confirm them. <!-- junior-request-attribution:start --> via **David Cramer**. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3A5d3914babce549420a1ad7b950c41799 --> -- [View Session](https://junior-prod.sentry.dev/conversations/agent%3A5d3914babce549420a1ad7b950c41799) [[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A5d3914babce549420a1ad7b950c41799/?project=4510944073809921) <!-- junior-session-footer:end --> --------- Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
…-filter-conversion
…-filter-conversion # Conflicts: # packages/junior-dashboard/e2e/automation-editor.spec.ts # packages/junior-dashboard/src/client/pages/automations/AutomationDetails.tsx # packages/junior-dashboard/src/client/pages/automations/AutomationVersionsPage.tsx
|
the pr description here needs to be simplified. its somewhat easy to understand but its an essay |
What this does
Today an event automation can point at one thing in two ways:
getsentry/junior#7, orrepo: getsentry/junior, pullRequest: 7.#2407 added filters. This PR starts to move everyone to filters, so later we can delete identifiers (#2362).
When someone creates or edits an event automation and gives an identifier, Junior now saves filters that match exactly the same events. The automation runs exactly as before. It does not start to run for more things.
This PR does not change automations that are already saved. They keep running as they are. A separate draft PR, #2447, converts them later.
Refs #2362
What it looks like
Someone asks: "tell me when a review is posted on #7".
The agent still sends this to
createEventAutomation:{ "namespace": "github", "resourceType": "pull_request", "identifier": "getsentry/junior#7", "events": ["pull_request.review.commented"] }Junior now saves this:
{ "namespace": "github", "events": ["pull_request.review.commented"], "match": { "repo": "getsentry/junior", "pullRequest": 7 } }The dashboard and the automation details show the filters.
What each plugin converts:
ENG-123)When Junior keeps an identifier, the automation still works. Its details show a short note that says why.
Sentry keeps identifiers because each Sentry identifier contains an org name, and Junior has no way to check that org. If Junior converted an identifier with an old or wrong org, an automation that never ran could start to run for the wrong things.
Changes to updating an automation
This is the part that changes behavior. It only affects
updateEventAutomation, the tool that the agent uses.Before this PR, a new
matchreplaced all saved filters. After conversion, the filters are the thing that keeps an automation pointed at one PR. So "also skip drafts" could quietly turn "PR #7" into "every PR in the repo".Now
matchchanges only the filters that it names:match: { isDraft: false }repo,pullRequest: 7repo,pullRequest: 7,isDraft: falsematch: { pullRequest: null }repo,pullRequest: 7repo(every PR in the repo)match: { pullRequest: [7, 8] }repo,pullRequest: 7repo,pullRequest: [7, 8]match: {}match: { repo: null }repo,pullRequest: 7repoThe identifier rules from #2407 stay the same: leave out
identifierto keep it, and set it tonullto drop it.The dashboard editor shows every filter and saves the whole trigger, so it works the same as before.
Junior now also rejects a trigger that can never run. An example is identifier
getsentry/junior#7with filterpullRequest: 5. The error names the filter. Before, Junior saved the trigger, and it never ran.What might break
match: {}used to remove all filters. Now it does nothing. To remove a filter, set it tonull.matchused to drop the filters that it left out. Now they stay.identifierMatch, that turns an identifier into filters. Plugins that do not add it keep identifiers. It is temporary, and a later change removes it with identifiers.Smaller changes
Checks (head
e9711e4c3)main. Some event automation delivery evals and one scheduler eval also fail on other open PRs. These failures are not caused by this PR.--
View Session [Sentry]