Skip to content

feat(seer): Add org-level default stopping point and wire coding agent defaults into project creation#111697

Merged
srest2021 merged 32 commits intomasterfrom
srest2021/CW-1120
Mar 31, 2026
Merged

feat(seer): Add org-level default stopping point and wire coding agent defaults into project creation#111697
srest2021 merged 32 commits intomasterfrom
srest2021/CW-1120

Conversation

@srest2021
Copy link
Copy Markdown
Member

@srest2021 srest2021 commented Mar 26, 2026

Fixes CW-1120

Register new org option sentry:default_automated_run_stopping_point and wire all org-level Seer defaults (stopping point, coding agent, auto_open_prs) into both project creation and the existing-org migration task.

Project creation and the org migration task to new seat-based pricing now:

  • Read the org's defaultAutomatedRunStoppingPoint and defaultCodingAgent and defaultCodingAgentIntegrationId
  • For external agents, configure automation_handoff with auto_create_pr from auto_open_prs
  • For Seer agent, auto_open_prs=true forces open_pr; auto_open_prs=false caps open_pr down to code_changes
  • Also adds ChoiceField validation for defaultCodingAgent (with alias mapping for cursor → cursor_background_agent, claude_code → claude_code_agent) and defaultAutomatedRunStoppingPoint.

…t defaults into project creation

Register new org option `sentry:default_stopping_point` and wire all
org-level Seer defaults (stopping point, coding agent, auto_open_prs)
into project creation and existing-org migration. When auto_open_prs
is true, stopping point is forced to open_pr. External agents
(Cursor/Claude) now get automation_handoff set on new projects.

Also adds input validation for defaultCodingAgent with alias mapping
(cursor -> cursor_background_agent, claude_code -> claude_code_agent)
and ChoiceField validation for defaultAutomatedRunStoppingPoint.

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Made-with: Cursor
@linear-code
Copy link
Copy Markdown

linear-code bot commented Mar 26, 2026

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Mar 26, 2026
Cover all org-default-to-project mapping cases: Seer agent with
default and custom stopping points, auto_open_prs forcing open_pr,
external agents (Cursor/Claude) with handoff config, missing
integration ID edge case, API error handling, and dual-write
feature flag gating.

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Made-with: Cursor
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 26, 2026

Backend Test Failures

Failures on 82d0e45 in this run:

tests/sentry/core/endpoints/test_organization_details.py::OrganizationUpdateTest::test_default_coding_agent_null_on_first_write_create_pathlog
tests/sentry/core/endpoints/test_organization_details.py:1513: in test_default_coding_agent_null_on_first_write_create_path
    assert self.organization.get_option("sentry:seer_default_coding_agent") is None
E   AssertionError: assert 'seer' is None
E    +  where 'seer' = <bound method Organization.get_option of <Organization at 0x7f378f8ff9d0: id=4557861493669904, owner_id=None, name='baz', slug='baz'>>('sentry:seer_default_coding_agent')
E    +    where <bound method Organization.get_option of <Organization at 0x7f378f8ff9d0: id=4557861493669904, owner_id=None, name='baz', slug='baz'>> = <Organization at 0x7f378f8ff9d0: id=4557861493669904, owner_id=None, name='baz', slug='baz'>.get_option
E    +      where <Organization at 0x7f378f8ff9d0: id=4557861493669904, owner_id=None, name='baz', slug='baz'> = <sentry.testutils.silo.OrganizationUpdateTest testMethod=test_default_coding_agent_null_on_first_write_create_path>.organization
tests/sentry/core/endpoints/test_organization_details.py::OrganizationUpdateTest::test_default_coding_agent_can_be_clearedlog
tests/sentry/core/endpoints/test_organization_details.py:1588: in test_default_coding_agent_can_be_cleared
    assert self.organization.get_option("sentry:seer_default_coding_agent") is None
E   AssertionError: assert 'seer' is None
E    +  where 'seer' = <bound method Organization.get_option of <Organization at 0x7f5189539450: id=4557861495963664, owner_id=None, name='baz', slug='baz'>>('sentry:seer_default_coding_agent')
E    +    where <bound method Organization.get_option of <Organization at 0x7f5189539450: id=4557861495963664, owner_id=None, name='baz', slug='baz'>> = <Organization at 0x7f5189539450: id=4557861495963664, owner_id=None, name='baz', slug='baz'>.get_option
E    +      where <Organization at 0x7f5189539450: id=4557861495963664, owner_id=None, name='baz', slug='baz'> = <sentry.testutils.silo.OrganizationUpdateTest testMethod=test_default_coding_agent_can_be_cleared>.organization

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 27, 2026

Backend Test Failures

Failures on 7fa7844 in this run:

tests/sentry/core/endpoints/test_organization_details.py::OrganizationUpdateTest::test_default_coding_agent_can_be_clearedlog
tests/sentry/core/endpoints/test_organization_details.py:1588: in test_default_coding_agent_can_be_cleared
    assert self.organization.get_option("sentry:seer_default_coding_agent") is None
E   AssertionError: assert 'seer' is None
E    +  where 'seer' = <bound method Organization.get_option of <Organization at 0x7f6be2ec3110: id=4557865831825424, owner_id=None, name='baz', slug='baz'>>('sentry:seer_default_coding_agent')
E    +    where <bound method Organization.get_option of <Organization at 0x7f6be2ec3110: id=4557865831825424, owner_id=None, name='baz', slug='baz'>> = <Organization at 0x7f6be2ec3110: id=4557865831825424, owner_id=None, name='baz', slug='baz'>.get_option
E    +      where <Organization at 0x7f6be2ec3110: id=4557865831825424, owner_id=None, name='baz', slug='baz'> = <sentry.testutils.silo.OrganizationUpdateTest testMethod=test_default_coding_agent_can_be_cleared>.organization
tests/sentry/core/endpoints/test_organization_details.py::OrganizationUpdateTest::test_default_coding_agent_null_on_first_write_create_pathlog
tests/sentry/core/endpoints/test_organization_details.py:1513: in test_default_coding_agent_null_on_first_write_create_path
    assert self.organization.get_option("sentry:seer_default_coding_agent") is None
E   AssertionError: assert 'seer' is None
E    +  where 'seer' = <bound method Organization.get_option of <Organization at 0x7f4879311bd0: id=4557865831170064, owner_id=None, name='baz', slug='baz'>>('sentry:seer_default_coding_agent')
E    +    where <bound method Organization.get_option of <Organization at 0x7f4879311bd0: id=4557865831170064, owner_id=None, name='baz', slug='baz'>> = <Organization at 0x7f4879311bd0: id=4557865831170064, owner_id=None, name='baz', slug='baz'>.get_option
E    +      where <Organization at 0x7f4879311bd0: id=4557865831170064, owner_id=None, name='baz', slug='baz'> = <sentry.testutils.silo.OrganizationUpdateTest testMethod=test_default_coding_agent_null_on_first_write_create_path>.organization

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 27, 2026

Backend Test Failures

Failures on 3692bc0 in this run:

tests/sentry/core/endpoints/test_organization_details.py::OrganizationUpdateTest::test_default_coding_agent_claudelog
tests/sentry/core/endpoints/test_organization_details.py:1529: in test_default_coding_agent_claude
    response = self.get_success_response(self.organization.slug, **data)
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_details.py::OrganizationUpdateTest::test_default_coding_agent_cursorlog
tests/sentry/core/endpoints/test_organization_details.py:1519: in test_default_coding_agent_cursor
    response = self.get_success_response(self.organization.slug, **data)
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/core/endpoints/test_organization_details.py::OrganizationUpdateTest::test_default_coding_agent_can_be_setlog
tests/sentry/core/endpoints/test_organization_details.py:1504: in test_default_coding_agent_can_be_set
    response = self.get_success_response(self.organization.slug, **data)
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code

@srest2021 srest2021 marked this pull request as ready for review March 27, 2026 21:12
@srest2021 srest2021 requested review from a team as code owners March 27, 2026 21:12
@github-actions
Copy link
Copy Markdown
Contributor

Backend Test Failures

Failures on d8d7241 in this run:

tests/sentry/integrations/bitbucket/test_issues.py::BitbucketIssueTest::test_get_create_issue_configlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/integrations/bitbucket/test_issues.py:198: in test_get_create_issue_config
    assert installation.get_create_issue_config(self.group, self.user) == [
E   assert [{'choices': ...iority', ...}] == [{'choices': ...iority', ...}]
E     
E     At index 2 diff: {'name': 'description', 'label': 'Description', 'default': 'Sentry Issue: [BAR-1](http://testserver/organizations/baz/issues/34/?referrer=bitbucket_integration)\n\n```\nStacktrace (appel le plus récent en premier) : \n\n  File "sentry/models/foo.py", line 29, in build_msg\n    string_max_length=self.string_max_length)\n\nmessage\n```', 'type': 'textarea', 'autosize': True, 'maxRows': 10} != {'name': 'description', 'label': 'Description', 'default': 'Sentry Issue: [BAR-1](http://testserver/organizations/baz/issues/34/?referrer=bitbucket_integration)\n\n```\nStacktrace (most recent call first):\n\n  File "sentry/models/foo.py", line 29, in build_msg\n    string_max_length=self.string_max_length)\n\nmessage\n```', 'type': 'textarea', 'autosize': True, 'maxRows': 10}
E     
E     Full diff:
E       [
E           {
E               'choices': [
E                   (
E                       'myaccount/repo1',
E                       'myaccount/repo1',
E                   ),
E                   (
E                       'myaccount/repo2',
E                       'myaccount/repo2',
E                   ),
E               ],
E               'default': 'myaccount/repo1',
E               'label': 'Bitbucket Repository',
E               'name': 'repo',
E               'required': True,
E               'type': 'select',
E               'updatesForm': True,
E               'url': '/extensions/bitbucket/search/baz/9/',
E           },
E           {
E               'default': 'message',
E               'label': 'Title',
E               'maxLength': 255,
E               'name': 'title',
E               'required': True,
E               'type': 'string',
E           },
E           {
E               'autosize': True,
E               'default': 'Sentry Issue: '
E               '[BAR-1](http://testserver/organizations/baz/issues/34/?referrer=bitbucket_integration)\n'
E               '\n'
E               '```\n'
E     -         'Stacktrace (most recent call first):\n'
E     +         'Stacktrace (appel le plus récent en premier) : \n'
E               '\n'
E               '  File "sentry/models/foo.py", line 29, in build_msg\n'
E               '    string_max_length=self.string_max_length)\n'
E               '\n'
E               'message\n'
E               '```',
... (58 more lines)

@github-actions
Copy link
Copy Markdown
Contributor

Backend Test Failures

Failures on 6368880 in this run:

tests/sentry/integrations/bitbucket/test_issues.py::BitbucketIssueTest::test_get_create_issue_configlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/integrations/bitbucket/test_issues.py:198: in test_get_create_issue_config
    assert installation.get_create_issue_config(self.group, self.user) == [
E   assert [{'choices': ...iority', ...}] == [{'choices': ...iority', ...}]
E     
E     At index 2 diff: {'name': 'description', 'label': 'Description', 'default': 'Sentry Issue: [BAR-1](http://testserver/organizations/baz/issues/56/?referrer=bitbucket_integration)\n\n```\nStacktrace (appel le plus récent en premier) : \n\n  File "sentry/models/foo.py", line 29, in build_msg\n    string_max_length=self.string_max_length)\n\nmessage\n```', 'type': 'textarea', 'autosize': True, 'maxRows': 10} != {'name': 'description', 'label': 'Description', 'default': 'Sentry Issue: [BAR-1](http://testserver/organizations/baz/issues/56/?referrer=bitbucket_integration)\n\n```\nStacktrace (most recent call first):\n\n  File "sentry/models/foo.py", line 29, in build_msg\n    string_max_length=self.string_max_length)\n\nmessage\n```', 'type': 'textarea', 'autosize': True, 'maxRows': 10}
E     
E     Full diff:
E       [
E           {
E               'choices': [
E                   (
E                       'myaccount/repo1',
E                       'myaccount/repo1',
E                   ),
E                   (
E                       'myaccount/repo2',
E                       'myaccount/repo2',
E                   ),
E               ],
E               'default': 'myaccount/repo1',
E               'label': 'Bitbucket Repository',
E               'name': 'repo',
E               'required': True,
E               'type': 'select',
E               'updatesForm': True,
E               'url': '/extensions/bitbucket/search/baz/9/',
E           },
E           {
E               'default': 'message',
E               'label': 'Title',
E               'maxLength': 255,
E               'name': 'title',
E               'required': True,
E               'type': 'string',
E           },
E           {
E               'autosize': True,
E               'default': 'Sentry Issue: '
E               '[BAR-1](http://testserver/organizations/baz/issues/56/?referrer=bitbucket_integration)\n'
E               '\n'
E               '```\n'
E     -         'Stacktrace (most recent call first):\n'
E     +         'Stacktrace (appel le plus récent en premier) : \n'
E               '\n'
E               '  File "sentry/models/foo.py", line 29, in build_msg\n'
E               '    string_max_length=self.string_max_length)\n'
E               '\n'
E               'message\n'
E               '```',
... (58 more lines)

Copy link
Copy Markdown
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 3 potential issues.

There are 5 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@srest2021 srest2021 merged commit 5f4782f into master Mar 31, 2026
108 of 109 checks passed
@srest2021 srest2021 deleted the srest2021/CW-1120 branch March 31, 2026 21:55
dashed pushed a commit that referenced this pull request Apr 1, 2026
…t defaults into project creation (#111697)

Fixes CW-1120

Register new org option `sentry:default_automated_run_stopping_point`
and wire all org-level Seer defaults (stopping point, coding agent,
auto_open_prs) into both project creation and the existing-org migration
task.

Project creation and the org migration task to new seat-based pricing
now:
- Read the org's `defaultAutomatedRunStoppingPoint` and
`defaultCodingAgent` and `defaultCodingAgentIntegrationId`
- For external agents, configure automation_handoff with
`auto_create_pr` from `auto_open_prs`
- For Seer agent, `auto_open_prs=true` forces `open_pr`;
`auto_open_prs=false` caps `open_pr` down to `code_changes`
- Also adds ChoiceField validation for `defaultCodingAgent` (with alias
mapping for cursor → cursor_background_agent, claude_code →
claude_code_agent) and `defaultAutomatedRunStoppingPoint`.

---------

Co-authored-by: Claude Sonnet 4 <noreply@anthropic.com>
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.

3 participants